private void updateStats(int record_type) {
    long current_d_received = gm_stats.getTotalDataBytesReceived();
    long current_p_received = gm_stats.getTotalProtocolBytesReceived();

    long current_d_sent = gm_stats.getTotalDataBytesSent();
    long current_p_sent = gm_stats.getTotalProtocolBytesSent();

    long current_dht_sent = 0;
    long current_dht_received = 0;

    DHT[] dhts = getDHTs();

    if (dhts != null) {

      for (DHT dht : dhts) {

        DHTTransportStats dht_stats = dht.getTransport().getStats();

        current_dht_sent += dht_stats.getBytesSent();
        current_dht_received += dht_stats.getBytesReceived();
      }
    }

    write(
        record_type,
        new long[] {
          (current_p_sent - ss_p_sent),
          (current_d_sent - ss_d_sent),
          (current_p_received - ss_p_received),
          (current_d_received - ss_d_received),
          (current_dht_sent - ss_dht_sent),
          (current_dht_received - ss_dht_received)
        });
  }
Beispiel #2
0
  public DHTNATPuncherImpl(DHTNATPuncherAdapter _adapter, DHT _dht) {
    adapter = _adapter;
    dht = _dht;

    logger = dht.getLogger();

    plugin_interface = dht.getLogger().getPluginInterface();

    formatters = plugin_interface.getUtilities().getFormatters();
    pub_mon = plugin_interface.getUtilities().getMonitor();
    server_mon = plugin_interface.getUtilities().getMonitor();
    punch_mon = plugin_interface.getUtilities().getMonitor();

    timer = plugin_interface.getUtilities().createTimer("DHTNATPuncher:refresher", true);
  }
  public DHTSpeedTesterImpl(DHT _dht) {
    dht = _dht;

    plugin_interface = dht.getLogger().getPluginInterface();

    UTTimer timer = plugin_interface.getUtilities().createTimer("DHTSpeedTester:finder", true);

    timer.addPeriodicEvent(
        5000,
        new UTTimerEventPerformer() {
          public void perform(UTTimerEvent event) {
            findContacts();
          }
        });

    timer.addPeriodicEvent(
        1000,
        new UTTimerEventPerformer() {
          int tick_count;

          public void perform(UTTimerEvent event) {
            try {
              pingContacts(tick_count);

            } finally {

              tick_count++;
            }
          }
        });
  }
Beispiel #4
0
  protected boolean sendTunnelMessage(DHTTransportContact target, byte[] data) {
    try {
      dht.getTransport()
          .writeTransfer(
              new DHTTransportProgressListener() {
                public void reportSize(long size) {}

                public void reportActivity(String str) {}

                public void reportCompleteness(int percent) {}
              },
              target,
              transfer_handler_key,
              new byte[0],
              data,
              TUNNEL_TIMEOUT);

      return (true);

    } catch (DHTTransportException e) {

      // log(e); timeout most likely

      return (false);
    }
  }
Beispiel #5
0
  public void setRendezvous(DHTTransportContact target, DHTTransportContact rendezvous) {
    explicit_rendezvous_map.put(target.getAddress(), rendezvous);

    if (target.getAddress().equals(dht.getTransport().getLocalContact().getAddress())) {

      publish(true);
    }
  }
  protected void findContacts() {
    DHTTransportContact[] reachables = dht.getTransport().getReachableContacts();

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

      DHTTransportContact contact = reachables[i];

      byte[] address = contact.getAddress().getAddress().getAddress();

      if (tried_bloom == null || tried_bloom.getEntryCount() > 500) {

        tried_bloom = BloomFilterFactory.createAddOnly(4096);
      }

      if (!tried_bloom.contains(address)) {

        tried_bloom.add(address);

        synchronized (pending_contacts) {
          potentialPing ping =
              new potentialPing(
                  contact,
                  DHTNetworkPositionManager.estimateRTT(
                      contact.getNetworkPositions(),
                      dht.getTransport().getLocalContact().getNetworkPositions()));

          pending_contacts.add(0, ping);

          if (pending_contacts.size() > 60) {

            pending_contacts.removeLast();
          }
        }
      }
    }
  }
