package edu.washington.cs.oneswarm.f2f;
import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.bouncycastle.util.encoders.Base64;
import org.gudy.azureus2.core3.util.ByteFormatter;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.HashWrapper;
import org.gudy.azureus2.plugins.Plugin;
import org.gudy.azureus2.plugins.PluginException;
import org.gudy.azureus2.plugins.PluginInterface;
import org.gudy.azureus2.plugins.download.Download;
import org.gudy.azureus2.plugins.download.DownloadException;
import org.gudy.azureus2.plugins.torrent.Torrent;
import com.aelitis.net.magneturi.MagnetURIHandler;
import com.aelitis.net.magneturi.MagnetURIHandlerException;
import com.aelitis.net.magneturi.MagnetURIHandlerListener;
import com.aelitis.net.magneturi.MagnetURIHandlerProgressListener;
import edu.washington.cs.oneswarm.f2f.OSF2FNatChecker.NatCheckResult;
import edu.washington.cs.oneswarm.f2f.OSF2FNatChecker.NatCheckResult.Status;
import edu.washington.cs.oneswarm.f2f.OSF2FSpeedChecker.OutgoingSpeedCheck;
import edu.washington.cs.oneswarm.f2f.friends.FriendBean;
import edu.washington.cs.oneswarm.f2f.friends.FriendImportManager;
import edu.washington.cs.oneswarm.f2f.friends.LanFriendFinder;
import edu.washington.cs.oneswarm.f2f.messaging.OSF2FHashSearch;
import edu.washington.cs.oneswarm.f2f.messaging.OSF2FSearch;
import edu.washington.cs.oneswarm.f2f.messaging.OSF2FTextSearch;
import edu.washington.cs.oneswarm.f2f.network.EndpointInterface;
import edu.washington.cs.oneswarm.f2f.network.FriendConnection;
import edu.washington.cs.oneswarm.f2f.network.FriendConnection.OverlayForward;
import edu.washington.cs.oneswarm.f2f.network.OverlayManager;
import edu.washington.cs.oneswarm.f2f.permissions.GroupBean;
import edu.washington.cs.oneswarm.f2f.permissions.PermissionsDAO;
import edu.washington.cs.oneswarm.plugins.PluginCallback;
import edu.washington.cs.publickey.PublicKeyFriend;
public class OSF2FPlugin implements Plugin {
private final static boolean ADD_INFO_TO_AZ_SWT_UI = true;
private static Logger logger = Logger.getLogger(OSF2FPlugin.class.getName());
// public static boolean logToStdOut = false;
private OSF2FMain main;
private final long mStartupTime = System.currentTimeMillis();
class OneSwarmURIHandlerListener implements MagnetURIHandlerListener {
private final PluginInterface pluginInterface;
public OneSwarmURIHandlerListener(PluginInterface pluginInterface) {
this.pluginInterface = pluginInterface;
}
@Override
public byte[] badge() {
return null; // we don't really need this
}
@Override
public boolean download(URL magnet_url) throws MagnetURIHandlerException {
try {
pluginInterface.getDownloadManager().addDownload(magnet_url, false);
return (true);
} catch (DownloadException e) {
throw (new MagnetURIHandlerException("Operation failed", e));
}
}
@Override
public byte[] download(final MagnetURIHandlerProgressListener progress, final byte[] hash,
InetSocketAddress[] sources, long timeout) throws MagnetURIHandlerException {
logger.fine("Got download request for: " + ByteFormatter.encodeString(hash)
+ " timeout: " + timeout + " sources has: " + sources.length);
// no download if we've already got it
try {
Download dl = pluginInterface.getDownloadManager().getDownload(hash);
if (dl != null) {
Torrent torrent = dl.getTorrent();
if (torrent != null) {
return (torrent.writeToBEncodedData());
}
}
} catch (Throwable e) {
Debug.printStackTrace(e);
}
/**
* Issue a text search for the converted hash and poll for results
* until timeout expires.
*/
try {
long started = System.currentTimeMillis();
/**
* Special case -- we just started up. In which case, this will
* surely fail (since we have no connected friends). If we
* started a minute ago or less, first wait until we have one
* connected friend
*/
while (getOnlineFriends().size() == 0
&& started + timeout > System.currentTimeMillis()) {
logger.fine("Waiting for friend connection before issuing magnet search: "
+ (System.currentTimeMillis() - started));
Thread.sleep(1000);
}
if (getOnlineFriends().size() == 0) {
logger.warning("No online friends -- couldn't download magnet link.");
return null;
}
int search_id = OSF2FPlugin.this.sendTextSearch("id:"
+ new String(Base64.encode(hash)));
/**
* TODO: This needs to be rewritten to query multiple potential
* sources for metainfo. Unfortunately, all sources aren't
* exposed in the TextSearchResult structure right now, so we do
* the same thing as the rest of the code: use the first.
*/
final ByteArrayOutputStream out = new ByteArrayOutputStream();
boolean requested = false;
while (started + timeout > System.currentTimeMillis()) {
List<TextSearchResult> results = OSF2FPlugin.this
.getTextSearchResult(search_id);
if (results.size() > 0 && !requested) {
requested = true;
final int channel_id = results.get(0).getFirstSeenChannelId();
final int connection_id = results.get(0).getFirstSeenConnectionId();
OSF2FPlugin.this.sendMetaInfoRequest(connection_id, channel_id, hash, 0,
new PluginCallback<byte[]>() {
@Override
public void dataRecieved(long count) {
progress.reportActivity("Read: " + count);
logger.finer("Read " + count);
}
@Override
public void errorOccured(String str) {
progress.reportActivity("Error: " + str);
logger.warning("Error occurred during metainfo download: "
+ connection_id + " / " + channel_id + " / " + str);
}
@Override
public void progressUpdate(int percentage) {
progress.reportCompleteness(percentage);
logger.finer("Progress updated: " + percentage);
}
@Override
public void requestCompleted(byte[] bytes) {
try {
out.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
logger.fine("Metainfo DL completed: " + bytes.length
+ " / " + (new String(Base64.encode(hash))));
}
});
}
if (out.size() > 0) {
return out.toByteArray();
}
Thread.sleep(100);
}
} catch (Throwable e) {
Debug.printStackTrace(e);
}
return null;
}
@Override
public int get(String name, Map values) {
return Integer.MIN_VALUE;
}
@Override
public boolean set(String name, Map values) {
return false;
}
};
@Override
public void initialize(final PluginInterface pluginInterface) throws PluginException {
System.err.println("Loading friend-to-friend plugin");
Log.setLogger(pluginInterface.getLogger());
main = OSF2FMain.getSingelton();
main.init(pluginInterface);
if (ADD_INFO_TO_AZ_SWT_UI) {
new OSF2FAzSwtUi(main).initialize(pluginInterface);
}
MagnetURIHandler.getSingleton()
.addListener(new OneSwarmURIHandlerListener(pluginInterface));
}
public Integer addFriend(Friend f) {
return main.getFriendManager().addFriend(f);
}
public void stopTransfers() {
main.getOverlayManager().closeAllConnections();
}
public void restartTransfers() {
main.getOverlayManager().restartAllConnections();
}
public void connectToFriend(String publicKey) {
Friend f = getFriend(publicKey);
if (f != null) {
main.getDHTConnector().connectToFriend(f);
} else {
Log.log(Log.LT_WARNING, "Friend not found: " + publicKey, true);
}
}
public void sendChatToFriend(Friend friend, String inPlaintextMessage) {
main.getOverlayManager().sendChatMessage(friend.getConnectionId(), inPlaintextMessage);
}
public Friend getFriend(String publicKey) {
publicKey = publicKey.replaceAll("\\s+", "");
Friend f = main.getFriendManager().getFriend(Base64.decode(publicKey));
return f;
}
public Map<Integer, Friend> getOnlineFriends() {
Map<Integer, Friend> friends = main.getOverlayManager().getConnectedFriends();
// System.out.println("connected friends: " + friends.size());
return friends;
}
public List<Friend> getFriends() {
return Arrays.asList(main.getFriendManager().getFriends());
}
public void sendFileListRequest(int connectionId, long maxCacheAge,
PluginCallback<FileList> callback) {
// TODO might want to check if we have a previous list
main.getOverlayManager().sendFileListRequest(connectionId, maxCacheAge, callback);
// callback.requestCompleted(new byte[10]);
}
public void sendMetaInfoRequest(int connectionId, int channelId, byte[] infohash,
int lengthHint, PluginCallback<byte[]> callback) {
main.getOverlayManager().sendMetaInfoRequest(connectionId, channelId, infohash, lengthHint,
callback);
// callback.requestCompleted(new byte[10]);
}
public int sendTextSearch(String searchString) {
return main.getOverlayManager().getSearchManager().sendTextSearch(searchString, null);
}
public List<TextSearchResult> getTextSearchResult(int searchId) {
return main.getOverlayManager().getSearchManager().getSearchResult(searchId);
}
public String getMyPublicKey() {
return new String(Base64.encode(main.getOverlayManager().getOwnPublicKey().getEncoded()));
}
public void setTorrentPrivacy(byte[] infohash, boolean publicNet, boolean f2fNet) {
(new RuntimeException("This method is deprecated. Stop using it.")).printStackTrace();
main.getF2DownloadManager().setTorrentPrivacy(infohash, publicNet, f2fNet);
}
public boolean isSharedWithFriends(byte[] infohash) {
return main.getF2DownloadManager().isSharedWithFriends(infohash);
}
public boolean isSharedWithPublic(byte[] infohash) {
return main.getF2DownloadManager().isSharedWithPublic(infohash);
}
@SuppressWarnings("unchecked")
public Map<String, String>[] getTransferStats() {
List<Map<String, String>> map = new LinkedList<Map<String, String>>();
List<FriendConnection> friendConnections = main.getOverlayManager().getFriendConnections();
// start by adding the transports, transports are ignored from now on
// only forwards are returned in this query
// for (FriendConnection fc : friendConnections) {
// ConcurrentHashMap<Integer, OverlayTransport> trans =
// fc.getOverlayTransports();
// for (OverlayTransport t : trans.values()) {
// HashMap<String, String> stats = new HashMap<String, String>();
// stats.put("type", "transport");
// stats.put("to", fc.getRemoteFriend().getNick());
// stats.put("from", "Me");
// stats.put("out", "" + t.getBytesOut());
// stats.put("in", "" + t.getBytesIn());
// stats.put("uid", "transport" +
// ByteFormatter.encodeString(fc.getRemoteFriend().getPublicKey()));
// map.add(stats);
// }
// }
// add the forwards
HashMap<Integer, OverlayForward> forwards = new HashMap<Integer, OverlayForward>();
for (FriendConnection fc : friendConnections) {
for (Integer channelId : fc.getOverlayForwards().keySet()) {
OverlayForward f = fc.getOverlayForwards().get(channelId);
// add the first forward
if (!forwards.containsKey(channelId)) {
forwards.put(channelId, f);
} else {
// this is the second, figure out in which direction the
// forward is
OverlayForward forward1 = forwards.get(channelId);
OverlayForward forward2 = f;
/*
* the forwarding rate is the sum of the rates, one in each
* direction
*/
long rate = forward1.getForwardingRate() + forward2.getForwardingRate();
long total = forward1.getBytesForwarded() + forward2.getBytesForwarded();
// this is for the ui, if the rate is close to 0, skip it
// except when total forwarded is significant, then show it
if (rate > 100 || total > 1024 * 1024) {
HashMap<String, String> stats = new HashMap<String, String>();
stats.put("id", "" + Integer.toHexString(channelId));
stats.put("type", "forward");
stats.put("rate", "" + rate);
stats.put("total", "" + total);
/*
* try to decode the content if possible, default to
* unknown
*/
stats.put("content", "unknown");
OSF2FSearch sourceMessage = forward1.getSourceMessage();
if (sourceMessage instanceof OSF2FTextSearch) {
stats.put("content",
((OSF2FTextSearch) sourceMessage).getSearchString());
} else if (sourceMessage instanceof OSF2FHashSearch) {
FileListManager filelistManager = main.getOverlayManager()
.getFilelistManager();
String torrentNameIfKnown = filelistManager
.getTorrentNameFromInfoHashHash(((OSF2FHashSearch) sourceMessage)
.getInfohashhash());
if (torrentNameIfKnown != null) {
stats.put("content", torrentNameIfKnown);
}
}
if (forward1.isSearcherSide()) {
// this means that forward one sent the search,
// forward1.remoteFriend() is the person from which
// the data is coming
stats.put("from", forward1.getRemoteFriend().getNick());
stats.put("to", forward2.getRemoteFriend().getNick());
stats.put("uid", "fwd" + forward1.getRemoteFriend().getPublicKey()
+ "->" + forward2.getRemoteFriend().getPublicKey());
} else {
stats.put("to", forward1.getRemoteFriend().getNick());
stats.put("from", forward2.getRemoteFriend().getNick());
stats.put("uid", "fwd" + forward2.getRemoteFriend().getPublicKey()
+ "->" + forward1.getRemoteFriend().getPublicKey());
}
map.add(stats);
}
}
}
}
return map.toArray(new HashMap[map.size()]);
}
public String[] getSupportedXMPPNetworks() {
return FriendImportManager.getXmppNetworks();
}
public List<Friend> getNewUsersFromXMPP(String xmppNetworkName, String username,
char[] password, String machineName) throws Exception {
List<byte[]> knownKeys = main.getFriendManager().getKnownKeysForFriendImport();
List<PublicKeyFriend> importedFriends = FriendImportManager.importXMPPFriends(knownKeys,
xmppNetworkName, username, password, machineName);
if (importedFriends == null) {
return new LinkedList<Friend>();
}
List<Friend> newFriends = main.getFriendManager().convertToFriendArrayAndFilter(
importedFriends);
return newFriends;
}
public void disconnectFriend(Friend inFriend) {
main.getOverlayManager().disconnectFriend(inFriend);
}
public void setFriendSettings(String publicKey, String nickname, boolean blocked,
boolean canSeeFileList, boolean allowChat, boolean requestFileList, String group) {
Friend f = getFriend(publicKey);
if (f != null) {
boolean triggerLookup = false;
if (f.isBlocked() && !blocked) {
triggerLookup = true;
}
boolean sendFileList = false;
if (f.isCanSeeFileList() != canSeeFileList) {
sendFileList = true;
}
String oldNick = f.getNick();
Log.log("updating: " + nickname, true);
f.setNick(nickname);
f.setBlocked(blocked);
f.setCanSeeFileList(canSeeFileList);
f.setRequestFileList(requestFileList);
f.setAllowChat(allowChat);
f.setNewFriend(false);
f.setGroup(group);
System.out.println("setting group: " + group);
if (f.getDateAdded() == null) {
f.setDateAdded(new Date());
} else if (f.getDateAdded().equals(new Date(0))) {
f.setDateAdded(new Date());
}
if (blocked) {
// disconnect all connections to the friend
disconnectFriend(f);
}
main.getFriendManager().flushToDisk(false, true, false);
if (triggerLookup) {
main.getDHTConnector().connectToFriend(f);
try {
main.getDHTConnector().publishLocationInfoForFriend(f);
} catch (Exception e) {
}
}
/**
* PIAMOD -- syncing with the groups code here (we may have changed
* the name)
*/
// PermissionsDAO.get().refresh_friend_groups();
try {
GroupBean userGroup = PermissionsDAO.get().getUserGroup(
new String(Base64.encode(f.getPublicKey())));
// New users may have no GroupBean.
if (userGroup != null) {
PermissionsDAO.get().renameGroup(userGroup.getGroupID(), f.getNick());
} else {
logger.warning("Couldn't rename group (GroupBean null): " + f.getNick());
}
} catch (IOException e) {
logger.warning("Group rename failed: " + e.toString());
e.printStackTrace();
}
if (f.getStatus() == Friend.STATUS_ONLINE && sendFileList) {
main.getOverlayManager().triggerFileListUpdates();
}
} else {
Log.log(Log.LT_WARNING, "Friend not found: " + publicKey, true);
}
}
public List<Integer> getAndClearTextSearchStats() {
return main.getOverlayManager().getSearchManager().getAndClearTextSearchStats();
}
public List<Integer> getAndClearHashSearchStats() {
return main.getOverlayManager().getSearchManager().getAndClearHashSearchStats();
}
public int getAndClearForwardedSearchNum() {
return main.getOverlayManager().getSearchManager().getAndClearForwardedSearchNum();
}
public Map<Friend, FileList> getOnlineFileLists() {
Map<Friend, FileList> onlineFileLists = new HashMap<Friend, FileList>();
List<Friend> friends = new LinkedList<Friend>(getOnlineFriends().values());
for (Friend friend : friends) {
FileList fl = main.getOverlayManager().getFilelistManager().getFriendsList(friend);
onlineFileLists.put(friend, fl);
}
return onlineFileLists;
}
public void registerForFriendConnectNotifications(FriendConnectListener callback) {
main.getOverlayManager().registerForConnectNotifications(callback);
}
public List<Friend> getLanOneSwarmUsers() {
LanFriendFinder lanFriendFinder = main.getLanFriendFinder();
if (lanFriendFinder != null) {
return lanFriendFinder.getNearbyUsers();
}
return new LinkedList<Friend>();
}
public void refreshFileLists() {
main.getOverlayManager().getFilelistManager().scheduleFileListRefresh();
}
public Map<String, Integer> getNewFriendsCountsFromAutoCheck() {
Map<String, Integer> newFriendsCountsFromAutoCheck = main.getFriendManager()
.getNewFriendsCountsFromAutoCheck();
List<Friend> lanOneSwarmUsers = getLanOneSwarmUsers();
List<Friend> lanUsers = main.getFriendManager().filterKnownFriends(lanOneSwarmUsers);
/*
* only show lan users as requests if they have attempted to connect
*/
int num = 0;
for (Friend lanUser : lanUsers) {
if (main.getFriendManager().hasTriedToConnect(lanUser)) {
if (!main.getFriendManager().isOnIgnoreRequestList(
new String(Base64.encode(lanUser.getPublicKey())))) {
num++;
} else {
logger.fine("not adding friend, is on ignore request list");
}
} else {
// logger.finest("not adding friends, has not tried to connect");
}
}
newFriendsCountsFromAutoCheck.put("Lan", num);
return newFriendsCountsFromAutoCheck;
}
public Map<byte[], String> getDeniedIncomingConnections() {
return main.getFriendManager().getDeniedIncomingConnections();
}
public void deleteFriend(String publicKey) {
Friend f = getFriend(publicKey);
if (f != null) {
/*
* remove the friend and disconnect any existing connections
*/
main.getFriendManager().removeFriend(f.getPublicKey());
main.getOverlayManager().disconnectFriend(f);
} else {
Log.log(Log.LT_WARNING, "Friend not found: " + publicKey, true);
}
}
public void addToIgnoreRequestList(String publicKey) {
main.getFriendManager().addToIgnoreRequestList(publicKey);
}
public String getGtalkStatus() {
return FriendImportManager.getGtalkStatus();
}
public FriendInvitation createInvitation(String name, boolean canSeeFileList, long maxAge,
byte securityLevel) {
return main.getAuthManager().createInvitation(name, canSeeFileList, maxAge, securityLevel);
}
public void redeemInvitation(FriendInvitation invitation, boolean testOnly) throws Exception {
main.redeemInvitation(invitation, testOnly);
}
public void updateInvitation(FriendInvitation invitation) {
main.getAuthManager().updateInvitation(invitation);
}
public void deleteInvitation(FriendInvitation invitation) {
main.getAuthManager().deleteInvitation(invitation);
}
public FriendInvitation getInvitation(HashWrapper key) {
return main.getAuthManager().getInvitation(key);
}
public List<FriendInvitation> getLocallyCreatedInvitations() {
return main.getAuthManager().getLocallyCreatedInvitations();
}
public List<FriendInvitation> getRedeemedInvitations() {
return main.getAuthManager().getRedeemedInvitations();
}
public String getDebugInfo() {
StringBuilder b = new StringBuilder();
long msSinceCheck = System.currentTimeMillis()
- main.getOverlayManager().getLastConnectionCheckRun();
b.append("Last connection check run: " + (msSinceCheck / 1000) + "s ago\n");
b.append("Queue:\n");
b.append(main.getOverlayManager().getQueueManager().getDebug() + "\n");
List<FriendConnection> friendConnections = main.getOverlayManager().getFriendConnections();
int totalForwards = 0;
int totalTransports = 0;
for (FriendConnection f : friendConnections) {
totalForwards += f.getOverlayForwards().size();
totalTransports += f.getOverlayTransports().size();
}
b.append("Total forwards: " + totalForwards + "\n");
b.append("Total transports: " + totalTransports + "\n\n");
b.append("Friend Connections Summary:\n");
for (FriendConnection f : friendConnections) {
b.append(f.getRemoteFriend().getNick() + " (" + f.getRemoteIp() + ") sendQueueBytes="
+ f.getTotalOutgoingQueueLengthBytes() + " lastSent="
+ f.getLastMessageSentTime() + " lastReci=" + f.getLastMessageRecvTime() + " "
+ "imageMetaQueue=" + f.getImageMetaInfoQueueSize() + " " + "torrentMetaQeue="
+ f.getTorrentMetaInfoQueueSize() + "\n");
b.append(f.getQueueDebug());
}
b.append("\nFriend Connections Details:\n");
for (FriendConnection f : friendConnections) {
b.append(f.getRemoteFriend().getNick() + " (" + f.getRemoteIp() + ") sendQueueBytes="
+ f.getTotalOutgoingQueueLengthBytes() + " lastSent="
+ f.getLastMessageSentTime() + " lastReci=" + f.getLastMessageRecvTime() + "\n");
b.append(f.getQueueDebug());
Map<Integer, OverlayForward> overlayForwards = f.getOverlayForwards();
if (overlayForwards.size() > 0) {
b.append(" Forwards:\n");
}
for (OverlayForward of : overlayForwards.values()) {
b.append(" channel=" + Integer.toHexString(of.getChannelId()) + " "
+ of.getRemoteFriend().getNick() + " lastSent=" + of.getLastMsgTime()
+ " src=" + of.getSourceMessage().getDescription() + "\n");
}
Collection<EndpointInterface> transports = f.getOverlayTransports().values();
if (transports.size() > 0) {
b.append(" Transports: \n");
}
for (EndpointInterface ot : transports) {
b.append(" channel=" + Integer.toHexString(ot.getChannelId()) + " path="
+ Integer.toHexString(ot.getPathID()[0])
+ "(x" + ot.getPathID().length + " lastSent=" + ot.getLastMsgTime() + "\n");
}
}
b.append("\n\n");
List<String> sentSearches = main.getOverlayManager().getSearchManager().debugSentSearches();
if (sentSearches.size() > 0) {
b.append("Sent Searches:\n");
for (String string : sentSearches) {
b.append(" " + string + "\n");
}
b.append("\n");
}
List<String> forwardedSearches = main.getOverlayManager().getSearchManager()
.debugForwardedSearches();
if (forwardedSearches.size() > 0) {
b.append("Forwarded Searches:\n");
for (String string : forwardedSearches) {
b.append(" " + string + "\n");
}
b.append("\n");
}
List<String> canceledSearches = main.getOverlayManager().getSearchManager()
.debugCanceledSearches();
if (canceledSearches.size() > 0) {
b.append("Canceled searches:\n");
for (String c : canceledSearches) {
b.append(" " + c + "\n");
}
b.append("\n");
}
return b.toString();
}
public String getDebugMessageLog(String friendPublicKey) {
List<FriendConnection> friendConnections = main.getOverlayManager().getFriendConnections();
for (FriendConnection f : friendConnections) {
if (Arrays.equals(f.getRemotePublicKey(), Base64.decode(friendPublicKey))) {
return f.getDebugMessageLog();
}
}
return "friend not online";
}
public String getSearchDebugLog() {
StringBuilder b = new StringBuilder();
FileListManager fm = main.getOverlayManager().getFilelistManager();
long searchesTotal = fm.getSearchesTotal();
long searchCacheHits = fm.getSearchCacheHits();
long percent = 0;
if (searchesTotal > 0) {
percent = (100 * searchCacheHits) / searchesTotal;
}
b.append("search cache: \n total_searches=" + searchesTotal + " cache_hits="
+ searchCacheHits + "(" + percent + "%)\n\n");
b.append(main.getOverlayManager().getSearchManager().getSearchDebug());
return b.toString();
}
public Friend[] scanXMLForFriends(String xml) {
try {
XMLDecoder decoder = new XMLDecoder(new BufferedInputStream(new ByteArrayInputStream(
xml.getBytes())), this, null, main.getClassLoader());
FriendBean[] o = (FriendBean[]) decoder.readObject();
Friend[] conv = new Friend[o.length];
int i = 0;
for (FriendBean extracted : o) {
conv[i++] = main.getFriendManager().getFriend(extracted);
}
decoder.close();
return conv;
} catch (Exception e) {
System.err.println("error scanning XML for friends: " + e.toString());
return null;
}
}
public String getLockDebug() {
return OverlayManager.lock.getLockDebug();
}
public String getForwardQueueLengthDebug() {
return main.getOverlayManager().getQueueManager().getForwardQueueLengthDebug();
}
public int performSpeedCheck() {
return main.getSpeedChecker().performSpeedCheck();
}
public void cancelSpeedCheck(int testId) {
OutgoingSpeedCheck check = main.getSpeedChecker().getSpeedCheck(testId);
if (check != null) {
check.close();
}
}
public HashMap<String, Double> getSpeedCheckResult(int checkId) {
OutgoingSpeedCheck speedCheck = main.getSpeedChecker().getSpeedCheck(checkId);
if (speedCheck == null) {
return null;
}
HashMap<String, Double> result = new HashMap<String, Double>();
result.put("progress", speedCheck.getProgress());
result.put("local", 1.0 * speedCheck.getLocalEstimate());
result.put("remote", 1.0 * speedCheck.getRemoteEstimate());
result.put("completed", speedCheck.isCompleted() ? 1.0 : 0.0);
result.put("closed", speedCheck.isClosed() ? 1.0 : 0.0);
result.put("good_servers", speedCheck.getGoodServers() * 1.0);
result.put("total_servers", speedCheck.getServerCount() * 1.0);
return result;
}
public void triggerNATCheck() {
main.getNatChecker().triggerNatCheck();
}
public HashMap<String, String> getNatCheckResult() {
NatCheckResult res = main.getNatChecker().getResult();
HashMap<String, String> map = new HashMap<String, String>();
if (res == null) {
return map;
}
map.put("status", "" + res.getStatus().getCode());
if (res.getStatus() == Status.SUCCESS) {
map.put("ip", res.ip);
map.put("port", "" + res.port);
}
return map;
}
}