/**
   * Put the JAIN-SIP stack in a state where it cannot receive any data and frees the network ports
   * used. That is to say remove JAIN-SIP <tt>ListeningPoint</tt>s and <tt>SipProvider</tt>s.
   */
  @SuppressWarnings("unchecked") // jain-sip legacy code
  private void stopListening() {
    try {
      this.secureJainSipProvider.removeSipListener(this);
      this.stack.deleteSipProvider(this.secureJainSipProvider);
      this.secureJainSipProvider = null;
      this.clearJainSipProvider.removeSipListener(this);
      this.stack.deleteSipProvider(this.clearJainSipProvider);
      this.clearJainSipProvider = null;

      Iterator<ListeningPoint> it = this.stack.getListeningPoints();
      Vector<ListeningPoint> lpointsToRemove = new Vector<ListeningPoint>();
      while (it.hasNext()) {
        lpointsToRemove.add(it.next());
      }

      it = lpointsToRemove.iterator();
      while (it.hasNext()) {
        this.stack.deleteListeningPoint(it.next());
      }

      this.stack.stop();
      if (logger.isTraceEnabled()) logger.trace("stopped listening");
    } catch (ObjectInUseException ex) {
      logger.fatal("Failed to stop listening", ex);
    }
  }
 /**
  * Find a matching client SUBSCRIBE to the incoming notify. NOTIFY requests are matched to such
  * SUBSCRIBE requests if they contain the same "Call-ID", a "To" header "tag" parameter which
  * matches the "From" header "tag" parameter of the SUBSCRIBE, and the same "Event" header field.
  * Rules for comparisons of the "Event" headers are described in section 7.2.1. If a matching
  * NOTIFY request contains a "Subscription-State" of "active" or "pending", it creates a new
  * subscription and a new dialog (unless they have already been created by a matching response, as
  * described above).
  *
  * @param notifyMessage
  */
 public SIPClientTransaction findSubscribeTransaction(SIPRequest notifyMessage) {
   synchronized (clientTransactions) {
     Iterator<SIPClientTransaction> it = clientTransactions.iterator();
     String thisToTag = notifyMessage.getTo().getTag();
     if (thisToTag == null) return null;
     Event eventHdr = (Event) notifyMessage.getHeader(EventHeader.NAME);
     if (eventHdr == null) return null;
     while (it.hasNext()) {
       SIPClientTransaction ct = (SIPClientTransaction) it.next();
       // SIPRequest sipRequest = ct.getOriginalRequest();
       String fromTag = ct.from.getTag();
       Event hisEvent = ct.event;
       // Event header is mandatory but some slopply clients
       // dont include it.
       if (hisEvent == null) continue;
       if (ct.method.equals(Request.SUBSCRIBE)
           && fromTag.equalsIgnoreCase(thisToTag)
           && hisEvent != null
           && eventHdr.match(hisEvent)
           && notifyMessage.getCallId().getCallId().equalsIgnoreCase(ct.callId.getCallId()))
         return ct;
     }
   }
   return null;
 }
  /**
   * Creates an invite request using the Tested Implementation and then tests creating a cancel for
   * the same invite request.
   */
  public void testCreateCancel() {
    try {
      Request invite = createTiInviteRequest(null, null, null);
      ClientTransaction tran = null;
      try {
        tran = tiSipProvider.getNewClientTransaction(invite);
      } catch (TransactionUnavailableException exc) {
        throw new TiUnexpectedError(
            "A TransactionUnavailableException was thrown while trying to "
                + "create a new client transaction",
            exc);
      }
      Request cancel = null;
      try {
        cancel = tran.createCancel();
      } catch (SipException ex) {
        ex.printStackTrace();
        fail("Failed to create cancel request!");
      }
      assertEquals(
          "The created request did not have a CANCEL method.", cancel.getMethod(), Request.CANCEL);
      assertEquals(
          "Request-URIs of the original and the cancel request do not match",
          cancel.getRequestURI(),
          invite.getRequestURI());
      assertEquals(
          "Call-IDs of the original and the cancel request do not match",
          cancel.getHeader(CallIdHeader.NAME),
          invite.getHeader(CallIdHeader.NAME));
      assertEquals(
          "ToHeaders of the original and the cancel request do not match",
          cancel.getHeader(ToHeader.NAME),
          invite.getHeader(ToHeader.NAME));
      assertTrue(
          "The CSeqHeader's sequence number of the original and "
              + "the cancel request do not match",
          ((CSeqHeader) cancel.getHeader(CSeqHeader.NAME)).getSequenceNumber()
              == ((CSeqHeader) invite.getHeader(CSeqHeader.NAME)).getSequenceNumber());
      assertEquals(
          "The CSeqHeader's method of the cancel request was not CANCEL",
          ((CSeqHeader) cancel.getHeader(CSeqHeader.NAME)).getMethod(),
          Request.CANCEL);
      assertTrue(
          "There was no ViaHeader in the cancel request",
          cancel.getHeaders(ViaHeader.NAME).hasNext());
      Iterator cancelVias = cancel.getHeaders(ViaHeader.NAME);
      ViaHeader cancelVia = ((ViaHeader) cancelVias.next());
      ViaHeader inviteVia = ((ViaHeader) invite.getHeaders(ViaHeader.NAME).next());
      assertEquals(
          "ViaHeaders of the original and the cancel request do not match!", cancelVia, inviteVia);
      assertFalse("Cancel request had more than one ViaHeader.", cancelVias.hasNext());
    } catch (Throwable exc) {
      exc.printStackTrace();
      fail(exc.getClass().getName() + ": " + exc.getMessage());
    }

    assertTrue(new Exception().getStackTrace()[0].toString(), true);
  }
  /**
   * Returns the JAIN-SIP <tt>ListeningPoint</tt> associated to the given transport string.
   *
   * @param transport a string like "UDP", "TCP" or "TLS".
   * @return the LP associated to the given transport.
   */
  @SuppressWarnings("unchecked") // jain-sip legacy code
  public ListeningPoint getLP(String transport) {
    ListeningPoint lp;
    Iterator<ListeningPoint> it = this.stack.getListeningPoints();

    while (it.hasNext()) {
      lp = it.next();
      // FIXME: JAIN-SIP stack is not consistent with case
      // (reported upstream)
      if (lp.getTransport().toLowerCase().equals(transport.toLowerCase())) return lp;
    }

    throw new IllegalArgumentException("Invalid transport: " + transport);
  }
  /**
   * Handles a new SIP response. It finds a client transaction to handle this message. If none
   * exists, it sends the message directly to the superclass.
   *
   * @param responseReceived Response to handle.
   * @param responseMessageChannel Channel that received message.
   * @return A client transaction.
   */
  protected ServerResponseInterface newSIPServerResponse(
      SIPResponse responseReceived, MessageChannel responseMessageChannel) {
    //	System.out.println("response = " + responseReceived.encode());

    // Iterator through all client transactions
    Iterator<SIPClientTransaction> transactionIterator;
    // Next transaction in the set
    SIPClientTransaction nextTransaction;
    // Transaction to handle this request
    SIPClientTransaction currentTransaction;

    String key = responseReceived.getTransactionId();

    currentTransaction = (SIPClientTransaction) clientTransactionTable.get(key);

    if (currentTransaction == null
        || !currentTransaction.isMessagePartOfTransaction(responseReceived)) {
      // Loop through all server transactions
      synchronized (clientTransactions) {
        transactionIterator = clientTransactions.iterator();
        currentTransaction = null;
        while (transactionIterator.hasNext() && currentTransaction == null) {

          nextTransaction = (SIPClientTransaction) transactionIterator.next();

          // If this transaction should handle this request,
          if (nextTransaction.isMessagePartOfTransaction(responseReceived)) {

            // Mark this transaction as the one to
            // handle this message
            currentTransaction = nextTransaction;
          }
        }
      }

      // If no transaction exists to handle this message,
      if (currentTransaction == null) {

        // Pass the message directly to the TU
        return super.newSIPServerResponse(responseReceived, responseMessageChannel);
      }
    }

    // Set ths transaction's encapsulated response interface
    // from the superclass
    currentTransaction.setResponseInterface(
        super.newSIPServerResponse(responseReceived, currentTransaction));
    return currentTransaction;
  }
 /**
  * Remove the dialog from the dialog table.
  *
  * @param dialog -- dialog to remove.
  */
 public void removeDialog(SIPDialog dialog) {
   synchronized (dialogTable) {
     Iterator<SIPDialog> it = this.dialogTable.values().iterator();
     while (it.hasNext()) {
       SIPDialog d = (SIPDialog) it.next();
       if (d == dialog) {
         if (LogWriter.needsLogging) {
           String dialogId = dialog.getDialogId();
           logWriter.logMessage("Removing Dialog " + dialogId);
         }
         it.remove();
       }
     }
   }
 }
  /**
   * Removes from the specified list of candidates providers connected to a registrar that does not
   * match the IP address that we are receiving a request from.
   *
   * @param candidates the list of providers we've like to filter.
   * @param request the request that we are currently dispatching
   */
  private void filterByAddress(List<ProtocolProviderServiceSipImpl> candidates, Request request) {
    Iterator<ProtocolProviderServiceSipImpl> iterPP = candidates.iterator();
    while (iterPP.hasNext()) {
      ProtocolProviderServiceSipImpl candidate = iterPP.next();

      if (candidate.getRegistrarConnection() == null) {
        // RegistrarLess connections are ok
        continue;
      }

      if (!candidate.getRegistrarConnection().isRegistrarless()
          && !candidate.getRegistrarConnection().isRequestFromSameConnection(request)) {
        iterPP.remove();
      }
    }
  }
  public SIPServerTransaction findPendingTransaction(SIPRequest requestReceived) {
    SIPServerTransaction currentTransaction;
    Iterator<SIPServerTransaction> transactionIterator;
    synchronized (pendingTransactions) {
      transactionIterator = pendingTransactions.iterator();
      currentTransaction = null;
      while (transactionIterator.hasNext() && currentTransaction == null) {

        SIPServerTransaction nextTransaction = (SIPServerTransaction) transactionIterator.next();

        // If this transaction should handle this request,
        if (nextTransaction.isMessagePartOfTransaction(requestReceived)) {
          // Mark this transaction as the one
          // to handle this message
          currentTransaction = nextTransaction;
        }
      }
    }
    return currentTransaction;
  }
  /**
   * Find the transaction corresponding to a given request.
   *
   * @param sipMessage request for which to retrieve the transaction.
   * @param isServer search the server transaction table if true.
   * @return the transaction object corresponding to the request or null if no such mapping exists.
   */
  public SIPTransaction findTransaction(SIPMessage sipMessage, boolean isServer) {
    SIPTransaction retval = null;

    if (isServer) {
      Via via = sipMessage.getTopmostVia();
      if (via.getBranch() != null) {
        String key = sipMessage.getTransactionId();

        synchronized (this.serverTransactionTable) {
          retval = (SIPTransaction) serverTransactionTable.get(key);
          if (LogWriter.needsLogging) logMessage("looking for key " + key);
          if (retval != null && retval.isMessagePartOfTransaction(sipMessage)) return retval;
        }
      }
      // Need to scan the table for old style transactions (RFC 2543
      // style)
      synchronized (this.serverTransactions) {
        Iterator<SIPServerTransaction> it = serverTransactions.iterator();
        while (it.hasNext()) {
          SIPServerTransaction sipServerTransaction = (SIPServerTransaction) it.next();
          if (sipServerTransaction.isMessagePartOfTransaction(sipMessage))
            return sipServerTransaction;
        }
      }
    } else {
      Via via = sipMessage.getTopmostVia();
      if (via.getBranch() != null) {
        String key = sipMessage.getTransactionId();
        synchronized (this.clientTransactionTable) {
          retval = (SIPTransaction) clientTransactionTable.get(key);
          if (retval != null && retval.isMessagePartOfTransaction(sipMessage)) return retval;
        }
      }
      // Need to scan the table for old style transactions (RFC 2543
      // style)
      synchronized (this.clientTransactions) {
        Iterator<SIPClientTransaction> it = clientTransactions.iterator();
        while (it.hasNext()) {
          SIPClientTransaction clientTransaction = (SIPClientTransaction) it.next();
          if (clientTransaction.isMessagePartOfTransaction(sipMessage)) return clientTransaction;
        }
      }
    }
    return null;
  }
  /**
   * Get the transaction to cancel. Search the server transaction table for a transaction that
   * matches the given transaction.
   */
  public SIPTransaction findCancelTransaction(SIPRequest cancelRequest, boolean isServer) {

    if (LogWriter.needsLogging) {
      logWriter.logMessage(
          "findCancelTransaction request= \n"
              + cancelRequest
              + "\nfindCancelRequest isServer="
              + isServer);
    }

    if (isServer) {
      synchronized (this.serverTransactions) {
        Iterator<SIPServerTransaction> li = this.serverTransactions.iterator();
        while (li.hasNext()) {
          SIPTransaction transaction = (SIPTransaction) li.next();
          // SIPRequest sipRequest = (SIPRequest) (transaction
          //		.getRequest());

          SIPServerTransaction sipServerTransaction = (SIPServerTransaction) transaction;
          if (sipServerTransaction.doesCancelMatchTransaction(cancelRequest))
            return sipServerTransaction;
        }
      }
    } else {
      synchronized (this.clientTransactions) {
        Iterator<SIPClientTransaction> li = this.clientTransactions.iterator();
        while (li.hasNext()) {
          SIPTransaction transaction = (SIPTransaction) li.next();
          //					SIPRequest sipRequest = (SIPRequest) (transaction
          //							.getRequest());

          SIPClientTransaction sipClientTransaction = (SIPClientTransaction) transaction;
          if (sipClientTransaction.doesCancelMatchTransaction(cancelRequest))
            return sipClientTransaction;
        }
      }
    }
    if (LogWriter.needsLogging)
      logWriter.logMessage("Could not find transaction for cancel request");
    return null;
  }