Beispiel #7
0
  protected DHTTransportUDPContact decodeContact(byte[] bytes) {
    try {
      ByteArrayInputStream bais = new ByteArrayInputStream(bytes);

      DataInputStream dis = new DataInputStream(bais);

      return ((DHTTransportUDPContact) dht.getTransport().importContact(dis));

    } catch (Throwable e) {

      log(e);

      return (null);
    }
  }
Beispiel #8
0
  public Map sendMessage(InetSocketAddress rendezvous, InetSocketAddress target, Map message) {
    try {
      DHTTransportUDP transport = (DHTTransportUDP) dht.getTransport();

      DHTTransportUDPContact rend_contact =
          transport.importContact(rendezvous, transport.getProtocolVersion());
      DHTTransportUDPContact target_contact =
          transport.importContact(target, transport.getProtocolVersion());

      Map result = sendPunch(rend_contact, target_contact, message, true);

      return (result);

    } catch (Throwable e) {

      Debug.printStackTrace(e);

      return (null);
    }
  }
Beispiel #9
0
  protected byte[] sendRequest(DHTTransportContact target, byte[] data, int timeout) {
    try {
      return (dht.getTransport()
          .writeReadTransfer(
              new DHTTransportProgressListener() {
                public void reportSize(long size) {}

                public void reportActivity(String str) {}

                public void reportCompleteness(int percent) {}
              },
              target,
              transfer_handler_key,
              data,
              timeout));

    } catch (DHTTransportException e) {

      // log(e); timeout most likely

      return (null);
    }
  }
