public void destroy() {
    try {
      server_mon.enter();

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

      while (it.hasNext()) {

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

        final DHTTransportUDPContact contact = (DHTTransportUDPContact) entry[0];

        new AEThread2("DHTNATPuncher:destroy", true) {
          public void run() {
            sendClose(contact);
          }
        }.start();
      }
    } catch (Throwable e) {

      log(e);

    } finally {

      server_mon.exit();
    }
  }
Exemple #2
0
 ImmutableMap<Service, Long> startupTimes() {
   List<Entry<Service, Long>> loadTimes;
   monitor.enter();
   try {
     loadTimes = Lists.newArrayListWithCapacity(startupTimers.size());
     // N.B. There will only be an entry in the map if the service has started
     for (Entry<Service, Stopwatch> entry : startupTimers.entrySet()) {
       Service service = entry.getKey();
       Stopwatch stopWatch = entry.getValue();
       if (!stopWatch.isRunning() && !(service instanceof NoOpService)) {
         loadTimes.add(Maps.immutableEntry(service, stopWatch.elapsed(MILLISECONDS)));
       }
     }
   } finally {
     monitor.leave();
   }
   Collections.sort(
       loadTimes,
       Ordering.<Long>natural()
           .onResultOf(
               new Function<Entry<Service, Long>, Long>() {
                 @Override
                 public Long apply(Map.Entry<Service, Long> input) {
                   return input.getValue();
                 }
               }));
   ImmutableMap.Builder<Service, Long> builder = ImmutableMap.builder();
   for (Entry<Service, Long> entry : loadTimes) {
     builder.put(entry);
   }
   return builder.build();
 }
  protected void receiveTunnelInbound(DHTTransportUDPContact originator, Map data) {
    log("Received tunnel inbound message from " + originator.getString());

    try {
      punch_mon.enter();

      for (int i = 0; i < oustanding_punches.size(); i++) {

        Object[] wait_data = (Object[]) oustanding_punches.get(i);

        DHTTransportContact wait_contact = (DHTTransportContact) wait_data[0];

        if (originator.getAddress().getAddress().equals(wait_contact.getAddress().getAddress())) {

          wait_data[2] = new Integer(originator.getTransportAddress().getPort());

          ((AESemaphore) wait_data[1]).release();
        }
      }

    } finally {

      punch_mon.exit();
    }
  }
Exemple #4
0
    /**
     * Updates the state with the given service transition.
     *
     * <p>This method performs the main logic of ServiceManager in the following steps.
     *
     * <ol>
     *   <li>Update the {@link #servicesByState()}
     *   <li>Update the {@link #startupTimers}
     *   <li>Based on the new state queue listeners to run
     *   <li>Run the listeners (outside of the lock)
     * </ol>
     */
    void transitionService(final Service service, State from, State to) {
      checkNotNull(service);
      checkArgument(from != to);
      monitor.enter();
      try {
        transitioned = true;
        if (!ready) {
          return;
        }
        // Update state.
        checkState(
            servicesByState.remove(from, service),
            "Service %s not at the expected location in the state map %s",
            service,
            from);
        checkState(
            servicesByState.put(to, service),
            "Service %s in the state map unexpectedly at %s",
            service,
            to);
        // Update the timer
        Stopwatch stopwatch = startupTimers.get(service);
        if (stopwatch == null) {
          // This means the service was started by some means other than ServiceManager.startAsync
          stopwatch = Stopwatch.createStarted();
          startupTimers.put(service, stopwatch);
        }
        if (to.compareTo(RUNNING) >= 0 && stopwatch.isRunning()) {
          // N.B. if we miss the STARTING event then we may never record a startup time.
          stopwatch.stop();
          if (!(service instanceof NoOpService)) {
            logger.log(Level.FINE, "Started {0} in {1}.", new Object[] {service, stopwatch});
          }
        }
        // Queue our listeners

        // Did a service fail?
        if (to == FAILED) {
          fireFailedListeners(service);
        }

        if (states.count(RUNNING) == numberOfServices) {
          // This means that the manager is currently healthy. N.B. If other threads call isHealthy
          // they are not guaranteed to get 'true', because any service could fail right now.
          fireHealthyListeners();
        } else if (states.count(TERMINATED) + states.count(FAILED) == numberOfServices) {
          fireStoppedListeners();
        }
      } finally {
        monitor.leave();
        // Run our executors outside of the lock
        executeListeners();
      }
    }
Exemple #5
0
 /**
  * Attempts to start the timer immediately prior to the service being started via {@link
  * Service#startAsync()}.
  */
 void tryStartTiming(Service service) {
   monitor.enter();
   try {
     Stopwatch stopwatch = startupTimers.get(service);
     if (stopwatch == null) {
       startupTimers.put(service, Stopwatch.createStarted());
     }
   } finally {
     monitor.leave();
   }
 }