Exemple #11
0
    @Override
    public void run() {
      try {
        logger.logEntry();

        // From
        FromHeader fromHeader = null;
        try {
          // this keep alive task only makes sense in case we have
          // a registrar so we deliberately use our AOR and do not
          // use the getOurSipAddress() method.
          fromHeader =
              provider
                  .getHeaderFactory()
                  .createFromHeader(
                      provider.getRegistrarConnection().getAddressOfRecord(),
                      SipMessageFactory.generateLocalTag());
        } catch (ParseException ex) {
          // this should never happen so let's just log and bail.
          logger.error("Failed to generate a from header for " + "our register request.", ex);
          return;
        }

        // Call ID Header
        CallIdHeader callIdHeader = provider.getDefaultJainSipProvider().getNewCallId();

        // CSeq Header
        CSeqHeader cSeqHeader = null;
        try {
          cSeqHeader =
              provider.getHeaderFactory().createCSeqHeader(getNextCSeqValue(), Request.OPTIONS);
        } catch (ParseException ex) {
          // Should never happen
          logger.error("Corrupt Sip Stack", ex);
          return;
        } catch (InvalidArgumentException ex) {
          // Should never happen
          logger.error("The application is corrupt", ex);
          return;
        }

        // To Header
        ToHeader toHeader = null;
        try {
          // this request isn't really going anywhere so we put our
          // own address in the To Header.
          toHeader = provider.getHeaderFactory().createToHeader(fromHeader.getAddress(), null);
        } catch (ParseException ex) {
          logger.error("Could not create a To header for address:" + fromHeader.getAddress(), ex);
          return;
        }

        // MaxForwardsHeader
        MaxForwardsHeader maxForwardsHeader = provider.getMaxForwardsHeader();
        // Request
        Request request = null;
        try {
          // create a host-only uri for the request uri header.
          String domain = ((SipURI) toHeader.getAddress().getURI()).getHost();

          // request URI
          SipURI requestURI = provider.getAddressFactory().createSipURI(null, domain);

          // Via Headers
          ArrayList<ViaHeader> viaHeaders = provider.getLocalViaHeaders(requestURI);

          request =
              provider
                  .getMessageFactory()
                  .createRequest(
                      requestURI,
                      Request.OPTIONS,
                      callIdHeader,
                      cSeqHeader,
                      fromHeader,
                      toHeader,
                      viaHeaders,
                      maxForwardsHeader);

          if (logger.isDebugEnabled()) logger.debug("Created OPTIONS request " + request);
        } catch (ParseException ex) {
          logger.error("Could not create an OPTIONS request!", ex);
          return;
        }

        Iterator<String> supportedMethods = provider.getSupportedMethods().iterator();

        // add to the allows header all methods that we support
        while (supportedMethods.hasNext()) {
          String method = supportedMethods.next();

          // don't support REGISTERs
          if (method.equals(Request.REGISTER)) continue;

          request.addHeader(provider.getHeaderFactory().createAllowHeader(method));
        }

        Iterator<String> events = provider.getKnownEventsList().iterator();

        synchronized (provider.getKnownEventsList()) {
          while (events.hasNext()) {
            String event = events.next();

            request.addHeader(provider.getHeaderFactory().createAllowEventsHeader(event));
          }
        }

        // Transaction
        ClientTransaction optionsTrans = null;
        try {
          optionsTrans = provider.getDefaultJainSipProvider().getNewClientTransaction(request);
        } catch (TransactionUnavailableException ex) {
          logger.error("Could not create options transaction!\n", ex);
          return;
        }
        try {
          optionsTrans.sendRequest();
          if (logger.isDebugEnabled()) logger.debug("sent request= " + request);
        } catch (SipException ex) {
          logger.error("Could not send out the options request!", ex);

          if (ex.getCause() instanceof IOException) {
            // IOException problem with network
            disconnect();
          }

          return;
        }
      } catch (Exception ex) {
        logger.error("Cannot send OPTIONS keep alive", ex);
      }
    }
  /**
   * parses received phones list and creates/resolves groups and contacts
   *
   * @param objReceived the obj with data.
   */
  private void phonesRecieved(JSONObject objReceived) {
    try {
      if (!objReceived.get("function").equals("sendlist") || !objReceived.containsKey("payload"))
        return;

      JSONObject payload = (JSONObject) objReceived.get("payload");
      /*
       * FIXME The following contains two very inefficient Map-iterating
       * loops.
       */
      Iterator iter = payload.keySet().iterator();
      List<JSONObject> phoneList = new ArrayList<JSONObject>();
      while (iter.hasNext()) {
        JSONObject obj = (JSONObject) payload.get(iter.next());
        Iterator phonesIter = obj.keySet().iterator();
        while (phonesIter.hasNext()) phoneList.add((JSONObject) obj.get(phonesIter.next()));
      }

      for (JSONObject phone : phoneList) {
        try {
          // don't handle non sip phones
          if (!((String) phone.get("tech")).equalsIgnoreCase("sip")) continue;

          String groupName = (String) phone.get("context");

          ContactGroupSipImpl parentGroup = findGroupByName(groupName);

          if (parentGroup == null) {
            parentGroup = new ContactGroupSipImpl(groupName, sipProvider);
            parentGroup.setPersistent(true);
            getRootGroup().addSubgroup(parentGroup);

            fireGroupEvent(parentGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
          }

          String number = (String) phone.get("number");

          Address address = sipProvider.parseAddressString(number);

          // if the contact is already in the contact list
          ContactSipImpl contact = parentOperationSet.resolveContactID(address.toString());

          if (contact == null) {
            contact = new ContactSipImpl(address, sipProvider);
            contact.setDisplayName(phone.get("firstname") + " " + phone.get("lastname"));
            contact.setResolved(true);
            parentGroup.addContact(contact);

            fireContactAdded(parentGroup, contact);
          } else {
            contact.setDisplayName(phone.get("firstname") + " " + phone.get("lastname"));
            contact.setResolved(true);

            fireContactResolved(parentGroup, contact);
          }
        } catch (Throwable t) {
          logger.error("Error parsing " + phone);
        }
      }
    } catch (Throwable t) {
      logger.error("Error init list from server", t);
    }
  }
  /**
   * Handles a new SIP request. It finds a server transaction to handle this message. If none
   * exists, it creates a new transaction.
   *
   * @param requestReceived Request to handle.
   * @param requestMessageChannel Channel that received message.
   * @return A server transaction.
   */
  protected ServerRequestInterface newSIPServerRequest(
      SIPRequest requestReceived, MessageChannel requestMessageChannel) {

    // Iterator through all server transactions
    Iterator<SIPServerTransaction> transactionIterator;
    // Next transaction in the set
    SIPServerTransaction nextTransaction;
    // Transaction to handle this request
    SIPServerTransaction currentTransaction;

    String key = requestReceived.getTransactionId();

    currentTransaction = (SIPServerTransaction) serverTransactionTable.get(key);
    if (currentTransaction == null
        || !currentTransaction.isMessagePartOfTransaction(requestReceived)) {

      // Loop through all server transactions
      synchronized (serverTransactions) {
        transactionIterator = serverTransactions.iterator();
        currentTransaction = null;
        while (transactionIterator.hasNext() && currentTransaction == null) {

          nextTransaction = (SIPServerTransaction) transactionIterator.next();

          // If this transaction should handle this request,
          if (nextTransaction.isMessagePartOfTransaction(requestReceived)) {
            // Mark this transaction as the one
            // to handle this message
            currentTransaction = nextTransaction;
          }
        }

        // If no transaction exists to handle this message
        if (currentTransaction == null) {
          currentTransaction = findPendingTransaction(requestReceived);
          if (currentTransaction != null) return currentTransaction;
          currentTransaction = createServerTransaction(requestMessageChannel);
          currentTransaction.setOriginalRequest(requestReceived);
          if (!isDialogCreated(requestReceived.getMethod())) {
            // Dialog is not created - can we find the state?
            // If so, then create a transaction and add it.
            String dialogId = requestReceived.getDialogId(true);
            SIPDialog dialog = getDialog(dialogId);
            // Sequence numbers are supposed to increment.
            // avoid processing old sequence numbers and
            // delivering the same request up to the
            // application if the request has already been seen.
            // Special handling applies to ACK processing.
            if (dialog != null
                && (requestReceived.getMethod().equals(Request.ACK)
                    || requestReceived.getCSeq().getSequenceNumber()
                        > dialog.getRemoteSequenceNumber())) {
              // Found a dialog.
              if (LogWriter.needsLogging)
                logWriter.logMessage("adding server transaction " + currentTransaction);
              serverTransactions.add(0, currentTransaction);
              addTransactionHash(currentTransaction);
              currentTransaction.startTransactionTimer();
              currentTransaction.isMapped = true;
            }
          } else {
            // Create the transaction but dont map it.
            String dialogId = requestReceived.getDialogId(true);
            SIPDialog dialog = getDialog(dialogId);
            // This is a dialog creating request that is part of an
            // existing dialog (eg. re-Invite). Re-invites get a non
            // null server transaction Id (unlike the original
            // invite).
            if (dialog != null
                && requestReceived.getCSeq().getSequenceNumber()
                    > dialog.getRemoteSequenceNumber()) {
              currentTransaction.map();
              if (LogWriter.needsLogging)
                logWriter.logMessage("adding server transaction " + currentTransaction);
              serverTransactions.add(0, currentTransaction);
              addTransactionHash(currentTransaction);
              currentTransaction.startTransactionTimer();
              currentTransaction.toListener = true;
            }
          }
        }
      }
    }

    // Set ths transaction's encapsulated request
    // interface from the superclass
    currentTransaction.setRequestInterface(
        super.newSIPServerRequest(requestReceived, currentTransaction));
    return currentTransaction;
  }