use of com.biglybt.core.logging.LogAlert in project BiglyBT by BiglySoftware.
the class VirtualChannelSelectorImpl method openNewSelector.
protected Selector openNewSelector() {
Selector sel = null;
final int MAX_TRIES = 10;
try {
sel = getSelector();
AEDiagnostics.logWithStack("seltrace", "Selector created for '" + parent.getName() + "'," + selector_guard.getType());
} catch (Throwable t) {
Debug.out("ERROR: caught exception on Selector.open()", t);
try {
Thread.sleep(3000);
} catch (Throwable x) {
x.printStackTrace();
}
int fail_count = (t instanceof SelectorTimeoutException ? 1000 : 1);
while (fail_count < MAX_TRIES) {
try {
sel = getSelector();
AEDiagnostics.logWithStack("seltrace", "Selector created for '" + parent.getName() + "'," + selector_guard.getType());
break;
} catch (Throwable f) {
Debug.out(f);
if (f instanceof SelectorTimeoutException) {
fail_count = 1000;
} else {
fail_count++;
}
if (fail_count < MAX_TRIES) {
try {
Thread.sleep(3000);
} catch (Throwable x) {
x.printStackTrace();
}
} else {
break;
}
}
}
if (fail_count < MAX_TRIES) {
// success !
Debug.out("NOTICE: socket Selector successfully opened after " + fail_count + " failures.");
} else {
// failure
Logger.log(new LogAlert(LogAlert.REPEATABLE, LogAlert.AT_ERROR, "ERROR: socket Selector.open() failed " + (fail_count == 1000 ? "due to timeout" : (MAX_TRIES + " times in a row")) + ", aborting." + "\nThis App / Java is likely being firewalled!"));
}
}
return sel;
}
use of com.biglybt.core.logging.LogAlert in project BiglyBT by BiglySoftware.
the class NetworkAdminImpl method checkBindAddresses.
private String checkBindAddresses(boolean log_alerts) {
Pattern addressSplitter = Pattern.compile(";");
Pattern interfaceSplitter = Pattern.compile("[\\]\\[]");
String bind_ips = COConfigurationManager.getStringParameter("Bind IP", "").trim();
boolean enforceBind = COConfigurationManager.getBooleanParameter("Enforce Bind IP");
if (enforceBind && bind_ips.length() == 0) {
if (log_alerts) {
Logger.log(new LogAlert(true, LogAlert.AT_WARNING, MessageText.getString("network.admin.bind.enforce.fail")));
}
}
String[] tokens = addressSplitter.split(bind_ips);
String failed_entries = "";
for (int i = 0; i < tokens.length; i++) {
String currentAddress = tokens[i];
currentAddress = currentAddress.trim();
if (currentAddress.length() == 0) {
continue;
}
boolean ok = false;
InetAddress parsedAddress = null;
try {
if (currentAddress.indexOf('.') != -1 || currentAddress.indexOf(':') != -1) {
parsedAddress = InetAddress.getByName(currentAddress);
}
} catch (Throwable e) {
}
if (parsedAddress != null) {
try {
if (parsedAddress.isAnyLocalAddress() || NetUtils.getByInetAddress(parsedAddress) != null) {
ok = true;
}
} catch (Throwable e) {
}
} else {
// interface name
String[] ifaces = interfaceSplitter.split(currentAddress);
NetworkInterface netInterface = null;
try {
netInterface = NetUtils.getByName(ifaces[0]);
} catch (Throwable e) {
}
if (netInterface != null) {
Enumeration interfaceAddresses = netInterface.getInetAddresses();
if (ifaces.length != 2) {
ok = interfaceAddresses.hasMoreElements();
} else {
try {
int selectedAddress = Integer.parseInt(ifaces[1]);
for (int j = 0; interfaceAddresses.hasMoreElements(); j++, interfaceAddresses.nextElement()) {
if (j == selectedAddress) {
ok = true;
break;
}
}
} catch (Throwable e) {
}
}
}
}
if (!ok) {
failed_entries += (failed_entries.length() == 0 ? "" : ", ") + currentAddress;
}
}
if (failed_entries.length() > 0) {
if (log_alerts) {
Logger.log(new LogAlert(true, LogAlert.AT_WARNING, "Bind IPs not resolved: " + failed_entries + "\n\nSee Tools->Options->Connection->Advanced Network Settings"));
}
return (failed_entries);
}
return (null);
}
use of com.biglybt.core.logging.LogAlert in project BiglyBT by BiglySoftware.
the class DiskManagerUtil method setFileLink.
static boolean setFileLink(DownloadManager download_manager, DiskManagerFileInfo[] info, DiskManagerFileInfo file_info, File from_file, File to_link, FileUtil.ProgressListener pl) {
if (to_link != null) {
File existing_file = file_info.getFile(true);
if (to_link.equals(existing_file)) {
return (true);
}
for (int i = 0; i < info.length; i++) {
if (to_link.equals(info[i].getFile(true))) {
Logger.log(new LogAlert(download_manager, LogAlert.REPEATABLE, LogAlert.AT_ERROR, "Attempt to link to existing file '" + info[i].getFile(true) + "'"));
return (false);
}
}
if (to_link.exists()) {
if (!existing_file.exists()) {
// using a new file, make sure we recheck
download_manager.recheckFile(file_info);
} else {
if (to_link.getParent().equals(existing_file.getParent()) && to_link.getName().equalsIgnoreCase(existing_file.getName())) {
if (!FileUtil.renameFile(existing_file, to_link)) {
Logger.log(new LogAlert(download_manager, LogAlert.REPEATABLE, LogAlert.AT_ERROR, "Failed to rename '" + existing_file.toString() + "'"));
return (false);
}
} else {
Object skip_delete = download_manager.getUserData("set_link_dont_delete_existing");
if ((skip_delete instanceof Boolean) && (Boolean) skip_delete) {
download_manager.recheckFile(file_info);
} else {
if (FileUtil.deleteWithRecycle(existing_file, download_manager.getDownloadState().getFlag(DownloadManagerState.FLAG_LOW_NOISE))) {
// new file, recheck
download_manager.recheckFile(file_info);
} else {
Logger.log(new LogAlert(download_manager, LogAlert.REPEATABLE, LogAlert.AT_ERROR, "Failed to delete '" + existing_file.toString() + "'"));
return (false);
}
}
}
}
} else {
if (existing_file.exists()) {
if (!FileUtil.renameFile(existing_file, to_link, pl)) {
Logger.log(new LogAlert(download_manager, LogAlert.REPEATABLE, LogAlert.AT_ERROR, "Failed to rename '" + existing_file.toString() + "'"));
return (false);
}
}
}
}
DownloadManagerState state = download_manager.getDownloadState();
state.setFileLink(file_info.getIndex(), from_file, to_link);
state.save();
return (true);
}
use of com.biglybt.core.logging.LogAlert in project BiglyBT by BiglySoftware.
the class DiskManagerUtil method getFileInfoSkeleton.
public static DiskManagerFileInfoSet getFileInfoSkeleton(final DownloadManager download_manager, final DiskManagerListener listener) {
final TOTorrent torrent = download_manager.getTorrent();
if (torrent == null) {
return (new DiskManagerFileInfoSetImpl(new DiskManagerFileInfoImpl[0], null));
}
String tempRootDir = download_manager.getAbsoluteSaveLocation().getParent();
if (// in case we alraedy are at the root
tempRootDir == null)
tempRootDir = download_manager.getAbsoluteSaveLocation().getPath();
if (!torrent.isSimpleTorrent()) {
tempRootDir += File.separator + download_manager.getAbsoluteSaveLocation().getName();
}
tempRootDir += File.separator;
// prevent attempted state saves and associated nastyness during population of
// the file skeleton entries
final boolean[] loading = { true };
try {
final String root_dir = StringInterner.intern(tempRootDir);
try {
final LocaleUtilDecoder locale_decoder = LocaleTorrentUtil.getTorrentEncoding(torrent);
TOTorrentFile[] torrent_files = torrent.getFiles();
final FileSkeleton[] res = new FileSkeleton[torrent_files.length];
final String incomplete_suffix = download_manager.getDownloadState().getAttribute(DownloadManagerState.AT_INCOMP_FILE_SUFFIX);
final DiskManagerFileInfoSet fileSetSkeleton = new DiskManagerFileInfoSet() {
@Override
public DiskManagerFileInfo[] getFiles() {
return res;
}
@Override
public int nbFiles() {
return res.length;
}
@Override
public void setPriority(int[] toChange) {
if (toChange.length != res.length)
throw new IllegalArgumentException("array length mismatches the number of files");
for (int i = 0; i < res.length; i++) res[i].priority = toChange[i];
if (!loading[0]) {
DiskManagerImpl.storeFilePriorities(download_manager, res);
}
for (int i = 0; i < res.length; i++) if (toChange[i] != 0)
listener.filePriorityChanged(res[i]);
}
@Override
public void setSkipped(boolean[] toChange, boolean setSkipped) {
if (toChange.length != res.length)
throw new IllegalArgumentException("array length mismatches the number of files");
if (!setSkipped) {
String[] types = DiskManagerImpl.getStorageTypes(download_manager);
boolean[] toLinear = new boolean[toChange.length];
boolean[] toReorder = new boolean[toChange.length];
int num_linear = 0;
int num_reorder = 0;
for (int i = 0; i < toChange.length; i++) {
if (toChange[i]) {
int old_type = DiskManagerUtil.convertDMStorageTypeFromString(types[i]);
if (old_type == DiskManagerFileInfo.ST_COMPACT) {
toLinear[i] = true;
num_linear++;
} else if (old_type == DiskManagerFileInfo.ST_REORDER_COMPACT) {
toReorder[i] = true;
num_reorder++;
}
}
}
if (num_linear > 0) {
if (!Arrays.equals(toLinear, setStorageTypes(toLinear, DiskManagerFileInfo.ST_LINEAR))) {
return;
}
}
if (num_reorder > 0) {
if (!Arrays.equals(toReorder, setStorageTypes(toReorder, DiskManagerFileInfo.ST_REORDER))) {
return;
}
}
}
File[] to_link = new File[res.length];
for (int i = 0; i < res.length; i++) {
if (toChange[i]) {
to_link[i] = res[i].setSkippedInternal(setSkipped);
}
}
if (!loading[0]) {
DiskManagerImpl.storeFilePriorities(download_manager, res);
}
List<Integer> from_indexes = new ArrayList<>();
List<File> from_links = new ArrayList<>();
List<File> to_links = new ArrayList<>();
for (int i = 0; i < res.length; i++) {
if (to_link[i] != null) {
from_indexes.add(i);
from_links.add(res[i].getFile(false));
to_links.add(to_link[i]);
}
}
if (from_links.size() > 0) {
download_manager.getDownloadState().setFileLinks(from_indexes, from_links, to_links);
}
if (!setSkipped) {
doFileExistenceChecks(this, toChange, download_manager, true);
}
for (int i = 0; i < res.length; i++) {
if (toChange[i]) {
listener.filePriorityChanged(res[i]);
}
}
}
@Override
public boolean[] setStorageTypes(boolean[] toChange, int newStorageType) {
if (toChange.length != res.length)
throw new IllegalArgumentException("array length mismatches the number of files");
String[] types = DiskManagerImpl.getStorageTypes(download_manager);
boolean[] modified = new boolean[res.length];
boolean[] toSkip = new boolean[res.length];
int toSkipCount = 0;
DownloadManagerState dmState = download_manager.getDownloadState();
try {
dmState.suppressStateSave(true);
for (int i = 0; i < res.length; i++) {
if (!toChange[i])
continue;
final int idx = i;
int old_type = DiskManagerUtil.convertDMStorageTypeFromString(types[i]);
if (newStorageType == old_type) {
modified[i] = true;
continue;
}
try {
File target_file = res[i].getFile(true);
if (target_file.exists()) {
CacheFile cache_file = CacheFileManagerFactory.getSingleton().createFile(new CacheFileOwner() {
@Override
public String getCacheFileOwnerName() {
return (download_manager.getInternalName());
}
@Override
public TOTorrentFile getCacheFileTorrentFile() {
return (res[idx].getTorrentFile());
}
@Override
public File getCacheFileControlFileDir() {
return (download_manager.getDownloadState().getStateFile());
}
@Override
public int getCacheMode() {
return (CacheFileOwner.CACHE_MODE_NORMAL);
}
}, target_file, DiskManagerUtil.convertDMStorageTypeToCache(newStorageType));
// need this to trigger recovery for re-order files :(
cache_file.getLength();
cache_file.close();
}
toSkip[i] = (newStorageType == FileSkeleton.ST_COMPACT || newStorageType == FileSkeleton.ST_REORDER_COMPACT) && !res[i].isSkipped();
if (toSkip[i]) {
toSkipCount++;
}
modified[i] = true;
} catch (Throwable e) {
Debug.printStackTrace(e);
Logger.log(new LogAlert(download_manager, LogAlert.REPEATABLE, LogAlert.AT_ERROR, "Failed to change storage type for '" + res[i].getFile(true) + "': " + Debug.getNestedExceptionMessage(e)));
// download's not running - tag for recheck
RDResumeHandler.recheckFile(download_manager, res[i]);
}
types[i] = DiskManagerUtil.convertDMStorageTypeToString(newStorageType);
}
/*
* set storage type and skipped before we do piece clearing and file
* clearing checks as those checks work better when skipped/stype is set
* properly
*/
dmState.setListAttribute(DownloadManagerState.AT_FILE_STORE_TYPES, types);
if (toSkipCount > 0) {
setSkipped(toSkip, true);
}
for (int i = 0; i < res.length; i++) {
if (!toChange[i])
continue;
// download's not running, update resume data as necessary
int cleared = RDResumeHandler.storageTypeChanged(download_manager, res[i]);
if (cleared > 0) {
res[i].downloaded = res[i].downloaded - cleared * res[i].getTorrentFile().getTorrent().getPieceLength();
if (res[i].downloaded < 0)
res[i].downloaded = 0;
}
}
DiskManagerImpl.storeFileDownloaded(download_manager, res, true);
doFileExistenceChecks(this, toChange, download_manager, newStorageType == FileSkeleton.ST_LINEAR || newStorageType == FileSkeleton.ST_REORDER);
} finally {
dmState.suppressStateSave(false);
dmState.save();
}
return modified;
}
};
for (int i = 0; i < res.length; i++) {
final TOTorrentFile torrent_file = torrent_files[i];
final int file_index = i;
FileSkeleton info = new FileSkeleton() {
private volatile CacheFile read_cache_file;
// do not access this field directly, use lazyGetFile() instead
private WeakReference dataFile = new WeakReference(null);
@Override
public void setPriority(int b) {
priority = b;
DiskManagerImpl.storeFilePriorities(download_manager, res);
listener.filePriorityChanged(this);
}
@Override
public void setSkipped(boolean _skipped) {
if (!_skipped && getStorageType() == ST_COMPACT) {
if (!setStorageType(ST_LINEAR)) {
return;
}
}
if (!_skipped && getStorageType() == ST_REORDER_COMPACT) {
if (!setStorageType(ST_REORDER)) {
return;
}
}
File to_link = setSkippedInternal(_skipped);
DiskManagerImpl.storeFilePriorities(download_manager, res);
if (to_link != null) {
download_manager.getDownloadState().setFileLink(file_index, getFile(false), to_link);
}
if (!_skipped) {
boolean[] toCheck = new boolean[fileSetSkeleton.nbFiles()];
toCheck[file_index] = true;
doFileExistenceChecks(fileSetSkeleton, toCheck, download_manager, true);
}
listener.filePriorityChanged(this);
}
@Override
public int getAccessMode() {
return (READ);
}
@Override
public long getDownloaded() {
return (downloaded);
}
@Override
public long getLastModified() {
return (getFile(true).lastModified());
}
@Override
public void setDownloaded(long l) {
downloaded = l;
}
@Override
public String getExtension() {
String ext = lazyGetFile().getName();
if (incomplete_suffix != null && ext.endsWith(incomplete_suffix)) {
ext = ext.substring(0, ext.length() - incomplete_suffix.length());
}
int separator = ext.lastIndexOf(".");
if (separator == -1)
separator = 0;
return ext.substring(separator);
}
@Override
public int getFirstPieceNumber() {
return (torrent_file.getFirstPieceNumber());
}
@Override
public int getLastPieceNumber() {
return (torrent_file.getLastPieceNumber());
}
@Override
public long getLength() {
return (torrent_file.getLength());
}
@Override
public int getIndex() {
return (file_index);
}
@Override
public int getNbPieces() {
return (torrent_file.getNumberOfPieces());
}
@Override
public int getPriority() {
return (priority);
}
@Override
protected File setSkippedInternal(boolean _skipped) {
// returns the file to link to if linkage is required
skipped_internal = _skipped;
if (!download_manager.isDestroyed()) {
DownloadManagerState dm_state = download_manager.getDownloadState();
String dnd_sf = dm_state.getAttribute(DownloadManagerState.AT_DND_SUBFOLDER);
if (dnd_sf != null) {
File link = getLink();
File file = getFile(false);
if (_skipped) {
if (link == null || link.equals(file)) {
File parent = file.getParentFile();
if (parent != null) {
String prefix = dm_state.getAttribute(DownloadManagerState.AT_DND_PREFIX);
String file_name = file.getName();
if (prefix != null && !file_name.startsWith(prefix)) {
file_name = prefix + file_name;
}
File new_parent = new File(parent, dnd_sf);
File new_file = new File(new_parent, file_name);
if (!new_file.exists()) {
if (!new_parent.exists()) {
new_parent.mkdirs();
}
if (new_parent.canWrite()) {
boolean ok;
if (file.exists()) {
ok = FileUtil.renameFile(file, new_file);
} else {
ok = true;
}
if (ok) {
return (new_file);
}
}
}
}
}
} else {
if (link != null && !file.exists()) {
File parent = file.getParentFile();
if (parent != null && parent.canWrite()) {
File new_parent = parent.getName().equals(dnd_sf) ? parent : new File(parent, dnd_sf);
// use link name to handle incomplete file suffix if set
File new_file = new File(new_parent, link.getName());
if (new_file.equals(link)) {
boolean ok;
String incomp_ext = dm_state.getAttribute(DownloadManagerState.AT_INCOMP_FILE_SUFFIX);
String file_name = file.getName();
String prefix = dm_state.getAttribute(DownloadManagerState.AT_DND_PREFIX);
boolean prefix_removed = false;
if (prefix != null && file_name.startsWith(prefix)) {
file_name = file_name.substring(prefix.length());
prefix_removed = true;
}
if (incomp_ext != null && incomp_ext.length() > 0 && getDownloaded() != getLength()) {
if (prefix == null) {
prefix = "";
}
file = new File(file.getParentFile(), prefix + file_name + incomp_ext);
} else if (prefix_removed) {
file = new File(file.getParentFile(), file_name);
}
if (new_file.exists()) {
ok = FileUtil.renameFile(new_file, file);
} else {
ok = true;
}
if (ok) {
File[] files = new_parent.listFiles();
if (files != null && files.length == 0) {
new_parent.delete();
}
return (file);
}
}
}
}
}
}
}
return (null);
}
@Override
public boolean isSkipped() {
return (skipped_internal);
}
@Override
public DiskManager getDiskManager() {
return (null);
}
@Override
public DownloadManager getDownloadManager() {
return (download_manager);
}
@Override
public File getFile(boolean follow_link) {
if (follow_link) {
File link = getLink();
if (link != null) {
return (link);
}
}
return lazyGetFile();
}
private File lazyGetFile() {
File toReturn = (File) dataFile.get();
if (toReturn != null)
return toReturn;
TOTorrent tor = download_manager.getTorrent();
String path_str = root_dir;
File simpleFile = null;
if (tor == null || tor.isSimpleTorrent()) {
// rumour has it tor can sometimes be null
simpleFile = download_manager.getAbsoluteSaveLocation();
} else {
byte[][] path_comps = torrent_file.getPathComponents();
for (int j = 0; j < path_comps.length; j++) {
String comp;
try {
comp = locale_decoder.decodeString(path_comps[j]);
} catch (UnsupportedEncodingException e) {
Debug.printStackTrace(e);
comp = "undecodableFileName" + file_index;
}
comp = FileUtil.convertOSSpecificChars(comp, j != path_comps.length - 1);
path_str += (j == 0 ? "" : File.separator) + comp;
}
}
dataFile = new WeakReference(toReturn = simpleFile != null ? simpleFile : new File(path_str));
// System.out.println("new file:"+toReturn);
return toReturn;
}
@Override
public TOTorrentFile getTorrentFile() {
return (torrent_file);
}
@Override
public boolean setLink(File link_destination) {
/**
* If we a simple torrent, then we'll redirect the call to the download and move the
* data files that way - that'll keep everything in sync.
*/
if (download_manager.getTorrent().isSimpleTorrent()) {
try {
download_manager.moveDataFiles(link_destination.getParentFile(), link_destination.getName());
return true;
} catch (DownloadManagerException e) {
// What should we do with the error?
return false;
}
}
return setLinkAtomic(link_destination);
}
@Override
public boolean setLinkAtomic(File link_destination) {
return (setFileLink(download_manager, res, this, lazyGetFile(), link_destination, null));
}
@Override
public boolean setLinkAtomic(File link_destination, FileUtil.ProgressListener pl) {
return (setFileLink(download_manager, res, this, lazyGetFile(), link_destination, pl));
}
@Override
public File getLink() {
return (download_manager.getDownloadState().getFileLink(file_index, lazyGetFile()));
}
@Override
public boolean setStorageType(int type) {
boolean[] change = new boolean[res.length];
change[file_index] = true;
return fileSetSkeleton.setStorageTypes(change, type)[file_index];
}
@Override
public int getStorageType() {
return (DiskManagerUtil.convertDMStorageTypeFromString(DiskManagerImpl.getStorageType(download_manager, file_index)));
}
@Override
public void flushCache() {
}
@Override
public DirectByteBuffer read(long offset, int length) throws IOException {
CacheFile temp;
try {
cache_read_mon.enter();
if (read_cache_file == null) {
try {
int type = convertDMStorageTypeFromString(DiskManagerImpl.getStorageType(download_manager, file_index));
read_cache_file = CacheFileManagerFactory.getSingleton().createFile(new CacheFileOwner() {
@Override
public String getCacheFileOwnerName() {
return (download_manager.getInternalName());
}
@Override
public TOTorrentFile getCacheFileTorrentFile() {
return (torrent_file);
}
@Override
public File getCacheFileControlFileDir() {
return (download_manager.getDownloadState().getStateFile());
}
@Override
public int getCacheMode() {
return (CacheFileOwner.CACHE_MODE_NORMAL);
}
}, getFile(true), convertDMStorageTypeToCache(type));
} catch (Throwable e) {
Debug.printStackTrace(e);
throw (new IOException(e.getMessage()));
}
}
temp = read_cache_file;
} finally {
cache_read_mon.exit();
}
DirectByteBuffer buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_DM_READ, length);
try {
temp.read(buffer, offset, CacheFile.CP_READ_CACHE);
} catch (Throwable e) {
buffer.returnToPool();
Debug.printStackTrace(e);
throw (new IOException(e.getMessage()));
}
return (buffer);
}
@Override
public int getReadBytesPerSecond() {
CacheFile temp = read_cache_file;
if (temp == null) {
return (0);
}
return (0);
}
@Override
public int getWriteBytesPerSecond() {
return (0);
}
@Override
public long getETA() {
return (-1);
}
@Override
public void close() {
CacheFile temp;
try {
cache_read_mon.enter();
temp = read_cache_file;
read_cache_file = null;
} finally {
cache_read_mon.exit();
}
if (temp != null) {
try {
temp.close();
} catch (Throwable e) {
Debug.printStackTrace(e);
}
}
}
@Override
public void addListener(DiskManagerFileInfoListener listener) {
if (getDownloaded() == getLength()) {
try {
listener.dataWritten(0, getLength());
listener.dataChecked(0, getLength());
} catch (Throwable e) {
Debug.printStackTrace(e);
}
}
}
@Override
public void removeListener(DiskManagerFileInfoListener listener) {
}
};
res[i] = info;
}
loadFilePriorities(download_manager, fileSetSkeleton);
loadFileDownloaded(download_manager, res);
return (fileSetSkeleton);
} finally {
loading[0] = false;
}
} catch (Throwable e) {
Debug.printStackTrace(e);
return (new DiskManagerFileInfoSetImpl(new DiskManagerFileInfoImpl[0], null));
}
}
use of com.biglybt.core.logging.LogAlert in project BiglyBT by BiglySoftware.
the class TOTorrentDeserialiseImpl method construct.
protected void construct(Map meta_data) throws TOTorrentException {
try {
String announce_url = null;
boolean got_announce = false;
boolean got_announce_list = false;
boolean bad_announce = false;
// decode the stuff
Iterator root_it = meta_data.keySet().iterator();
while (root_it.hasNext()) {
String key = (String) root_it.next();
if (key.equalsIgnoreCase(TK_ANNOUNCE)) {
got_announce = true;
announce_url = readStringFromMetaData(meta_data, TK_ANNOUNCE);
if (announce_url == null || announce_url.trim().length() == 0) {
bad_announce = true;
} else {
announce_url = announce_url.replaceAll(" ", "");
try {
setAnnounceURL(new URL(announce_url));
} catch (MalformedURLException e) {
if (!announce_url.contains("://")) {
announce_url = "http:/" + (announce_url.startsWith("/") ? "" : "/") + announce_url;
} else if (announce_url.startsWith("utp:")) {
// common typo for udp
announce_url = "udp" + announce_url.substring(3);
}
try {
setAnnounceURL(new URL(announce_url));
} catch (MalformedURLException f) {
Debug.out("Invalid announce url: " + announce_url);
bad_announce = true;
}
}
}
} else if (key.equalsIgnoreCase(TK_ANNOUNCE_LIST)) {
got_announce_list = true;
List announce_list = null;
Object ann_list = meta_data.get(TK_ANNOUNCE_LIST);
if (ann_list instanceof List) {
// some malformed torrents have this key as a zero-sized string instead of a zero-sized list
announce_list = (List) ann_list;
}
if (announce_list != null && announce_list.size() > 0) {
announce_url = readStringFromMetaData(meta_data, TK_ANNOUNCE);
if (announce_url != null) {
announce_url = announce_url.replaceAll(" ", "");
}
boolean announce_url_found = false;
for (int i = 0; i < announce_list.size(); i++) {
Object temp = announce_list.get(i);
if (temp instanceof byte[]) {
List l = new ArrayList();
l.add(temp);
temp = l;
}
if (temp instanceof List) {
Vector urls = new Vector();
List set = (List) temp;
while (set.size() > 0) {
// seen a case where this is a list with the announce url first and then some other junk
Object temp2 = set.remove(0);
try {
if (temp2 instanceof List) {
List junk = (List) temp2;
if (junk.size() > 0) {
set.add(junk.get(0));
}
continue;
}
String url_str = readStringFromMetaData((byte[]) temp2);
url_str = url_str.replaceAll(" ", "");
try {
urls.add(new URL(StringInterner.intern(url_str)));
if (url_str.equalsIgnoreCase(announce_url)) {
announce_url_found = true;
}
} catch (MalformedURLException e) {
if (!url_str.contains("://")) {
url_str = "http:/" + (url_str.startsWith("/") ? "" : "/") + url_str;
} else if (url_str.startsWith("utp:")) {
// common typo
url_str = "udp" + url_str.substring(3);
}
try {
urls.add(new URL(StringInterner.intern(url_str)));
if (url_str.equalsIgnoreCase(announce_url)) {
announce_url_found = true;
}
} catch (MalformedURLException f) {
Debug.out("Invalid url: " + url_str, f);
}
}
} catch (Throwable e) {
Debug.out("Torrent has invalid url-list entry (" + temp2 + ") - ignoring: meta=" + meta_data, e);
}
}
if (urls.size() > 0) {
URL[] url_array = new URL[urls.size()];
urls.copyInto(url_array);
addTorrentAnnounceURLSet(url_array);
}
} else {
Debug.out("Torrent has invalid url-list entry (" + temp + ") - ignoring: meta=" + meta_data);
}
}
if (!announce_url_found && announce_url != null && announce_url.length() > 0) {
try {
Vector urls = new Vector();
urls.add(new URL(StringInterner.intern(announce_url)));
URL[] url_array = new URL[urls.size()];
urls.copyInto(url_array);
addTorrentAnnounceURLSet(url_array);
} catch (Exception e) {
Debug.out("Invalid URL '" + announce_url + "' - meta=" + meta_data, e);
}
}
}
} else if (key.equalsIgnoreCase(TK_COMMENT)) {
setComment((byte[]) meta_data.get(TK_COMMENT));
} else if (key.equalsIgnoreCase(TK_CREATED_BY)) {
setCreatedBy((byte[]) meta_data.get(TK_CREATED_BY));
} else if (key.equalsIgnoreCase(TK_CREATION_DATE)) {
try {
Long creation_date = (Long) meta_data.get(TK_CREATION_DATE);
if (creation_date != null) {
setCreationDate(creation_date.longValue());
}
} catch (Exception e) {
System.out.println("creation_date extraction fails, ignoring");
}
} else if (key.equalsIgnoreCase(TK_INFO)) {
// processed later
} else {
Object prop = meta_data.get(key);
if (prop instanceof byte[]) {
setAdditionalByteArrayProperty(key, (byte[]) prop);
} else if (prop instanceof Long) {
setAdditionalLongProperty(key, (Long) prop);
} else if (prop instanceof List) {
setAdditionalListProperty(key, (List) prop);
} else {
setAdditionalMapProperty(key, (Map) prop);
}
}
}
if (bad_announce) {
if (got_announce_list) {
TOTorrentAnnounceURLSet[] sets = getAnnounceURLGroup().getAnnounceURLSets();
if (sets.length > 0) {
setAnnounceURL(sets[0].getAnnounceURLs()[0]);
} else {
throw (new TOTorrentException("ANNOUNCE_URL malformed ('" + announce_url + "' and no usable announce list)", TOTorrentException.RT_DECODE_FAILS));
}
} else {
throw (new TOTorrentException("ANNOUNCE_URL malformed ('" + announce_url + "'", TOTorrentException.RT_DECODE_FAILS));
}
}
if (!(got_announce_list || got_announce)) {
setAnnounceURL(TorrentUtils.getDecentralisedEmptyURL());
}
if (getAnnounceURL() == null) {
boolean done = false;
if (got_announce_list) {
TOTorrentAnnounceURLSet[] sets = getAnnounceURLGroup().getAnnounceURLSets();
if (sets.length > 0) {
setAnnounceURL(sets[0].getAnnounceURLs()[0]);
done = true;
}
}
if (!done) {
setAnnounceURL(TorrentUtils.getDecentralisedEmptyURL());
}
}
Map info = (Map) meta_data.get(TK_INFO);
if (info == null) {
throw (new TOTorrentException("Decode fails, 'info' element not found'", TOTorrentException.RT_DECODE_FAILS));
}
boolean hasUTF8Keys = info.containsKey(TK_NAME_UTF8);
setName((byte[]) info.get(TK_NAME));
long piece_length = ((Long) info.get(TK_PIECE_LENGTH)).longValue();
if (piece_length <= 0) {
throw (new TOTorrentException("Decode fails, piece-length is invalid", TOTorrentException.RT_DECODE_FAILS));
}
setPieceLength(piece_length);
setHashFromInfo(info);
Long simple_file_length = (Long) info.get(TK_LENGTH);
long total_length = 0;
String encoding = getAdditionalStringProperty("encoding");
hasUTF8Keys &= encoding == null || encoding.equals(ENCODING_ACTUALLY_UTF8_KEYS);
if (simple_file_length != null) {
setSimpleTorrent(true);
total_length = simple_file_length.longValue();
if (hasUTF8Keys) {
setNameUTF8((byte[]) info.get(TK_NAME_UTF8));
setAdditionalStringProperty("encoding", ENCODING_ACTUALLY_UTF8_KEYS);
}
setFiles(new TOTorrentFileImpl[] { new TOTorrentFileImpl(this, 0, 0, total_length, new byte[][] { getName() }) });
} else {
setSimpleTorrent(false);
List meta_files = (List) info.get(TK_FILES);
TOTorrentFileImpl[] files = new TOTorrentFileImpl[meta_files.size()];
if (hasUTF8Keys) {
for (int i = 0; i < files.length; i++) {
Map file_map = (Map) meta_files.get(i);
hasUTF8Keys &= file_map.containsKey(TK_PATH_UTF8);
if (!hasUTF8Keys) {
break;
}
}
if (hasUTF8Keys) {
setNameUTF8((byte[]) info.get(TK_NAME_UTF8));
setAdditionalStringProperty("encoding", ENCODING_ACTUALLY_UTF8_KEYS);
}
}
for (int i = 0; i < files.length; i++) {
Map file_map = (Map) meta_files.get(i);
long len = ((Long) file_map.get(TK_LENGTH)).longValue();
List paths = (List) file_map.get(TK_PATH);
List paths8 = (List) file_map.get(TK_PATH_UTF8);
byte[][] path_comps = null;
if (paths != null) {
path_comps = new byte[paths.size()][];
for (int j = 0; j < paths.size(); j++) {
path_comps[j] = (byte[]) paths.get(j);
}
}
TOTorrentFileImpl file;
if (hasUTF8Keys) {
byte[][] path_comps8 = new byte[paths8.size()][];
for (int j = 0; j < paths8.size(); j++) {
path_comps8[j] = (byte[]) paths8.get(j);
}
file = files[i] = new TOTorrentFileImpl(this, i, total_length, len, path_comps, path_comps8);
} else {
file = files[i] = new TOTorrentFileImpl(this, i, total_length, len, path_comps);
}
total_length += len;
// preserve any non-standard attributes
Iterator file_it = file_map.keySet().iterator();
while (file_it.hasNext()) {
String key = (String) file_it.next();
if (key.equals(TK_LENGTH) || key.equals(TK_PATH)) {
// standard
// we don't skip TK_PATH_UTF8 because some code might assume getAdditionalProperty can get it
} else {
file.setAdditionalProperty(key, file_map.get(key));
}
}
}
setFiles(files);
}
byte[] flat_pieces = (byte[]) info.get(TK_PIECES);
// work out how many pieces we require for the torrent
int pieces_required = (int) ((total_length + (piece_length - 1)) / piece_length);
int pieces_supplied = flat_pieces.length / 20;
if (pieces_supplied < pieces_required) {
throw (new TOTorrentException("Decode fails, insufficient pieces supplied", TOTorrentException.RT_DECODE_FAILS));
}
if (pieces_supplied > pieces_required) {
Debug.out("Torrent '" + new String(getName()) + "' has too many pieces (required=" + pieces_required + ",supplied=" + pieces_supplied + ") - ignoring excess");
}
byte[][] pieces = new byte[pieces_supplied][20];
for (int i = 0; i < pieces.length; i++) {
System.arraycopy(flat_pieces, i * 20, pieces[i], 0, 20);
}
setPieces(pieces);
// extract and additional info elements
Iterator info_it = info.keySet().iterator();
while (info_it.hasNext()) {
String key = (String) info_it.next();
if (key.equals(TK_NAME) || key.equals(TK_LENGTH) || key.equals(TK_FILES) || key.equals(TK_PIECE_LENGTH) || key.equals(TK_PIECES)) {
// standard attributes
} else {
addAdditionalInfoProperty(key, info.get(key));
}
}
try {
byte[] ho = (byte[]) info.get(TK_HASH_OVERRIDE);
if (ho != null) {
setHashOverride(ho);
} else {
if (info instanceof LightHashMapEx) {
LightHashMapEx info_ex = (LightHashMapEx) info;
if (info_ex.getFlag(LightHashMapEx.FL_MAP_ORDER_INCORRECT)) {
String name = getUTF8Name();
if (name == null) {
name = new String(getName());
}
String message = MessageText.getString("torrent.decode.info.order.bad", new String[] { name });
LogAlert alert = new LogAlert(this, LogAlert.UNREPEATABLE, LogAlert.AT_WARNING, message);
alert.forceNotify = true;
Logger.log(alert);
}
}
}
} catch (Throwable e) {
Debug.printStackTrace(e);
}
} catch (Throwable e) {
if (e instanceof TOTorrentException) {
throw ((TOTorrentException) e);
}
throw (new TOTorrentException("Torrent decode fails '" + Debug.getNestedExceptionMessageAndStack(e) + "'", TOTorrentException.RT_DECODE_FAILS, e));
}
}
Aggregations