Exemple #6
0
 void addListener(Listener listener, Executor executor) {
   checkNotNull(listener, "listener");
   checkNotNull(executor, "executor");
   monitor.enter();
   try {
     // no point in adding a listener that will never be called
     if (!stoppedGuard.isSatisfied()) {
       listeners.add(new ListenerCallQueue<Listener>(listener, executor));
     }
   } finally {
     monitor.leave();
   }
 }
Exemple #7
0
 ImmutableMultimap<State, Service> servicesByState() {
   ImmutableSetMultimap.Builder<State, Service> builder = ImmutableSetMultimap.builder();
   monitor.enter();
   try {
     for (Entry<State, Service> entry : servicesByState.entries()) {
       if (!(entry.getValue() instanceof NoOpService)) {
         builder.put(entry.getKey(), entry.getValue());
       }
     }
   } finally {
     monitor.leave();
   }
   return builder.build();
 }
Exemple #8
0
 void awaitStopped(long timeout, TimeUnit unit) throws TimeoutException {
   monitor.enter();
   try {
     if (!monitor.waitForUninterruptibly(stoppedGuard, timeout, unit)) {
       throw new TimeoutException(
           "Timeout waiting for the services to stop. The following "
               + "services have not stopped: "
               + Multimaps.filterKeys(
                   servicesByState, not(in(ImmutableSet.of(TERMINATED, FAILED)))));
     }
   } finally {
     monitor.leave();
   }
 }
Exemple #9
0
 void awaitHealthy(long timeout, TimeUnit unit) throws TimeoutException {
   monitor.enter();
   try {
     if (!monitor.waitForUninterruptibly(awaitHealthGuard, timeout, unit)) {
       throw new TimeoutException(
           "Timeout waiting for the services to become healthy. The "
               + "following services have not started: "
               + Multimaps.filterKeys(servicesByState, in(ImmutableSet.of(NEW, STARTING))));
     }
     checkHealthy();
   } finally {
     monitor.leave();
   }
 }
Exemple #10
0
  protected void rendezvousFailed(DHTTransportContact current_target, boolean tidy) {
    log("Rendezvous " + (tidy ? "closed" : "failed") + ": " + current_target.getString());

    try {
      pub_mon.enter();

      failed_rendezvous.put(current_target.getAddress(), "");

    } finally {

      pub_mon.exit();
    }

    publish(true);
  }
Exemple #11
0
  protected void receiveBind(DHTTransportUDPContact originator, Map request, Map response) {
    trace("received bind request");

    boolean ok = true;
    boolean log = true;

    try {
      server_mon.enter();

      Object[] entry = (Object[]) rendezvous_bindings.get(originator.getAddress().toString());

      if (entry == null) {

        if (rendezvous_bindings.size() == RENDEZVOUS_SERVER_MAX) {

          ok = false;
        }
      } else {

        // already present, no need to log again

        log = false;
      }

      if (ok) {

        long now = plugin_interface.getUtilities().getCurrentSystemTime();

        rendezvous_bindings.put(
            originator.getAddress().toString(), new Object[] {originator, new Long(now)});

        response.put("port", new Long(originator.getAddress().getPort()));
      }
    } finally {

      server_mon.exit();
    }

    if (log) {

      log("Rendezvous request from " + originator.getString() + " " + (ok ? "accepted" : "denied"));
    }

    response.put("ok", new Long(ok ? 1 : 0));
  }
Exemple #12
0
  protected void receivePunch(DHTTransportUDPContact originator, Map request, Map response) {
    trace("received punch request");

    boolean ok = false;

    String target_str = new String((byte[]) request.get("target"));

    Object[] entry;

    try {
      server_mon.enter();

      entry = (Object[]) rendezvous_bindings.get(target_str);

    } finally {

      server_mon.exit();
    }

    if (entry != null) {

      DHTTransportUDPContact target = (DHTTransportUDPContact) entry[0];

      Map target_client_data = sendConnect(target, originator, (Map) request.get("client_data"));

      if (target_client_data != null) {

        response.put("client_data", target_client_data);

        response.put("port", new Long(target.getTransportAddress().getPort()));

        ok = true;
      }
    }

    log(
        "Rendezvous punch request from "
            + originator.getString()
            + " to "
            + target_str
            + " "
            + (ok ? "initiated" : "failed"));

    response.put("ok", new Long(ok ? 1 : 0));
  }
