/** * 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; }
/** * 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; }
/** * Add a new client transaction to the set of existing transactions. Add it to the top of the list * so an incoming response has less work to do in order to find the transaction. * * @param clientTransaction -- client transaction to add to the set. */ public void addTransaction(SIPClientTransaction clientTransaction) { if (LogWriter.needsLogging) logWriter.logMessage("added transaction " + clientTransaction); synchronized (clientTransactions) { clientTransactions.add(0, clientTransaction); } addTransactionHash(clientTransaction); clientTransaction.startTransactionTimer(); }
/** Remove transaction. */ public void removeTransaction(SIPTransaction sipTransaction) { if (sipTransaction instanceof SIPServerTransaction) { synchronized (serverTransactions) { serverTransactions.remove(sipTransaction); } synchronized (serverTransactionTable) { String key = sipTransaction.getTransactionId(); serverTransactionTable.remove(key); } } else { synchronized (clientTransactions) { clientTransactions.remove(sipTransaction); } synchronized (clientTransactionTable) { String key = sipTransaction.getTransactionId(); clientTransactionTable.remove(key); } } }
/** * Create a client transaction from a raw channel. * * @param transaction is the transport channel to encapsulate. */ public MessageChannel createMessageChannel(SIPTransaction transaction) { synchronized (clientTransactions) { // New client transaction to return SIPTransaction returnChannel = createClientTransaction(transaction.getMessageChannel()); clientTransactions.add(0, (SIPClientTransaction) returnChannel); ((SIPClientTransaction) returnChannel).setViaPort(transaction.getViaPort()); ((SIPClientTransaction) returnChannel).setViaHost(transaction.getViaHost()); // Add the transaction timer for the state machine. returnChannel.startTransactionTimer(); return returnChannel; } }
/** * 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; }
/** * Creates a client transaction to handle a new request. Gets the real message channel from the * superclass, and then creates a new client transaction wrapped around this channel. * * @param nextHop Hop to create a channel to contact. */ public MessageChannel createMessageChannel(int sourcePort, Hop nextHop) throws UnknownHostException { synchronized (clientTransactions) { // New client transaction to return SIPTransaction returnChannel; // Create a new client transaction around the // superclass' message channel MessageChannel mc = super.createMessageChannel(sourcePort, nextHop); // Superclass will return null if no message processor // available for the transport. if (mc == null) return null; returnChannel = createClientTransaction(mc); clientTransactions.add(0, (SIPClientTransaction) returnChannel); ((SIPClientTransaction) returnChannel).setViaPort(nextHop.getPort()); ((SIPClientTransaction) returnChannel).setViaHost(nextHop.getHost()); // Add the transaction timer for the state machine. returnChannel.startTransactionTimer(); return returnChannel; } }
public void removePending(PendingRecord pendingRecord) { synchronized (pendingRecords) { pendingRecords.remove(pendingRecord); } }
public void putPending(PendingRecord pendingRecord) { synchronized (pendingRecords) { pendingRecords.add(pendingRecord); } }
public boolean hasResources() { if (transactionTableSize == -1) return true; else { return serverTransactions.size() < transactionTableSize; } }
/** * 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; }