Beispiel #10
0
  public Map punch(
      String reason,
      InetSocketAddress[] target,
      DHTTransportContact[] rendezvous_used,
      Map originator_client_data) {
    try {
      DHTTransportUDP transport = (DHTTransportUDP) dht.getTransport();

      DHTTransportUDPContact contact =
          transport.importContact(target[0], transport.getProtocolVersion());

      Map result = punch(reason, contact, rendezvous_used, originator_client_data);

      target[0] = contact.getTransportAddress();

      return (result);

    } catch (Throwable e) {

      Debug.printStackTrace(e);

      return (null);
    }
  }
  private void sessionStart() {
    OverallStatsImpl stats = (OverallStatsImpl) StatsFactory.getStats();

    synchronized (this) {
      if (closing) {

        return;
      }

      boolean enabled = COConfigurationManager.getBooleanParameter("long.term.stats.enable");

      if (active || !enabled) {

        return;
      }

      active = true;

      long[] snap = stats.getLastSnapshot();

      ss_d_received = gm_stats.getTotalDataBytesReceived();
      ss_p_received = gm_stats.getTotalProtocolBytesReceived();

      ss_d_sent = gm_stats.getTotalDataBytesSent();
      ss_p_sent = gm_stats.getTotalProtocolBytesSent();

      ss_dht_sent = 0;
      ss_dht_received = 0;

      if (core.isStarted()) {

        DHT[] dhts = getDHTs();

        if (dhts != null) {

          for (DHT dht : dhts) {

            DHTTransportStats dht_stats = dht.getTransport().getStats();

            ss_dht_sent += dht_stats.getBytesSent();
            ss_dht_received += dht_stats.getBytesReceived();
          }
        }
      }

      st_p_sent = snap[0] + (ss_p_sent - snap[6]);
      st_d_sent = snap[1] + (ss_d_sent - snap[7]);
      st_p_received = snap[2] + (ss_p_received - snap[8]);
      st_d_received = snap[3] + (ss_d_received - snap[9]);
      st_dht_sent = snap[4] + (ss_dht_sent - snap[10]);
      st_dht_received = snap[5] + (ss_dht_received - snap[11]);

      write(
          RT_SESSION_START,
          new long[] {
            st_p_sent, st_d_sent, st_p_received, st_d_received, st_dht_sent, st_dht_received
          });

      if (event == null) { // should always be null but hey ho

        event =
            SimpleTimer.addPeriodicEvent(
                "LongTermStats",
                MIN_IN_MILLIS,
                new TimerEventPerformer() {
                  public void perform(TimerEvent event) {
                    updateStats();
                  }
                });
      }
    }
  }
  private void start() {
    synchronized (this) {
      if (started) {

        return;
      }

      started = true;
    }

    N_3072 =
        fromHex(
            "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08"
                + "8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B"
                + "302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9"
                + "A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6"
                + "49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8"
                + "FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D"
                + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C"
                + "180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718"
                + "3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D"
                + "04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D"
                + "B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226"
                + "1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C"
                + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC"
                + "E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF");

    G_3072 = BigInteger.valueOf(5);

    try {
      PluginInterface dht_pi = core.getPluginManager().getPluginInterfaceByClass(DHTPlugin.class);

      if (dht_pi == null) {

        throw (new Exception("DHT Plugin not found"));
      }

      DHTPlugin dht_plugin = (DHTPlugin) dht_pi.getPlugin();

      if (!dht_plugin.isEnabled()) {

        throw (new Exception("DHT Plugin is disabled"));
      }

      DHT[] dhts = dht_plugin.getDHTs();

      List<DHTNATPuncher> punchers = new ArrayList<DHTNATPuncher>();

      for (DHT dht : dhts) {

        int net = dht.getTransport().getNetwork();

        if (net == DHT.NW_MAIN) {

          DHTNATPuncher primary_puncher = dht.getNATPuncher();

          if (primary_puncher != null) {

            punchers.add(primary_puncher);

            nat_punchers_ipv4.add(primary_puncher);

            for (int i = 1; i <= 2; i++) {

              DHTNATPuncher puncher = primary_puncher.getSecondaryPuncher();

              punchers.add(puncher);

              nat_punchers_ipv4.add(puncher);
            }
          }
        } else if (net == DHT.NW_MAIN_V6) {

          /*
           * no point in this atm as we don't support v6 tunnels

          DHTNATPuncher puncher = dht.getNATPuncher();

          if ( puncher != null ){

          	punchers.add( puncher );

          	nat_punchers_ipv6.add( puncher );

          	puncher = puncher.getSecondaryPuncher();

          	punchers.add( puncher );

          	nat_punchers_ipv6.add( puncher );
          }
          */
        }
      }

      if (punchers.size() == 0) {

        throw (new Exception("No suitable DHT instances available"));
      }

      for (DHTNATPuncher p : punchers) {

        p.forceActive(true);

        p.addListener(
            new DHTNATPuncherListener() {
              public void rendezvousChanged(DHTTransportContact rendezvous) {
                System.out.println("active: " + rendezvous.getString());

                synchronized (PairingManagerTunnelHandler.this) {
                  if (update_event == null) {

                    update_event =
                        SimpleTimer.addEvent(
                            "PMT:defer",
                            SystemTime.getOffsetTime(15 * 1000),
                            new TimerEventPerformer() {
                              public void perform(TimerEvent event) {
                                synchronized (PairingManagerTunnelHandler.this) {
                                  update_event = null;
                                }

                                System.out.println("    updating");

                                manager.updateNeeded();
                              };
                            });
                  }
                }
              }
            });
      }

      core.getNATTraverser()
          .registerHandler(
              new NATTraversalHandler() {
                private Map<Long, Object[]> server_map =
                    new LinkedHashMap<Long, Object[]>(10, 0.75f, true) {
                      protected boolean removeEldestEntry(Map.Entry<Long, Object[]> eldest) {
                        return size() > 10;
                      }
                    };

                public int getType() {
                  return (NATTraverser.TRAVERSE_REASON_PAIR_TUNNEL);
                }

                public String getName() {
                  return ("Pairing Tunnel");
                }

                public Map process(InetSocketAddress originator, Map data) {
                  if (SRP_VERIFIER == null || !active) {

                    return (null);
                  }

                  boolean good_request = false;

                  try {

                    Map result = new HashMap();

                    Long session = (Long) data.get("sid");

                    if (session == null) {

                      return (null);
                    }

                    InetAddress tunnel_originator;

                    try {
                      tunnel_originator = InetAddress.getByAddress((byte[]) data.get("origin"));

                    } catch (Throwable e) {

                      Debug.out("originator decode failed: " + data);

                      return (null);
                    }

                    System.out.println(
                        "PairManagerTunnelHander: incoming message - session="
                            + session
                            + ", payload="
                            + data
                            + " from "
                            + tunnel_originator
                            + " via "
                            + originator);

                    SRP6Server server;
                    BigInteger B;

                    synchronized (server_map) {
                      Object[] entry = server_map.get(session);

                      if (entry == null) {

                        long diff = SystemTime.getMonotonousTime() - last_server_create_time;

                        if (diff < 5000) {

                          try {
                            long sleep = 5000 - diff;

                            System.out.println("Sleeping for " + sleep + " before starting srp");

                            Thread.sleep(sleep);

                          } catch (Throwable e) {
                          }
                        }

                        server = new SRP6Server();

                        server.init(
                            N_3072,
                            G_3072,
                            SRP_VERIFIER,
                            new SHA256Digest(),
                            RandomUtils.SECURE_RANDOM);

                        B = server.generateServerCredentials();

                        server_map.put(session, new Object[] {server, B});

                        last_server_create_time = SystemTime.getMonotonousTime();

                        total_servers++;

                      } else {

                        server = (SRP6Server) entry[0];
                        B = (BigInteger) entry[1];
                      }
                    }

                    Long op = (Long) data.get("op");

                    if (op == 1) {

                      result.put("op", 2);

                      result.put("s", SRP_SALT);

                      result.put("b", B.toByteArray());

                      good_request = true;

                      if (data.containsKey("test")) {

                        manager.recordRequest(
                            "SRP Test", originator.getAddress().getHostAddress(), true);
                      }
                    } else if (op == 3) {

                      boolean log_error = true;

                      try {
                        long diff = SystemTime.getMonotonousTime() - last_server_agree_time;

                        if (diff < 5000) {

                          try {
                            long sleep = 5000 - diff;

                            System.out.println("Sleeping for " + sleep + " before completing srp");

                            Thread.sleep(sleep);

                          } catch (Throwable e) {
                          }
                        }

                        BigInteger A = new BigInteger((byte[]) data.get("a"));

                        BigInteger serverS = server.calculateSecret(A);

                        byte[] shared_secret = serverS.toByteArray();

                        Cipher decipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

                        byte[] key = new byte[16];

                        System.arraycopy(shared_secret, 0, key, 0, 16);

                        SecretKeySpec secret = new SecretKeySpec(key, "AES");

                        decipher.init(
                            Cipher.DECRYPT_MODE,
                            secret,
                            new IvParameterSpec((byte[]) data.get("enc_iv")));

                        byte[] dec = decipher.doFinal((byte[]) data.get("enc_data"));

                        String json_str = new String(dec, "UTF-8");

                        if (!json_str.startsWith("{")) {

                          log_error = false;

                          throw (new Exception("decode failed"));
                        }

                        JSONObject dec_json = (JSONObject) JSONUtils.decodeJSON(json_str);

                        String tunnel_url = (String) dec_json.get("url");

                        String service_id = new String((byte[]) data.get("service"), "UTF-8");

                        String endpoint_url = (String) dec_json.get("endpoint");

                        boolean ok =
                            createTunnel(
                                tunnel_originator,
                                session,
                                service_id,
                                secret,
                                tunnel_url,
                                endpoint_url);

                        result.put("op", 4);
                        result.put("status", ok ? "ok" : "failed");

                        good_request = true;

                      } catch (Throwable e) {

                        result.put("op", 4);
                        result.put("status", "failed");

                        // filter usual errors on bad agreement

                        if (e instanceof BadPaddingException
                            || e instanceof IllegalBlockSizeException) {

                          log_error = false;
                        }

                        if (log_error) {

                          e.printStackTrace();
                        }
                      } finally {

                        last_server_agree_time = SystemTime.getMonotonousTime();
                      }
                    }

                    return (result);

                  } finally {

                    if (!good_request) {

                      manager.recordRequest("SRP", originator.getAddress().getHostAddress(), false);
                    }
                  }
                }
              });

      SimpleTimer.addPeriodicEvent(
          "pm:tunnel:stats",
          30 * 1000,
          new TimerEventPerformer() {
            public void perform(TimerEvent event) {
              synchronized (tunnels) {
                if (tunnels.size() > 0) {

                  System.out.println("PairTunnels: " + tunnels.size());

                  for (PairManagerTunnel t : tunnels.values()) {

                    System.out.println("\t" + t.getString());
                  }
                }
              }
            }
          });

    } catch (Throwable e) {

      Debug.out(e);

      init_fail = Debug.getNestedExceptionMessage(e);

      manager.updateSRPState();
    }
  }