Exemple #13
0
 /**
  * Marks the {@link State} as ready to receive transitions. Returns true if no transitions have
  * been observed yet.
  */
 void markReady() {
   monitor.enter();
   try {
     if (!transitioned) {
       // nothing has transitioned since construction, good.
       ready = true;
     } else {
       // This should be an extremely rare race condition.
       List<Service> servicesInBadStates = Lists.newArrayList();
       for (Service service : servicesByState().values()) {
         if (service.state() != NEW) {
           servicesInBadStates.add(service);
         }
       }
       throw new IllegalArgumentException(
           "Services started transitioning asynchronously before "
               + "the ServiceManager was constructed: "
               + servicesInBadStates);
     }
   } finally {
     monitor.leave();
   }
 }
Exemple #14
0
  protected void runRendezvous() {
    try {
      pub_mon.enter();

      if (!rendezvous_thread_running) {

        rendezvous_thread_running = true;

        plugin_interface
            .getUtilities()
            .createThread(
                "DHTNatPuncher:rendevzous",
                new Runnable() {
                  public void run() {
                    runRendezvousSupport();
                  }
                });
      }
    } finally {

      pub_mon.exit();
    }
  }
Exemple #15
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();
      }
    }
  }
Exemple #16
0
  protected Map sendPunch(
      DHTTransportContact rendezvous,
      final DHTTransportUDPContact target,
      Map originator_client_data,
      boolean no_tunnel) {
    AESemaphore wait_sem = new AESemaphore("DHTNatPuncher::sendPunch");
    Object[] wait_data = new Object[] {target, wait_sem, new Integer(0)};

    try {

      try {
        punch_mon.enter();

        oustanding_punches.add(wait_data);

      } finally {

        punch_mon.exit();
      }

      Map request = new HashMap();

      request.put("type", new Long(RT_PUNCH_REQUEST));

      request.put("target", target.getAddress().toString().getBytes());

      if (originator_client_data != null) {

        if (no_tunnel) {

          originator_client_data.put("_notunnel", new Long(1));
        }

        request.put("client_data", originator_client_data);
      }

      // for a message payload (i.e. no_tunnel) we double the initiator timeout to give
      // more chance for reasonable size messages to get through as they have to go through
      // 2 xfer processes

      Map response =
          sendRequest(rendezvous, request, no_tunnel ? TRANSFER_TIMEOUT * 2 : TRANSFER_TIMEOUT);

      if (response == null) {

        return (null);
      }

      if (((Long) response.get("type")).intValue() == RT_PUNCH_REPLY) {

        int result = ((Long) response.get("ok")).intValue();

        trace(
            "received "
                + (no_tunnel ? "message" : "punch")
                + " reply: "
                + (result == 0 ? "failed" : "ok"));

        if (result == 1) {

          // pick up port changes from the rendezvous

          Long indirect_port = (Long) response.get("port");

          if (indirect_port != null) {

            int transport_port = indirect_port.intValue();

            if (transport_port != 0) {

              InetSocketAddress existing_address = target.getTransportAddress();

              if (transport_port != existing_address.getPort()) {

                target.setTransportAddress(
                    new InetSocketAddress(existing_address.getAddress(), transport_port));
              }
            }
          }

          if (!no_tunnel) {

            // ping the target a few times to try and establish a tunnel

            UTTimerEvent event =
                timer.addPeriodicEvent(
                    3000,
                    new UTTimerEventPerformer() {
                      private int pings = 1;

                      public void perform(UTTimerEvent event) {
                        if (pings > 3) {

                          event.cancel();

                          return;
                        }

                        pings++;

                        if (sendTunnelOutbound(target)) {

                          event.cancel();
                        }
                      }
                    });

            if (sendTunnelOutbound(target)) {

              event.cancel();
            }

            // give the other end a few seconds to kick off some tunnel events to us

            if (wait_sem.reserve(10000)) {

              event.cancel();
            }
          }

          // routers often fiddle with the port when not mapped so we need to grab the right one to
          // use
          // for direct communication

          // first priority goes to direct tunnel messages received

          int transport_port = 0;

          try {
            punch_mon.enter();

            transport_port = ((Integer) wait_data[2]).intValue();

          } finally {

            punch_mon.exit();
          }

          if (transport_port != 0) {

            InetSocketAddress existing_address = target.getTransportAddress();

            if (transport_port != existing_address.getPort()) {

              target.setTransportAddress(
                  new InetSocketAddress(existing_address.getAddress(), transport_port));
            }
          }

          Map target_client_data = (Map) response.get("client_data");

          if (target_client_data == null) {

            target_client_data = new HashMap();
          }

          return (target_client_data);
        }
      }

      return (null);

    } catch (Throwable e) {

      log(e);

      return (null);

    } finally {

      try {
        punch_mon.enter();

        oustanding_punches.remove(wait_data);

      } finally {

        punch_mon.exit();
      }
    }
  }