예제 #1
0
  /**
   * Sends a specific <tt>Request</tt> to the STUN server associated with this
   * <tt>StunCandidateHarvest</tt>.
   *
   * @param request the <tt>Request</tt> to send to the STUN server associated with this
   *     <tt>StunCandidateHarvest</tt>
   * @param firstRequest <tt>true</tt> if the specified <tt>request</tt> should be sent as the first
   *     request in the terms of STUN; otherwise, <tt>false</tt>
   * @return the <tt>TransactionID</tt> of the STUN client transaction through which the specified
   *     <tt>Request</tt> has been sent to the STUN server associated with this
   *     <tt>StunCandidateHarvest</tt>
   * @param transactionID the <tt>TransactionID</tt> of <tt>request</tt> because <tt>request</tt>
   *     only has it as a <tt>byte</tt> array and <tt>TransactionID</tt> is required for the
   *     <tt>applicationData</tt> property value
   * @throws StunException if anything goes wrong while sending the specified <tt>Request</tt> to
   *     the STUN server associated with this <tt>StunCandidateHarvest</tt>
   */
  protected TransactionID sendRequest(
      Request request, boolean firstRequest, TransactionID transactionID) throws StunException {
    if (!firstRequest && (longTermCredentialSession != null))
      longTermCredentialSession.addAttributes(request);

    StunStack stunStack = harvester.getStunStack();
    TransportAddress stunServer = harvester.stunServer;
    TransportAddress hostCandidateTransportAddress = hostCandidate.getTransportAddress();

    if (transactionID == null) {
      byte[] transactionIDAsBytes = request.getTransactionID();

      transactionID =
          (transactionIDAsBytes == null)
              ? TransactionID.createNewTransactionID()
              : TransactionID.createTransactionID(harvester.getStunStack(), transactionIDAsBytes);
    }
    synchronized (requests) {
      try {
        transactionID =
            stunStack.sendRequest(
                request, stunServer, hostCandidateTransportAddress, this, transactionID);
      } catch (IllegalArgumentException iaex) {
        if (logger.isLoggable(Level.INFO)) {
          logger.log(
              Level.INFO,
              "Failed to send "
                  + request
                  + " through "
                  + hostCandidateTransportAddress
                  + " to "
                  + stunServer,
              iaex);
        }
        throw new StunException(StunException.ILLEGAL_ARGUMENT, iaex.getMessage(), iaex);
      } catch (IOException ioex) {
        if (logger.isLoggable(Level.INFO)) {
          logger.log(
              Level.INFO,
              "Failed to send "
                  + request
                  + " through "
                  + hostCandidateTransportAddress
                  + " to "
                  + stunServer,
              ioex);
        }
        throw new StunException(StunException.NETWORK_ERROR, ioex.getMessage(), ioex);
      }

      requests.put(transactionID, request);
    }
    return transactionID;
  }
 private void permit(InetSocketAddress address) {
   logger.info("Permitting sends from {}", address);
   Request createPermissionRequest =
       MessageFactory.createCreatePermissionRequest(
           new TransportAddress(address, Transport.UDP),
           TransactionID.createNewTransactionID().getBytes());
   sendBlockingStunRequest(createPermissionRequest);
   logger.debug("Permitted sends from {}", address);
 }
  private void bind(TransportAddress address, int channelNumber) {
    if (peerAddressToChannel.containsKey(address)) {
      return;
    }

    logger.info("Binding '{}' to channel '{}'", address, channelNumber);
    Response response =
        sendBlockingStunRequest(
            MessageFactory.createChannelBindRequest(
                (char) channelNumber, address, TransactionID.createNewTransactionID().getBytes()));
    if (response.isSuccessResponse()) {
      logger.debug("Bound '{}' to channel '{}'", address, channelNumber);

      peerAddressToChannel.put(address, (char) channelNumber);
      channelToPeerAddress.put((char) channelNumber, address);
    } else {
      logger.warn("Binding for '{}' to channel '{}' failed", address, channelNumber);
    }
  }
예제 #4
0
  /**
   * Notifies this <tt>StunCandidateHarvest</tt> that a specific STUN <tt>Request</tt> has been
   * challenged for a long-term credential (as the short-term credential mechanism does not utilize
   * challenging) in a specific <tt>realm</tt> and with a specific <tt>nonce</tt>.
   *
   * @param realm the realm in which the specified STUN <tt>Request</tt> has been challenged for a
   *     long-term credential
   * @param nonce the nonce with which the specified STUN <tt>Request</tt> has been challenged for a
   *     long-term credential
   * @param request the STUN <tt>Request</tt> which has been challenged for a long-term credential
   * @param requestTransactionID the <tt>TransactionID</tt> of <tt>request</tt> because
   *     <tt>request</tt> only has it as a <tt>byte</tt> array and <tt>TransactionID</tt> is
   *     required for the <tt>applicationData</tt> property value
   * @return <tt>true</tt> if the challenge has been processed and this
   *     <tt>StunCandidateHarvest</tt> is to continue processing STUN <tt>Response</tt>s; otherwise,
   *     <tt>false</tt>
   * @throws StunException if anything goes wrong while processing the challenge
   */
  private boolean processChallenge(
      byte[] realm, byte[] nonce, Request request, TransactionID requestTransactionID)
      throws StunException {
    UsernameAttribute usernameAttribute =
        (UsernameAttribute) request.getAttribute(Attribute.USERNAME);

    if (usernameAttribute == null) {
      if (longTermCredentialSession == null) {
        LongTermCredential longTermCredential = harvester.createLongTermCredential(this, realm);

        if (longTermCredential == null) {
          // The long-term credential mechanism is not being utilized.
          return false;
        } else {
          longTermCredentialSession = new LongTermCredentialSession(longTermCredential, realm);
          harvester
              .getStunStack()
              .getCredentialsManager()
              .registerAuthority(longTermCredentialSession);
        }
      } else {
        /*
         * If we're going to use the long-term credential to retry the
         * request, the long-term credential should be for the request
         * in terms of realm.
         */
        if (!longTermCredentialSession.realmEquals(realm)) return false;
      }
    } else {
      /*
       * If we sent a USERNAME in our request, then we had the long-term
       * credential at the time we sent the request in question.
       */
      if (longTermCredentialSession == null) return false;
      else {
        /*
         * If we're going to use the long-term credential to retry the
         * request, the long-term credential should be for the request
         * in terms of username.
         */
        if (!longTermCredentialSession.usernameEquals(usernameAttribute.getUsername()))
          return false;
        else {
          // And it terms of realm, of course.
          if (!longTermCredentialSession.realmEquals(realm)) return false;
        }
      }
    }

    /*
     * The nonce is either becoming known for the first time or being
     * updated after the old one has gone stale.
     */
    longTermCredentialSession.setNonce(nonce);

    Request retryRequest = createRequestToRetry(request);
    TransactionID retryRequestTransactionID = null;

    if (retryRequest != null) {
      if (requestTransactionID != null) {
        Object applicationData = requestTransactionID.getApplicationData();

        if (applicationData != null) {
          byte[] retryRequestTransactionIDAsBytes = retryRequest.getTransactionID();

          retryRequestTransactionID =
              (retryRequestTransactionIDAsBytes == null)
                  ? TransactionID.createNewTransactionID()
                  : TransactionID.createTransactionID(
                      harvester.getStunStack(), retryRequestTransactionIDAsBytes);
          retryRequestTransactionID.setApplicationData(applicationData);
        }
      }
      retryRequestTransactionID = sendRequest(retryRequest, false, retryRequestTransactionID);
    }
    return (retryRequestTransactionID != null);
  }