Beispiel #13
0
  protected void publishSupport() {
    DHTTransport transport = dht.getTransport();

    if (TESTING || !transport.isReachable()) {

      DHTTransportContact local_contact = transport.getLocalContact();

      // see if the rendezvous has failed and therefore we are required to find a new one

      boolean force =
          rendezvous_target != null
              && failed_rendezvous.containsKey(rendezvous_target.getAddress());

      if (rendezvous_local_contact != null && !force) {

        if (local_contact.getAddress().equals(rendezvous_local_contact.getAddress())) {

          // already running for the current local contact

          return;
        }
      }

      DHTTransportContact explicit =
          (DHTTransportContact) explicit_rendezvous_map.get(local_contact.getAddress());

      if (explicit != null) {

        try {
          pub_mon.enter();

          rendezvous_local_contact = local_contact;
          rendezvous_target = explicit;

          runRendezvous();

        } finally {

          pub_mon.exit();
        }
      } else {

        final DHTTransportContact[] new_rendezvous_target = {null};

        DHTTransportContact[] reachables = dht.getTransport().getReachableContacts();

        int reachables_tried = 0;
        int reachables_skipped = 0;

        final Semaphore sem = plugin_interface.getUtilities().getSemaphore();

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

          DHTTransportContact contact = reachables[i];

          try {
            pub_mon.enter();

            // see if we've found a good one yet

            if (new_rendezvous_target[0] != null) {

              break;
            }

            // skip any known bad ones

            if (failed_rendezvous.containsKey(contact.getAddress())) {

              reachables_skipped++;

              sem.release();

              continue;
            }
          } finally {

            pub_mon.exit();
          }

          if (i > 0) {

            try {
              Thread.sleep(1000);

            } catch (Throwable e) {

            }
          }

          reachables_tried++;

          contact.sendPing(
              new DHTTransportReplyHandlerAdapter() {
                public void pingReply(DHTTransportContact ok_contact) {
                  trace("Punch:" + ok_contact.getString() + " OK");

                  try {
                    pub_mon.enter();

                    if (new_rendezvous_target[0] == null) {

                      new_rendezvous_target[0] = ok_contact;
                    }
                  } finally {

                    pub_mon.exit();

                    sem.release();
                  }
                }

                public void failed(DHTTransportContact failed_contact, Throwable e) {
                  try {
                    trace("Punch:" + failed_contact.getString() + " Failed");

                  } finally {

                    sem.release();
                  }
                }
              });
        }

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

          sem.reserve();

          try {
            pub_mon.enter();

            if (new_rendezvous_target[0] != null) {

              rendezvous_target = new_rendezvous_target[0];
              rendezvous_local_contact = local_contact;

              log(
                  "Rendezvous found: "
                      + rendezvous_local_contact.getString()
                      + " -> "
                      + rendezvous_target.getString());

              runRendezvous();

              break;
            }
          } finally {

            pub_mon.exit();
          }
        }

        if (new_rendezvous_target[0] == null) {

          log(
              "No rendezvous found: candidates="
                  + reachables.length
                  + ",tried="
                  + reachables_tried
                  + ",skipped="
                  + reachables_skipped);

          try {
            pub_mon.enter();

            rendezvous_local_contact = null;
            rendezvous_target = null;

          } finally {

            pub_mon.exit();
          }
        }
      }
    } else {

      try {
        pub_mon.enter();

        rendezvous_local_contact = null;
        rendezvous_target = null;

      } finally {

        pub_mon.exit();
      }
    }
  }
