/* * Created on Dec 20, 2004 * Created by Alon Rohter * Copyright (C) 2004-2005 Aelitis, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * AELITIS, SAS au capital de 46,603.30 euros * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. * */ package com.aelitis.azureus.core.versioncheck; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketException; import java.net.URL; import java.net.URLEncoder; import java.net.UnknownHostException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; import org.gudy.azureus2.core3.config.COConfigurationManager; import org.gudy.azureus2.core3.config.ParameterListener; import org.gudy.azureus2.core3.internat.MessageText; import org.gudy.azureus2.core3.logging.LogAlert; import org.gudy.azureus2.core3.logging.LogEvent; import org.gudy.azureus2.core3.logging.LogIDs; import org.gudy.azureus2.core3.logging.Logger; import org.gudy.azureus2.core3.stats.transfer.OverallStats; import org.gudy.azureus2.core3.stats.transfer.StatsFactory; import org.gudy.azureus2.core3.stats.transfer.impl.OverallStatsImpl; import org.gudy.azureus2.core3.util.AEMonitor; import org.gudy.azureus2.core3.util.AEThread; import org.gudy.azureus2.core3.util.BDecoder; import org.gudy.azureus2.core3.util.BEncoder; import org.gudy.azureus2.core3.util.Constants; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.core3.util.SystemProperties; import org.gudy.azureus2.core3.util.SystemTime; import org.gudy.azureus2.plugins.PluginInterface; import org.gudy.azureus2.plugins.ipc.IPCException; import org.gudy.azureus2.plugins.ipc.IPCInterface; import org.gudy.azureus2.update.CoreUpdateChecker; import com.aelitis.azureus.core.AzureusCoreFactory; import com.aelitis.azureus.core.clientmessageservice.ClientMessageService; import com.aelitis.azureus.core.clientmessageservice.ClientMessageServiceClient; import com.aelitis.azureus.core.impl.AzureusCoreImpl; import com.aelitis.azureus.core.networkmanager.admin.NetworkAdmin; import com.aelitis.azureus.core.networkmanager.admin.NetworkAdminASN; import com.aelitis.azureus.core.networkmanager.impl.osssl.OneSwarmSslKeyManager; import com.aelitis.net.udp.uc.PRUDPPacketHandler; import com.aelitis.net.udp.uc.PRUDPPacketHandlerFactory; import com.aelitis.net.udp.uc.PRUDPReleasablePacketHandler; import edu.washington.cs.oneswarm.f2f.Friend; /** * Client for checking version information from a remote server. */ public class VersionCheckClient { private static final LogIDs LOGID = LogIDs.CORE; public static final String REASON_UPDATE_CHECK_START = "us"; public static final String REASON_UPDATE_CHECK_PERIODIC = "up"; public static final String REASON_CHECK_SWT = "sw"; public static final String REASON_DHT_EXTENDED_ALLOWED = "dx"; public static final String REASON_DHT_ENABLE_ALLOWED = "de"; public static final String REASON_EXTERNAL_IP = "ip"; public static final String REASON_RECOMMENDED_PLUGINS = "rp"; public static final String REASON_SECONDARY_CHECK = "sc"; private static final String AZ_MSG_SERVER_ADDRESS_V4 = Constants.VERSION_SERVER_V4; private static final int AZ_MSG_SERVER_PORT = 27001; private static final String MESSAGE_TYPE_ID = "AZVER"; public static final String HTTP_SERVER_ADDRESS_V4 = AZ_MSG_SERVER_ADDRESS_V4; public static final int HTTP_SERVER_PORT = 80; public static final String TCP_SERVER_ADDRESS_V4 = AZ_MSG_SERVER_ADDRESS_V4; public static final int TCP_SERVER_PORT = 80; public static final String UDP_SERVER_ADDRESS_V4 = AZ_MSG_SERVER_ADDRESS_V4; public static final int UDP_SERVER_PORT = 2080; public static final String AZ_MSG_SERVER_ADDRESS_V6 = Constants.VERSION_SERVER_V6; public static final String HTTP_SERVER_ADDRESS_V6 = AZ_MSG_SERVER_ADDRESS_V6; public static final String TCP_SERVER_ADDRESS_V6 = AZ_MSG_SERVER_ADDRESS_V6; public static final String UDP_SERVER_ADDRESS_V6 = AZ_MSG_SERVER_ADDRESS_V6; private static final long CACHE_PERIOD = 10 * 1000; private static boolean secondary_check_done; static { VersionCheckClientUDPCodecs.registerCodecs(); } private static final int AT_V4 = 1; private static final int AT_V6 = 2; private static final int AT_EITHER = 3; private static VersionCheckClient instance; /** * Get the singleton instance of the version check client. * @return version check client */ public static synchronized VersionCheckClient getSingleton() { if (instance == null) { instance = new VersionCheckClient(); } return (instance); } private boolean prefer_v6; private Map last_check_data_v4 = null; private Map last_check_data_v6 = null; private final AEMonitor check_mon = new AEMonitor( "versioncheckclient"); private long last_check_time_v4 = 0; private long last_check_time_v6 = 0; private long last_feature_flag_cache; private long last_feature_flag_cache_time; private VersionCheckClient() { COConfigurationManager.addAndFireParameterListener("IPV6 Prefer Addresses", new ParameterListener() { public void parameterChanged(String name) { prefer_v6 = COConfigurationManager.getBooleanParameter(name); } }); } /** * Get the version check reply info. * @return reply data, possibly cached, if the server was already checked within the last minute */ public Map getVersionCheckInfo(String reason) { return (getVersionCheckInfo(reason, AT_EITHER)); } public Map getVersionCheckInfo(String reason, int address_type) { if (address_type == AT_V4) { return (getVersionCheckInfoSupport(reason, false, false, false)); } else if (address_type == AT_V6) { return (getVersionCheckInfoSupport(reason, false, false, true)); } else { Map reply = getVersionCheckInfoSupport(reason, false, false, prefer_v6); if (reply == null || reply.size() == 0) { reply = getVersionCheckInfoSupport(reason, false, false, !prefer_v6); } return (reply); } } protected Map getVersionCheckInfoSupport(String reason, boolean only_if_cached, boolean force, boolean v6) { if (v6) { try { check_mon.enter(); long time_diff = SystemTime.getCurrentTime() - last_check_time_v6; force = force || time_diff > CACHE_PERIOD || time_diff < 0; if (last_check_data_v6 == null || last_check_data_v6.size() == 0 || force) { // if we've never checked before then we go ahead even if the "only_if_cached" // flag is set as its had not chance of being cached yet! if (only_if_cached && last_check_data_v6 != null) { return (new HashMap()); } try { last_check_data_v6 = performVersionCheck( constructVersionCheckMessage(reason), false, true, true); if (last_check_data_v6 != null && last_check_data_v6.size() > 0) { COConfigurationManager.setParameter("versioncheck.cache.v6", last_check_data_v6); } } catch (SocketException t) { // internet is broken Debug.out(t.getClass().getName() + ": " + t.getMessage()); } catch (UnknownHostException t) { // dns is broken Debug.out(t.getClass().getName() + ": " + t.getMessage()); } catch (Throwable t) { Debug.out(t); last_check_data_v6 = new HashMap(); } } else { Logger.log(new LogEvent(LOGID, "VersionCheckClient is using " + "cached version check info. Using " + last_check_data_v6.size() + " reply keys.")); } } finally { check_mon.exit(); } if (last_check_data_v6 == null) last_check_data_v6 = new HashMap(); return last_check_data_v6; } else { try { check_mon.enter(); long time_diff = SystemTime.getCurrentTime() - last_check_time_v4; force = force || time_diff > CACHE_PERIOD || time_diff < 0; if (last_check_data_v4 == null || last_check_data_v4.size() == 0 || force) { // if we've never checked before then we go ahead even if the "only_if_cached" // flag is set as its had not chance of being cached yet! if (only_if_cached && last_check_data_v4 != null) { return (new HashMap()); } try { last_check_data_v4 = performVersionCheck( constructVersionCheckMessage(reason), false, true, false); if (last_check_data_v4 != null && last_check_data_v4.size() > 0) { COConfigurationManager.setParameter("versioncheck.cache.v4", last_check_data_v4); } // clear down any plugin-specific data that has successfully been sent to the version server try { if (AzureusCoreFactory.isCoreAvailable()) { //installed plugin IDs PluginInterface[] plugins = AzureusCoreFactory.getSingleton().getPluginManager().getPluginInterfaces(); for (int i = 0; i < plugins.length; i++) { PluginInterface plugin = plugins[i]; Map data = plugin.getPluginconfig().getPluginMapParameter( "plugin.versionserver.data", null); if (data != null) { plugin.getPluginconfig().setPluginMapParameter( "plugin.versionserver.data", new HashMap()); } } } } catch (Throwable e) { } } catch (UnknownHostException t) { // no internet Debug.outNoStack("VersionCheckClient - " + t.getClass().getName() + ": " + t.getMessage()); } catch (IOException t) { // General connection problem. Debug.outNoStack("VersionCheckClient - " + t.getClass().getName() + ": " + t.getMessage()); } catch (Throwable t) { Debug.out(t); last_check_data_v4 = new HashMap(); } } else { if (Logger.isEnabled()) Logger.log(new LogEvent(LOGID, "VersionCheckClient is using " + "cached version check info. Using " + last_check_data_v4.size() + " reply keys.")); } } finally { check_mon.exit(); } if (last_check_data_v4 == null) last_check_data_v4 = new HashMap(); return last_check_data_v4; } } private boolean isVersionCheckDataValid(int address_type) { boolean v6_ok = last_check_data_v6 != null && last_check_data_v6.size() > 0; boolean v4_ok = last_check_data_v4 != null && last_check_data_v4.size() > 0; if (address_type == AT_V4) { return (v4_ok); } else if (address_type == AT_V6) { return (v6_ok); } else { return (v4_ok | v6_ok); } } protected Map getMostRecentVersionCheckData() { // currently we maintain v4 much more accurately than v6 if (last_check_data_v4 != null) { return (last_check_data_v4); } Map res = COConfigurationManager.getMapParameter("versioncheck.cache.v4", null); if (res != null) { return (res); } if (last_check_data_v6 != null) { return (last_check_data_v6); } res = COConfigurationManager.getMapParameter("versioncheck.cache.v6", null); return (res); } public long getFeatureFlags() { long now = SystemTime.getCurrentTime(); if (now > last_feature_flag_cache_time && now - last_feature_flag_cache_time < 60000) { return (last_feature_flag_cache); } Map m = getMostRecentVersionCheckData(); long result; if (m == null) { result = 0; } else { byte[] b_feat_flags = (byte[]) m.get("feat_flags"); if (b_feat_flags != null) { try { result = Long.parseLong(new String((byte[]) b_feat_flags)); } catch (Throwable e) { result = 0; } } else { result = 0; } } last_feature_flag_cache = result; last_feature_flag_cache_time = now; return (result); } public long getCacheTime(boolean v6) { return (v6 ? last_check_time_v6 : last_check_time_v4); } /** * Get the ip address seen by the version check server. * NOTE: This information may be cached, see getVersionCheckInfo(). * @return external ip address, or empty string if no address information found */ public String getExternalIpAddress(boolean only_if_cached, boolean v6) { Map reply = getVersionCheckInfoSupport(REASON_EXTERNAL_IP, only_if_cached, false, v6); byte[] address = (byte[]) reply.get("source_ip_address"); if (address != null) { return new String(address); } return (null); } /** * Is the DHT plugin allowed to be enabled. * @return true if DHT can be enabled, false if it should not be enabled */ public boolean DHTEnableAllowed() { return true; // PIAMOD -- no more remote control of DHT // Map reply = getVersionCheckInfo(REASON_DHT_ENABLE_ALLOWED, AT_EITHER); // // boolean res = false; // // byte[] value = (byte[]) reply.get("enable_dht"); // // if (value != null) { // // res = new String(value).equalsIgnoreCase("true"); // } // // // we take the view that if the version check failed then we go ahead // // and enable the DHT (i.e. we're being optimistic) // // if (!res) { // res = !isVersionCheckDataValid(AT_EITHER); // } // // return res; } /** * Is the DHT allowed to be used by external plugins. * @return true if extended DHT use is allowed, false if not allowed */ public boolean DHTExtendedUseAllowed() { return true; /** * PIAMOD -- no more remote control of plugin use of DHT */ // Map reply = getVersionCheckInfo(REASON_DHT_EXTENDED_ALLOWED, AT_EITHER); // // boolean res = false; // // byte[] value = (byte[]) reply.get("enable_dht_extended_use"); // if (value != null) { // res = new String(value).equalsIgnoreCase("true"); // } // // // be generous and enable extended use if check failed // // if (!res) { // res = !isVersionCheckDataValid(AT_EITHER); // } // // return res; } public String[] getRecommendedPlugins() { /** * PIAMOD -- no more recommended plugins. */ return new String[] {}; // Map reply = getVersionCheckInfo(REASON_RECOMMENDED_PLUGINS, AT_EITHER); // // List l = (List) reply.get("recommended_plugins"); // // if (l == null) { // // return (new String[0]); // } // // String[] res = new String[l.size()]; // // for (int i = 0; i < l.size(); i++) { // // res[i] = new String((byte[]) l.get(i)); // } // // for( String s : res ) { // System.out.println("update instrumentation: recommended: " + s); // } // // return (res); } /** * Perform the actual version check by connecting to the version server. * @param data_to_send version message * @return version reply * @throws Exception if the server check connection fails */ private Map performVersionCheck(Map data_to_send, boolean use_az_message, boolean use_http, boolean v6) throws Exception { Exception error = null; Map reply = null; if (use_az_message) { try { reply = executeAZMessage(data_to_send, v6); reply.put("protocol_used", "AZMSG"); } catch (IOException e) { error = e; } catch (Exception e) { Debug.printStackTrace(e); error = e; } } if (reply == null && use_http) { try { reply = executeHTTP(data_to_send, v6); reply.put("protocol_used", "HTTP"); error = null; } catch (IOException e) { error = e; } catch (Exception e) { Debug.printStackTrace(e); error = e; } } if (error != null) { throw (error); } if (Logger.isEnabled()) Logger.log(new LogEvent(LOGID, "VersionCheckClient server " + "version check successful. Received " + reply.size() + " reply keys.")); if (v6) { last_check_time_v6 = SystemTime.getCurrentTime(); } else { last_check_time_v4 = SystemTime.getCurrentTime(); } return reply; } private Map executeAZMessage(Map data_to_send, boolean v6) throws Exception { String host = v6 ? AZ_MSG_SERVER_ADDRESS_V6 : AZ_MSG_SERVER_ADDRESS_V4; if (Logger.isEnabled()) Logger.log(new LogEvent(LOGID, "VersionCheckClient retrieving " + "version information from " + host + ":" + AZ_MSG_SERVER_PORT)); ClientMessageService msg_service = null; Map reply = null; try { msg_service = ClientMessageServiceClient.getServerService(host, AZ_MSG_SERVER_PORT, MESSAGE_TYPE_ID); msg_service.sendMessage(data_to_send); //send our version message reply = msg_service.receiveMessage(); //get the server reply preProcessReply(reply, v6); } finally { if (msg_service != null) { msg_service.close(); } } return (reply); } private Map executeHTTP(Map data_to_send, boolean v6) throws Exception { String host = v6 ? HTTP_SERVER_ADDRESS_V6 : HTTP_SERVER_ADDRESS_V4; if (Logger.isEnabled()) Logger.log(new LogEvent(LOGID, "VersionCheckClient retrieving " + "version information from " + host + ":" + HTTP_SERVER_PORT + " via HTTP")); String url_str = "http://" + host + (HTTP_SERVER_PORT == 80 ? "" : (":" + HTTP_SERVER_PORT)) + "/version?"; url_str += URLEncoder.encode(new String(BEncoder.encode(data_to_send), Constants.DEFAULT_ENCODING), Constants.DEFAULT_ENCODING); URL url = new URL(url_str); HttpURLConnection url_connection = (HttpURLConnection) url.openConnection(); url_connection.connect(); try { InputStream is = url_connection.getInputStream(); Map reply = BDecoder.decode(new BufferedInputStream(is)); preProcessReply(reply, v6); return (reply); } finally { url_connection.disconnect(); } } public String getHTTPGetString(boolean for_proxy, boolean v6) { return (getHTTPGetString(new HashMap(), for_proxy, v6)); } private String getHTTPGetString(Map content, boolean for_proxy, boolean v6) { String host = v6 ? HTTP_SERVER_ADDRESS_V6 : HTTP_SERVER_ADDRESS_V4; String get_str = "GET " + (for_proxy ? ("http://" + host + ":" + HTTP_SERVER_PORT) : "") + "/version?"; try { get_str += URLEncoder.encode(new String(BEncoder.encode(content), "ISO-8859-1"), "ISO-8859-1"); } catch (Throwable e) { } get_str += " HTTP/1.1" + "\015\012" + "\015\012"; return (get_str); } private Map executeTCP(Map data_to_send, InetAddress bind_ip, int bind_port, boolean v6) throws Exception { String host = v6 ? TCP_SERVER_ADDRESS_V6 : TCP_SERVER_ADDRESS_V4; if (Logger.isEnabled()) Logger.log(new LogEvent(LOGID, "VersionCheckClient retrieving " + "version information from " + host + ":" + TCP_SERVER_PORT + " via TCP")); String get_str = getHTTPGetString(data_to_send, false, v6); Socket socket = null; try { socket = new Socket(); if (bind_ip != null) { socket.bind(new InetSocketAddress(bind_ip, bind_port)); } else if (bind_port != 0) { socket.bind(new InetSocketAddress(bind_port)); } socket.setSoTimeout(10000); socket.connect(new InetSocketAddress(host, TCP_SERVER_PORT), 10000); OutputStream os = socket.getOutputStream(); os.write(get_str.getBytes("ISO-8859-1")); os.flush(); InputStream is = socket.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int total_len = 0; while (true) { int len = is.read(buffer); if (len <= 0) { break; } total_len += len; if (total_len > 16000) { throw (new IOException("reply too large")); } baos.write(buffer, 0, len); } byte[] reply_bytes = baos.toByteArray(); for (int i = 3; i < reply_bytes.length; i++) { if (reply_bytes[i - 3] == (byte) '\015' && reply_bytes[i - 2] == (byte) '\012' && reply_bytes[i - 1] == (byte) '\015' && reply_bytes[i - 0] == (byte) '\012') { Map reply = BDecoder.decode(new BufferedInputStream( new ByteArrayInputStream(reply_bytes, i + 1, reply_bytes.length - (i + 1)))); preProcessReply(reply, v6); return (reply); } } throw (new Exception("Invalid reply: " + new String(reply_bytes))); } finally { if (socket != null) { try { socket.close(); } catch (Throwable e) { } } } } private Map executeUDP(Map data_to_send, InetAddress bind_ip, int bind_port, boolean v6) throws Exception { String host = v6 ? UDP_SERVER_ADDRESS_V6 : UDP_SERVER_ADDRESS_V4; PRUDPReleasablePacketHandler handler = PRUDPPacketHandlerFactory.getReleasableHandler(bind_port); PRUDPPacketHandler packet_handler = handler.getHandler(); long timeout = 5; Random random = new Random(); try { Exception last_error = null; packet_handler.setExplicitBindAddress(bind_ip); for (int i = 0; i < 3; i++) { try { // connection ids for requests must always have their msb set... // apart from the original darn udp tracker spec.... long connection_id = 0x8000000000000000L | random.nextLong(); VersionCheckClientUDPRequest request_packet = new VersionCheckClientUDPRequest( connection_id); request_packet.setPayload(data_to_send); VersionCheckClientUDPReply reply_packet = (VersionCheckClientUDPReply) packet_handler.sendAndReceive( null, request_packet, new InetSocketAddress(host, UDP_SERVER_PORT), timeout); Map reply = reply_packet.getPayload(); preProcessReply(reply, v6); return (reply); } catch (Exception e) { last_error = e; timeout = timeout * 2; } } if (last_error != null) { throw (last_error); } throw (new Exception("Timeout")); } finally { packet_handler.setExplicitBindAddress(null); handler.release(); } } protected void preProcessReply(Map reply, final boolean v6) { NetworkAdmin admin = NetworkAdmin.getSingleton(); try { byte[] address = (byte[]) reply.get("source_ip_address"); InetAddress my_ip = InetAddress.getByName(new String(address)); NetworkAdminASN old_asn = admin.getCurrentASN(); NetworkAdminASN new_asn = admin.lookupCurrentASN(my_ip); if (!new_asn.sameAs(old_asn)) { // kick off a secondary version check to communicate the new information if (!secondary_check_done) { secondary_check_done = true; new AEThread("Secondary version check", true) { public void runSupport() { getVersionCheckInfoSupport(REASON_SECONDARY_CHECK, false, true, v6); } }.start(); } } } catch (Throwable e) { Debug.printStackTrace(e); } Long as_advice = (Long) reply.get("as_advice"); if (as_advice != null) { NetworkAdminASN current_asn = admin.getCurrentASN(); String asn = current_asn.getASName(); if (asn != null) { long advice = as_advice.longValue(); if (advice != 0) { // require crypto String done_asn = COConfigurationManager.getStringParameter( "ASN Advice Followed", ""); if (!done_asn.equals(asn)) { COConfigurationManager.setParameter("ASN Advice Followed", asn); boolean change = advice == 1 || advice == 2; boolean alert = advice == 1 || advice == 3; if (!COConfigurationManager.getBooleanParameter("network.transport.encrypted.require")) { if (change) { COConfigurationManager.setParameter( "network.transport.encrypted.require", true); } if (alert) { String msg = MessageText.getString("crypto.alert.as.warning", new String[] { asn }); Logger.log(new LogAlert(false, LogAlert.AT_WARNING, msg)); } } } } } } // set ui.toolbar.uiswitcher based on instructions from tracker // Really shouldn't be in VersionCheck client, but instead have some // listener and have the code elsewhere. Simply calling //getVersionCheckInfo from "code elsewhere" (to get the cached result) //caused a deadlock at startup. Long lEnabledUISwitcher = (Long) reply.get("ui.toolbar.uiswitcher"); if (lEnabledUISwitcher != null) { COConfigurationManager.setBooleanDefault("ui.toolbar.uiswitcher", lEnabledUISwitcher.longValue() == 1); } } public InetAddress getExternalIpAddressHTTP(boolean v6) throws Exception { Map reply = executeHTTP(new HashMap(), v6); byte[] address = (byte[]) reply.get("source_ip_address"); return (InetAddress.getByName(new String(address))); } public InetAddress getExternalIpAddressTCP(InetAddress bind_ip, int bind_port, boolean v6) throws Exception { Map reply = executeTCP(new HashMap(), bind_ip, bind_port, v6); byte[] address = (byte[]) reply.get("source_ip_address"); return (InetAddress.getByName(new String(address))); } public InetAddress getExternalIpAddressUDP(InetAddress bind_ip, int bind_port, boolean v6) throws Exception { Map reply = executeUDP(new HashMap(), bind_ip, bind_port, v6); byte[] address = (byte[]) reply.get("source_ip_address"); return (InetAddress.getByName(new String(address))); } /** * Construct the default version check message. * @return message to send */ private Map constructVersionCheckMessage(String reason) { Map message = new HashMap(); //******************************************************** /* * EDIT: by isdal, adding version for our mods jar */ message.put(CoreUpdateChecker.KEY_ONE_SWARM_MOD_VERSION, Constants.getOneSwarmAzureusModsVersion()); /* * check if we should include the tcp port in the update */ if (COConfigurationManager.getLongParameter("Perform.NAT.Check", 1) > 0){ message.put("tcp_port", new Integer(COConfigurationManager.getIntParameter("TCP.Listen.Port"))); message.put("udp_port", new Integer(COConfigurationManager.getIntParameter("UDP.Listen.Port"))); } long speedTest = COConfigurationManager.getLongParameter("Allow.Incoming.Speed.Check", 0); if (speedTest > 0) { message.put("speed_test", speedTest); } /* * Check which update group we are in, currently: default, beta, planetlab */ String group = "default"; if (System.getProperty("oneswarm.experimental.config.file") != null){ group = "planetlab"; } else if (COConfigurationManager.getBooleanParameter("oneswarm.beta.updates")){ group = "beta"; } message.put("update_group", group); //*********************************************************** message.put("appid", SystemProperties.getApplicationIdentifier()); message.put("version", Constants.AZUREUS_VERSION); String id = COConfigurationManager.getStringParameter("ID", null); boolean send_info = COConfigurationManager.getBooleanParameter("Send Version Info"); int last_send_time = COConfigurationManager.getIntParameter( "Send Version Info Last Time", -1); int current_send_time = (int) (SystemTime.getCurrentTime() / 1000); COConfigurationManager.setParameter("Send Version Info Last Time", current_send_time); if (id != null && send_info) { message.put("id", id); message.put("os", Constants.OSName); message.put("os_version", System.getProperty("os.version")); message.put("os_arch", System.getProperty("os.arch")); //see http://lopica.sourceforge.net/os.html if (last_send_time != -1 && last_send_time < current_send_time) { // tims since last message.put("tsl", new Long(current_send_time - last_send_time)); } message.put("reason", reason); String java_version = System.getProperty("java.version"); if (java_version == null) { java_version = "unknown"; } message.put("java", java_version); String java_vendor = System.getProperty("java.vm.vendor"); if (java_vendor == null) { java_vendor = "unknown"; } message.put("javavendor", java_vendor); long max_mem = Runtime.getRuntime().maxMemory() / (1024 * 1024); message.put("javamx", new Long(max_mem)); String java_rt_name = System.getProperty("java.runtime.name"); if (java_rt_name != null) { message.put("java_rt_name", java_rt_name); } String java_rt_version = System.getProperty("java.runtime.version"); if (java_rt_version != null) { message.put("java_rt_version", java_rt_version); } OverallStats stats = StatsFactory.getStats(); if (stats != null) { long total_bytes_downloaded = stats.getDownloadedBytes(); long total_bytes_uploaded = stats.getUploadedBytes(); long total_uptime = stats.getTotalUpTime(); message.put("total_bytes_downloaded", new Long(total_bytes_downloaded)); message.put("total_bytes_uploaded", new Long(total_bytes_uploaded)); message.put("total_uptime", new Long(total_uptime)); //message.put( "dlstats", stats.getDownloadStats()); // ******************************************************* // Edit: by isdal // Adding performance data for the beta testing f2f stuff PluginInterface f2fIf = AzureusCoreImpl.getSingleton().getPluginManager().getPluginInterfaceByID( "osf2f"); IPCInterface f2fIpc = null; if (f2fIf != null) { if (f2fIf.isOperational()) { f2fIpc = f2fIf.getIPC(); } else { Debug.out("osf2f is not yet operational"); } } if (f2fIpc != null) { try { List<Integer> textSearch = (List<Integer>) f2fIpc.invoke( "getAndClearTextSearchStats", new Object[0]); message.put("text_search_stats", textSearch); List<Integer> hashSearch = (List<Integer>) f2fIpc.invoke( "getAndClearHashSearchStats", new Object[0]); message.put("hash_search_stats", hashSearch); Integer forwarded = (Integer) f2fIpc.invoke( "getAndClearForwardedSearchNum", new Object[0]); message.put("forwarded_search_stats", forwarded); long totalF2FUploaded = 0; long totalF2FDownloaded = 0; Map<String, Integer> friendSourceCounts = new HashMap<String, Integer>(); List<Long> datacounts = new LinkedList<Long>(); List<Friend> friends = (List<Friend>) f2fIpc.invoke("getFriends", new Object[0]); for (Friend friend : friends) { totalF2FUploaded += friend.getTotalUploaded(); totalF2FDownloaded += friend.getTotalDownloaded(); datacounts.add(friend.getTotalDownloaded()); /* * sanity checks + no reason to send full string, first 2 chars is enough */ if (friend.getSourceNetwork() != null && friend.getSourceNetwork().length() >= 2) { String friendSrc = friend.getSourceNetwork().substring(0, 2); if (!friendSourceCounts.containsKey(friendSrc)) { friendSourceCounts.put(friendSrc, 0); } friendSourceCounts.put(friendSrc, friendSourceCounts.get(friendSrc) + 1); } } OverallStatsImpl oStats = (OverallStatsImpl)stats; oStats.updateInitialF2FStats(totalF2FDownloaded, totalF2FUploaded); message.put("f2f_uploaded", oStats.getUploadedF2FBytes()); message.put("f2f_downloaded", oStats.getDownloadedF2FBytes()); message.put("add_friend_method", friendSourceCounts); // message.put("f2f_counters", datacounts); } catch (Throwable e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { Debug.out("no osf2f plugin, skipping"); System.err.println("plugin list: "); PluginInterface[] plugins = AzureusCoreImpl.getSingleton().getPluginManager().getPlugins(); for (PluginInterface p : plugins) { System.err.print(p.getPluginID() + ","); } System.err.println(""); } // *********************************************************** } try { NetworkAdminASN current_asn = NetworkAdmin.getSingleton().getCurrentASN(); String as = current_asn.getAS(); message.put("ip_as", current_asn.getAS()); String asn = current_asn.getASName(); if (asn.length() > 64) { asn = asn.substring(0, 64); } message.put("ip_asn", asn); } catch (Throwable e) { Debug.out(e); } String ui = COConfigurationManager.getStringParameter("ui"); if (ui.length() > 0) { message.put("ui", ui); } // send locale, so we can determine which languages need attention message.put("locale", Locale.getDefault().toString()); String originalLocale = System.getProperty("user.language") + "_" + System.getProperty("user.country"); String variant = System.getProperty("user.variant"); if (variant != null && variant.length() > 0) { originalLocale += "_" + variant; } message.put("orig_locale", originalLocale); try { if (AzureusCoreFactory.isCoreAvailable()) { //installed plugin IDs PluginInterface[] plugins = AzureusCoreFactory.getSingleton().getPluginManager().getPluginInterfaces(); List pids = new ArrayList(); List vs_data = new ArrayList(); for (int i = 0; i < plugins.length; i++) { PluginInterface plugin = plugins[i]; String pid = plugin.getPluginID(); String info = plugin.getPluginconfig().getPluginStringParameter( "plugin.info"); // filter out built-in and core ones if ((info != null && info.length() > 0) || (!pid.startsWith("<") && !pid.startsWith("azbp") && !pid.startsWith("azupdater") && !pid.startsWith("azplatform") && !pids.contains(pid))) { if (info != null && info.length() > 0) { if (info.length() < 256) { pid += ":" + info; } else { Debug.out("Plugin '" + pid + "' reported excessive info string '" + info + "'"); } } pids.add(pid); } Map data = plugin.getPluginconfig().getPluginMapParameter( "plugin.versionserver.data", null); if (data != null) { Map payload = new HashMap(); byte[] data_bytes = BEncoder.encode(data); if (data_bytes.length > 16 * 1024) { Debug.out("Plugin '" + pid + "' reported excessive version server data (length=" + data_bytes.length + ")"); payload.put("error", "data too long: " + data_bytes.length); } else { payload.put("data", data_bytes); } payload.put("id", pid); payload.put("version", plugin.getPluginVersion()); vs_data.add(payload); } } message.put("plugins", pids); if (vs_data.size() > 0) { message.put("plugin_data", vs_data); } } } catch (Throwable e) { Debug.out(e); } } //swt stuff try { Class c = Class.forName("org.eclipse.swt.SWT"); String swt_platform = (String) c.getMethod("getPlatform", new Class[] {}).invoke( null, new Object[] {}); message.put("swt_platform", swt_platform); if (send_info) { Integer swt_version = (Integer) c.getMethod("getVersion", new Class[] {}).invoke(null, new Object[] {}); message.put("swt_version", new Long(swt_version.longValue())); c = Class.forName("org.gudy.azureus2.ui.swt.mainwindow.MainWindow"); if (c != null) { c.getMethod("addToVersionCheckMessage", new Class[] { Map.class }).invoke(null, new Object[] { message }); } } } catch (ClassNotFoundException e) { /* ignore */ } catch (NoClassDefFoundError er) { /* ignore */ } catch (InvocationTargetException err) { /* ignore */ } catch (Throwable t) { t.printStackTrace(); } boolean using_phe = COConfigurationManager.getBooleanParameter("network.transport.encrypted.require"); message.put("using_phe", using_phe ? new Long(1) : new Long(0)); return message; } public static void main(String[] args) { try { COConfigurationManager.initialise(); boolean v6 = false; System.out.println("UDP: " + getSingleton().getExternalIpAddressUDP(null, 0, v6)); System.out.println("TCP: " + getSingleton().getExternalIpAddressTCP(null, 0, v6)); System.out.println("HTTP: " + getSingleton().getExternalIpAddressHTTP(v6)); } catch (Throwable e) { e.printStackTrace(); } } }