public void runSupport() {
    byte[] input_buffer = new byte[request_dg.getLength()];

    System.arraycopy(request_dg.getData(), 0, input_buffer, 0, input_buffer.length);

    int packet_data_length = input_buffer.length;

    String auth_user = null;
    byte[] auth_user_bytes = null;
    byte[] auth_hash = null;

    if (server.isTrackerPasswordEnabled()) {

      // auth detail should be attached to the packet. Auth details are 16
      // bytes

      if (input_buffer.length < 17) {

        Logger.log(
            new LogEvent(
                LOGID,
                LogEvent.LT_WARNING,
                "TRTrackerServerProcessorUDP: " + "packet received but authorisation missing"));

        return;
      }

      packet_data_length -= 16;

      auth_user_bytes = new byte[8];

      auth_hash = new byte[8];

      System.arraycopy(input_buffer, packet_data_length, auth_user_bytes, 0, 8);

      int user_len = 0;

      while (user_len < 8 && auth_user_bytes[user_len] != 0) {

        user_len++;
      }

      auth_user = new String(auth_user_bytes, 0, user_len);

      System.arraycopy(input_buffer, packet_data_length + 8, auth_hash, 0, 8);
    }

    DataInputStream is =
        new DataInputStream(new ByteArrayInputStream(input_buffer, 0, packet_data_length));

    try {
      String client_ip_address = request_dg.getAddress().getHostAddress();

      PRUDPPacketRequest request = PRUDPPacketRequest.deserialiseRequest(null, is);

      Logger.log(
          new LogEvent(
              LOGID, "TRTrackerServerProcessorUDP: packet received: " + request.getString()));

      PRUDPPacket reply = null;
      TRTrackerServerTorrentImpl torrent = null;

      if (auth_user_bytes != null) {

        // user name is irrelevant as we only have one at the moment

        // <parg_home> so <new_packet> = <old_packet> + <user_padded_to_8_bytes> + <hash>
        // <parg_home> where <hash> = first 8 bytes of sha1(<old_packet> + <user_padded_to_8> +
        // sha1(pass))
        // <XTF> Yes

        byte[] sha1_pw = null;

        if (server.hasExternalAuthorisation()) {

          try {
            URL resource = new URL("udp://" + server.getHost() + ":" + server.getPort() + "/");

            sha1_pw = server.performExternalAuthorisation(resource, auth_user);

          } catch (MalformedURLException e) {

            Debug.printStackTrace(e);
          }

          if (sha1_pw == null) {

            Logger.log(
                new LogEvent(
                    LOGID,
                    LogEvent.LT_ERROR,
                    "TRTrackerServerProcessorUDP: auth fails for user '" + auth_user + "'"));

            reply = new PRUDPPacketReplyError(request.getTransactionId(), "Access Denied");
          }
        } else {

          sha1_pw = server.getPassword();
        }

        // if we haven't already failed then check the PW

        if (reply == null) {

          SHA1Hasher hasher = new SHA1Hasher();

          hasher.update(input_buffer, 0, packet_data_length);
          hasher.update(auth_user_bytes);
          hasher.update(sha1_pw);

          byte[] digest = hasher.getDigest();

          for (int i = 0; i < auth_hash.length; i++) {

            if (auth_hash[i] != digest[i]) {

              Logger.log(
                  new LogEvent(
                      LOGID,
                      LogEvent.LT_ERROR,
                      "TRTrackerServerProcessorUDP: auth fails for user '" + auth_user + "'"));

              reply = new PRUDPPacketReplyError(request.getTransactionId(), "Access Denied");

              break;
            }
          }
        }
      }

      int request_type = TRTrackerServerRequest.RT_UNKNOWN;

      if (reply == null) {

        if (server.isEnabled()) {

          try {
            int type = request.getAction();

            if (type == PRUDPPacketTracker.ACT_REQUEST_CONNECT) {

              reply = handleConnect(client_ip_address, request);

            } else if (type == PRUDPPacketTracker.ACT_REQUEST_ANNOUNCE) {

              Object[] x =
                  handleAnnounceAndScrape(
                      client_ip_address, request, TRTrackerServerRequest.RT_ANNOUNCE);

              if (x == null) {

                throw (new Exception("Connection ID mismatch"));
              }

              reply = (PRUDPPacket) x[0];
              torrent = (TRTrackerServerTorrentImpl) x[1];

              request_type = TRTrackerServerRequest.RT_ANNOUNCE;

            } else if (type == PRUDPPacketTracker.ACT_REQUEST_SCRAPE) {

              Object[] x =
                  handleAnnounceAndScrape(
                      client_ip_address, request, TRTrackerServerRequest.RT_SCRAPE);

              if (x == null) {

                throw (new Exception("Connection ID mismatch"));
              }

              reply = (PRUDPPacket) x[0];
              torrent = (TRTrackerServerTorrentImpl) x[1];

              request_type = TRTrackerServerRequest.RT_SCRAPE;

            } else {

              reply = new PRUDPPacketReplyError(request.getTransactionId(), "unsupported action");
            }
          } catch (Throwable e) {

            // e.printStackTrace();

            String error = e.getMessage();

            if (error == null) {

              error = e.toString();
            }

            reply = new PRUDPPacketReplyError(request.getTransactionId(), error);
          }
        } else {

          System.out.println("UDP Tracker: replying 'disabled' to " + client_ip_address);

          reply = new PRUDPPacketReplyError(request.getTransactionId(), "UDP Tracker disabled");
        }
      }

      if (reply != null) {

        InetAddress address = request_dg.getAddress();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        DataOutputStream os = new DataOutputStream(baos);

        reply.serialise(os);

        byte[] output_buffer = baos.toByteArray();

        DatagramPacket reply_packet =
            new DatagramPacket(output_buffer, output_buffer.length, address, request_dg.getPort());

        socket.send(reply_packet);

        server.updateStats(request_type, torrent, input_buffer.length, output_buffer.length);
      }

    } catch (Throwable e) {

      Logger.log(new LogEvent(LOGID, "TRTrackerServerProcessorUDP: processing fails", e));
    } finally {

      try {
        is.close();

      } catch (Throwable e) {

      }
    }
  }
  /**
   * Construct the default version check message.
   *
   * @return message to send
   */
  public static Map constructVersionCheckMessage(String reason) {

    // only send if anonymous-check flag is not set

    boolean send_info = COConfigurationManager.getBooleanParameter("Send Version Info");

    Map message = new HashMap();

    // always send
    message.put("appid", SystemProperties.getApplicationIdentifier());
    message.put("appname", SystemProperties.getApplicationName());
    message.put("version", Constants.AZUREUS_VERSION);

    String sub_ver = Constants.AZUREUS_SUBVER;

    if (sub_ver.length() > 0) {
      message.put("subver", sub_ver);
    }

    if (COConfigurationManager.getBooleanParameter("Beta Programme Enabled")) {

      message.put("beta_prog", "true");
    }

    message.put("ui", COConfigurationManager.getStringParameter("ui", "unknown"));
    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

    boolean using_phe =
        COConfigurationManager.getBooleanParameter("network.transport.encrypted.require");
    message.put("using_phe", using_phe ? new Long(1) : new Long(0));

    // 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);

      Integer swt_version =
          (Integer) c.getMethod("getVersion", new Class[] {}).invoke(null, new Object[] {});
      message.put("swt_version", new Long(swt_version.longValue()));

      if (send_info) {
        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();
    }

    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);

    String id = COConfigurationManager.getStringParameter("ID", null);

    if (id != null && send_info) {
      message.put("id", id);

      try {
        byte[] id2 = CryptoManagerFactory.getSingleton().getSecureID();

        message.put("id2", id2);

      } catch (Throwable e) {
      }

      if (last_send_time != -1 && last_send_time < current_send_time) {
        // time 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();

        // removed due to complaints about anonymous stats collection
        // 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());
      }

      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);
      }

      // 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);

      // We may want to reply differently if the user is in Beginner mode vs Advanced
      message.put("user_mode", COConfigurationManager.getIntParameter("User Mode", -1));

      Set<String> features = UtilitiesImpl.getFeaturesInstalled();

      if (features.size() > 0) {

        String str = "";

        for (String f : features) {
          str += (str.length() == 0 ? "" : ",") + f;
        }

        message.put("vzfeatures", str);
      }

      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);
      }
    }

    return message;
  }