Beispiel #14
0
  protected DHTTransportContact getRendezvous(String reason, DHTTransportContact target) {
    DHTTransportContact explicit =
        (DHTTransportContact) explicit_rendezvous_map.get(target.getAddress());

    if (explicit != null) {

      return (explicit);
    }

    byte[] key = getPublishKey(target);

    final DHTTransportValue[] result_value = {null};

    final Semaphore sem = plugin_interface.getUtilities().getSemaphore();

    dht.get(
        key,
        reason + ": lookup for '" + target.getString() + "'",
        (byte) 0,
        1,
        RENDEZVOUS_LOOKUP_TIMEOUT,
        false,
        true,
        new DHTOperationAdapter() {
          public void read(DHTTransportContact contact, DHTTransportValue value) {
            result_value[0] = value;

            sem.release();
          }

          public void complete(boolean timeout) {
            sem.release();
          }
        });

    sem.reserve();

    DHTTransportContact result = null;

    if (result_value[0] != null) {

      byte[] bytes = result_value[0].getValue();

      try {
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);

        DataInputStream dis = new DataInputStream(bais);

        byte version = dis.readByte();

        if (version != 0) {

          throw (new Exception("Unsupported rendezvous version '" + version + "'"));
        }

        result = dht.getTransport().importContact(dis);

      } catch (Throwable e) {

        log(e);
      }
    }

    log(
        "Lookup of rendezvous for "
            + target.getString()
            + " -> "
            + (result == null ? "None" : result.getString()));

    return (result);
  }
