Example #1
0
  /**
   * Create a UPnP candidate.
   *
   * @param socket local socket
   * @param externalIP external IP address
   * @param port local port
   * @param component parent component
   * @param device the UPnP gateway device
   * @return a new <tt>UPNPCandidate</tt> instance which represents the specified
   *     <tt>TransportAddress</tt>
   * @throws Exception if something goes wrong during candidate creation
   */
  private List<LocalCandidate> createUPNPCandidate(
      IceSocketWrapper socket,
      String externalIP,
      int port,
      Component component,
      GatewayDevice device)
      throws Exception {
    List<LocalCandidate> ret = new ArrayList<>();
    TransportAddress addr = new TransportAddress(externalIP, port, Transport.UDP);

    HostCandidate base = new HostCandidate(socket, component);

    UPNPCandidate candidate = new UPNPCandidate(addr, base, component, device);
    IceSocketWrapper stunSocket = candidate.getStunSocket(null);
    candidate.getStunStack().addSocket(stunSocket);
    component.getComponentSocket().add(candidate.getCandidateIceSocketWrapper());

    ret.add(candidate);
    ret.add(base);

    return ret;
  }
Example #2
0
  /**
   * Gathers UPnP candidates for all host <tt>Candidate</tt>s that are already present in the
   * specified <tt>component</tt>. This method relies on the specified <tt>component</tt> to already
   * contain all its host candidates so that it would resolve them.
   *
   * @param component the {@link Component} that we'd like to gather candidate UPnP
   *     <tt>Candidate</tt>s for
   * @return the <tt>LocalCandidate</tt>s gathered by this <tt>CandidateHarvester</tt>
   */
  public synchronized Collection<LocalCandidate> harvest(Component component) {
    Collection<LocalCandidate> candidates = new HashSet<>();
    int retries = 0;

    logger.fine("Begin UPnP harvesting");
    try {
      if (device == null) {
        // do it only once
        if (finishThreads == 0) {
          try {
            UPNPThread wanIPThread = new UPNPThread(stIP);
            UPNPThread wanPPPThread = new UPNPThread(stPPP);

            wanIPThread.start();
            wanPPPThread.start();

            synchronized (rootSync) {
              while (finishThreads != 2) {
                rootSync.wait();
              }
            }

            if (wanIPThread.getDevice() != null) {
              device = wanIPThread.getDevice();
            } else if (wanPPPThread.getDevice() != null) {
              device = wanPPPThread.getDevice();
            }

          } catch (Throwable e) {
            logger.info("UPnP discovery failed: " + e);
          }
        }

        if (device == null) return candidates;
      }

      InetAddress localAddress = device.getLocalAddress();
      String externalIPAddress = device.getExternalIPAddress();
      PortMappingEntry portMapping = new PortMappingEntry();

      IceSocketWrapper socket =
          new IceUdpSocketWrapper(new MultiplexingDatagramSocket(0, localAddress));
      int port = socket.getLocalPort();
      int externalPort = socket.getLocalPort();

      while (retries < MAX_RETRIES) {
        if (!device.getSpecificPortMappingEntry(port, "UDP", portMapping)) {
          if (device.addPortMapping(
              externalPort, port, localAddress.getHostAddress(), "UDP", "ice4j.org: " + port)) {
            List<LocalCandidate> cands =
                createUPNPCandidate(socket, externalIPAddress, externalPort, component, device);

            logger.info("Add UPnP port mapping: " + externalIPAddress + " " + externalPort);

            // we have to add the UPNPCandidate and also the base.
            // if we don't add the base, we won't be able to add
            // peer reflexive candidate if someone contact us on the
            // UPNPCandidate
            for (LocalCandidate cand : cands) {
              // try to add the candidate to the component and then
              // only add it to the harvest not redundant
              if (component.addLocalCandidate(cand)) {
                candidates.add(cand);
              }
            }

            break;
          } else {
            port++;
          }
        } else {
          port++;
        }
        retries++;
      }
    } catch (Throwable e) {
      logger.info("Exception while gathering UPnP candidates: " + e);
    }

    return candidates;
  }
Example #3
0
  /**
   * Gathers Jingle Nodes candidates for all host <tt>Candidate</tt>s that are already present in
   * the specified <tt>component</tt>. This method relies on the specified <tt>component</tt> to
   * already contain all its host candidates so that it would resolve them.
   *
   * @param component the {@link Component} that we'd like to gather candidate Jingle Nodes
   *     <tt>Candidate</tt>s for
   * @return the <tt>LocalCandidate</tt>s gathered by this <tt>CandidateHarvester</tt>
   */
  @Override
  public synchronized Collection<LocalCandidate> harvest(Component component) {
    logger.info("harvest Jingle Nodes");

    Collection<LocalCandidate> candidates = new HashSet<LocalCandidate>();
    String ip = null;
    int port = -1;

    /* if we have already a candidate (RTCP) allocated, get it */
    if (localAddressSecond != null && relayedAddressSecond != null) {
      LocalCandidate candidate =
          createJingleNodesCandidate(relayedAddressSecond, component, localAddressSecond);

      // try to add the candidate to the component and then only add it to
      // the harvest not redundant (not sure how it could be red. but ...)
      if (component.addLocalCandidate(candidate)) {
        candidates.add(candidate);
      }

      localAddressSecond = null;
      relayedAddressSecond = null;
      return candidates;
    }

    XMPPConnection conn = serviceNode.getConnection();
    JingleChannelIQ ciq = null;

    if (serviceNode != null) {
      final TrackerEntry preferred = serviceNode.getPreferedRelay();

      if (preferred != null) {
        ciq = SmackServiceNode.getChannel(conn, preferred.getJid());
      }
    }

    if (ciq != null) {
      ip = ciq.getHost();
      port = ciq.getRemoteport();

      if (logger.isInfoEnabled()) {
        logger.info(
            "JN relay: " + ip + " remote port:" + port + " local port: " + ciq.getLocalport());
      }

      if (ip == null || ciq.getRemoteport() == 0) {
        logger.warn("JN relay ignored because ip was null or port 0");
        return candidates;
      }

      // Drop the scope or interface name if the relay sends it
      // along in its IPv6 address. The scope/ifname is only valid on the
      // host that owns the IP and we don't need it here.
      int scopeIndex = ip.indexOf('%');
      if (scopeIndex > 0) {
        logger.warn("Dropping scope from assumed IPv6 address " + ip);
        ip = ip.substring(0, scopeIndex);
      }

      /* RTP */
      TransportAddress relayedAddress = new TransportAddress(ip, port, Transport.UDP);
      TransportAddress localAddress = new TransportAddress(ip, ciq.getLocalport(), Transport.UDP);

      LocalCandidate local = createJingleNodesCandidate(relayedAddress, component, localAddress);

      /* RTCP */
      relayedAddressSecond = new TransportAddress(ip, port + 1, Transport.UDP);
      localAddressSecond = new TransportAddress(ip, ciq.getLocalport() + 1, Transport.UDP);

      // try to add the candidate to the component and then only add it to
      // the harvest not redundant (not sure how it could be red. but ...)
      if (component.addLocalCandidate(local)) {
        candidates.add(local);
      }
    }

    return candidates;
  }