Beispiel #15
0
  public void start() {
    if (started) {

      return;
    }

    started = true;

    DHTTransport transport = dht.getTransport();

    transport.addListener(
        new DHTTransportListener() {
          public void localContactChanged(DHTTransportContact local_contact) {
            publish(false);
          }

          public void currentAddress(String address) {}

          public void reachabilityChanged(boolean reacheable) {
            publish(false);
          }
        });

    transport.registerTransferHandler(
        transfer_handler_key,
        new DHTTransportTransferHandler() {
          public String getName() {
            return ("NAT Traversal");
          }

          public byte[] handleRead(DHTTransportContact originator, byte[] key) {
            return (null);
          }

          public byte[] handleWrite(DHTTransportContact originator, byte[] key, byte[] value) {
            return (receiveRequest((DHTTransportUDPContact) originator, value));
          }
        });

    timer.addPeriodicEvent(
        REPUBLISH_TIME_MIN,
        new UTTimerEventPerformer() {
          public void perform(UTTimerEvent event) {
            publish(false);
          }
        });

    timer.addPeriodicEvent(
        RENDEZVOUS_SERVER_TIMEOUT / 2,
        new UTTimerEventPerformer() {
          public void perform(UTTimerEvent event) {
            long now = plugin_interface.getUtilities().getCurrentSystemTime();

            try {
              server_mon.enter();

              Iterator it = rendezvous_bindings.values().iterator();

              while (it.hasNext()) {

                Object[] entry = (Object[]) it.next();

                long time = ((Long) entry[1]).longValue();

                boolean removed = false;

                if (time > now) {

                  // clock change, easiest approach is to remove it

                  it.remove();

                  removed = true;

                } else if (now - time > RENDEZVOUS_SERVER_TIMEOUT) {

                  // timeout

                  it.remove();

                  removed = true;
                }

                if (removed) {

                  log(
                      "Rendezvous "
                          + ((DHTTransportContact) entry[0]).getString()
                          + " removed due to inactivity");
                }
              }
            } finally {

              server_mon.exit();
            }
          }
        });

    publish(false);
  }