protected void runTask() { SIPTransaction transaction = SIPTransaction.this; // release the connection associated with this transaction. SIPTransactionStack sipStack = transaction.getSIPStack(); if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("LingerTimer: run() : " + getTransactionId()); } if (transaction instanceof SIPClientTransaction) { sipStack.removeTransaction(transaction); transaction.close(); } else if (transaction instanceof ServerTransaction) { // Remove it from the set if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack.getStackLogger().logDebug("removing" + transaction); sipStack.removeTransaction(transaction); if ((!sipStack.cacheServerConnections) && --transaction.encapsulatedChannel.useCount <= 0) { // Close the encapsulated socket if stack is configured transaction.close(); } else { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG) && (!sipStack.cacheServerConnections) && transaction.isReliable()) { int useCount = transaction.encapsulatedChannel.useCount; sipStack.getStackLogger().logDebug("Use Count = " + useCount); } } } }
/** * Send a message to a specified receiver address. * * @param msg string to send. * @param peerAddress Address of the place to send it to. * @param peerPort the port to send it to. * @throws IOException If there is trouble sending this message. */ protected void sendMessage(byte[] msg, InetAddress peerAddress, int peerPort, boolean reConnect) throws IOException { // Via is not included in the request so silently drop the reply. if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend()) { this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO); } if (peerPort == -1) { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack .getStackLogger() .logDebug(getClass().getName() + ":sendMessage: Dropping reply!"); } throw new IOException("Receiver port not set "); } else { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack .getStackLogger() .logDebug( "sendMessage " + peerAddress.getHostAddress() + "/" + peerPort + "\n" + "messageSize = " + msg.length + " message = " + new String(msg)); this.sipStack.getStackLogger().logDebug("*******************\n"); } } DatagramPacket reply = new DatagramPacket(msg, msg.length, peerAddress, peerPort); try { DatagramSocket sock; boolean created = false; if (sipStack.udpFlag) { // Use the socket from the message processor (for firewall // support use the same socket as the message processor // socket -- feature request # 18 from java.net). This also // makes the whole thing run faster! sock = ((UDPMessageProcessor) messageProcessor).sock; // Bind the socket to the stack address in case there // are multiple interfaces on the machine (feature reqeust // by Will Scullin) 0 binds to an ephemeral port. // sock = new DatagramSocket(0,sipStack.stackInetAddress); } else { // bind to any interface and port. sock = new DatagramSocket(); created = true; } sock.send(reply); if (created) sock.close(); } catch (IOException ex) { throw ex; } catch (Exception ex) { InternalErrorHandler.handleException(ex); } }
/** * Return a reply from a pre-constructed reply. This sends the message back to the entity who * caused us to create this channel in the first place. * * @param sipMessage Message string to send. * @throws IOException If there is a problem with sending the message. */ public void sendMessage(SIPMessage sipMessage) throws IOException { if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend()) { if (sipMessage instanceof SIPRequest && ((SIPRequest) sipMessage).getRequestLine() != null) { /* * We dont want to log empty trace messages. */ this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO); } else { this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO); } } // Test and see where we are going to send the messsage. If the message // is sent back to oursleves, just // shortcircuit processing. long time = System.currentTimeMillis(); try { for (MessageProcessor messageProcessor : sipStack.getMessageProcessors()) { if (messageProcessor.getIpAddress().equals(this.peerAddress) && messageProcessor.getPort() == this.peerPort && messageProcessor.getTransport().equals(this.peerProtocol)) { MessageChannel messageChannel = messageProcessor.createMessageChannel(this.peerAddress, this.peerPort); if (messageChannel instanceof RawMessageChannel) { ((RawMessageChannel) messageChannel).processMessage(sipMessage); if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack.getStackLogger().logDebug("Self routing message"); return; } } } byte[] msg = sipMessage.encodeAsBytes(this.getTransport()); sendMessage(msg, peerAddress, peerPort, peerProtocol, sipMessage instanceof SIPRequest); } catch (IOException ex) { throw ex; } catch (Exception ex) { sipStack.getStackLogger().logError("An exception occured while sending message", ex); throw new IOException("An exception occured while sending message"); } finally { if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES) && !sipMessage.isNullRequest()) logMessage(sipMessage, peerAddress, peerPort, time); else if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_DEBUG)) sipStack.getStackLogger().logDebug("Sent EMPTY Message"); } }
/** * Sets the request message that this transaction handles. * * @param newOriginalRequest Request being handled. */ public void setOriginalRequest(SIPRequest newOriginalRequest) { // Branch value of topmost Via header String newBranch; if (this.originalRequest != null && (!this.originalRequest .getTransactionId() .equals(newOriginalRequest.getTransactionId()))) { sipStack.removeTransactionHash(this); } // This will be cleared later. this.originalRequest = newOriginalRequest; // just cache the control information so the // original request can be released later. this.method = newOriginalRequest.getMethod(); this.from = (From) newOriginalRequest.getFrom(); this.to = (To) newOriginalRequest.getTo(); // Save these to avoid concurrent modification exceptions! this.toTag = this.to.getTag(); this.fromTag = this.from.getTag(); this.callId = (CallID) newOriginalRequest.getCallId(); this.cSeq = newOriginalRequest.getCSeq().getSeqNumber(); this.event = (Event) newOriginalRequest.getHeader("Event"); this.transactionId = newOriginalRequest.getTransactionId(); originalRequest.setTransaction(this); // If the message has an explicit branch value set, newBranch = ((Via) newOriginalRequest.getViaHeaders().getFirst()).getBranch(); if (newBranch != null) { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack.getStackLogger().logDebug("Setting Branch id : " + newBranch); // Override the default branch with the one // set by the message setBranch(newBranch); } else { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack .getStackLogger() .logDebug("Branch id is null - compute TID!" + newOriginalRequest.encode()); setBranch(newOriginalRequest.getTransactionId()); } }
/** * Transaction constructor. * * @param newParentStack Parent stack for this transaction. * @param newEncapsulatedChannel Underlying channel for this transaction. */ protected SIPTransaction( SIPTransactionStack newParentStack, MessageChannel newEncapsulatedChannel) { sipStack = newParentStack; this.semaphore = new Semaphore(1, true); encapsulatedChannel = newEncapsulatedChannel; // Record this to check if the address has changed before sending // message to avoid possible race condition. this.peerPort = newEncapsulatedChannel.getPeerPort(); this.peerAddress = newEncapsulatedChannel.getPeerAddress(); this.peerInetAddress = newEncapsulatedChannel.getPeerInetAddress(); // @@@ hagai this.peerPacketSourcePort = newEncapsulatedChannel.getPeerPacketSourcePort(); this.peerPacketSourceAddress = newEncapsulatedChannel.getPeerPacketSourceAddress(); this.peerProtocol = newEncapsulatedChannel.getPeerProtocol(); if (this.isReliable()) { encapsulatedChannel.useCount++; if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack .getStackLogger() .logDebug( "use count for encapsulated channel" + this + " " + encapsulatedChannel.useCount); } this.currentState = null; disableRetransmissionTimer(); disableTimeoutTimer(); eventListeners = Collections.synchronizedSet(new HashSet<SIPTransactionEventListener>()); // Always add the parent stack as a listener // of this transaction addEventListener(newParentStack); }
/** * Changes the state of this transaction. * * @param newState New state of this transaction. */ public void setState(TransactionState newState) { // PATCH submitted by sribeyron if (currentState == TransactionState.COMPLETED) { if (newState != TransactionState.TERMINATED && newState != TransactionState.CONFIRMED) newState = TransactionState.COMPLETED; } if (currentState == TransactionState.CONFIRMED) { if (newState != TransactionState.TERMINATED) newState = TransactionState.CONFIRMED; } if (currentState != TransactionState.TERMINATED) currentState = newState; else newState = currentState; // END OF PATCH if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack .getStackLogger() .logDebug( "Transaction:setState " + newState + " " + this + " branchID = " + this.getBranch() + " isClient = " + (this instanceof SIPClientTransaction)); sipStack.getStackLogger().logStackTrace(); } }
/** * Log a message into the log file. * * @param message message to log into the log file. */ private void logMessage(String message) { // String tname = Thread.currentThread().getName(); checkLogFile(); String logInfo = message; if (printWriter != null) { printWriter.println(logInfo); } if (sipStack.isLoggingEnabled()) { stackLogger.logInfo(logInfo); } }
/** * Implementation of the ParseExceptionListener interface. * * @param ex Exception that is given to us by the parser. * @throws ParseException If we choose to reject the header or message. */ public void handleException( ParseException ex, SIPMessage sipMessage, Class hdrClass, String header, String message) throws ParseException { if (sipStack.isLoggingEnabled()) this.sipStack.getStackLogger().logException(ex); // Log the bad message for later reference. if ((hdrClass != null) && (hdrClass.equals(From.class) || hdrClass.equals(To.class) || hdrClass.equals(CSeq.class) || hdrClass.equals(Via.class) || hdrClass.equals(CallID.class) || hdrClass.equals(RequestLine.class) || hdrClass.equals(StatusLine.class))) { if (sipStack.isLoggingEnabled()) { sipStack.getStackLogger().logError("BAD MESSAGE!"); sipStack.getStackLogger().logError(message); } throw ex; } else { sipMessage.addUnparsed(header); } }
protected void semRelease() { try { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("semRelease ]]]]" + this); sipStack.getStackLogger().logStackTrace(); } this.isSemaphoreAquired = false; this.semaphore.release(); } catch (Exception ex) { sipStack.getStackLogger().logError("Unexpected exception releasing sem", ex); } }
/** * Enables a timeout event to occur for this transaction after the number of ticks passed to this * method. * * @param tickCount Number of ticks before this transaction times out. */ protected final void enableTimeoutTimer(int tickCount) { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack .getStackLogger() .logDebug( "enableTimeoutTimer " + this + " tickCount " + tickCount + " currentTickCount = " + timeoutTimerTicksLeft); timeoutTimerTicksLeft = tickCount; }
/** * Constructor. We create one of these when we send out a message. * * @param targetAddr INET address of the place where we want to send messages. * @param port target port (where we want to send the message). * @param sipStack our SIP Stack. */ protected UDPMessageChannel( InetAddress targetAddr, int port, SIPTransactionStack sipStack, UDPMessageProcessor messageProcessor) { peerAddress = targetAddr; peerPort = port; peerProtocol = "UDP"; super.messageProcessor = messageProcessor; this.myAddress = messageProcessor.getIpAddress().getHostAddress(); this.myPort = messageProcessor.getPort(); this.sipStack = sipStack; if (sipStack.isLoggingEnabled()) { this.sipStack.logWriter.logDebug( "Creating message channel " + targetAddr.getHostAddress() + "/" + port); } }
/** * Constructor. We create one of these when we send out a message. * * @param targetAddr INET address of the place where we want to send messages. * @param port target port (where we want to send the message). * @param sipStack our SIP Stack. */ protected UDPMessageChannel( InetAddress targetAddr, int port, SIPTransactionStack sipStack, UDPMessageProcessor messageProcessor) { peerAddress = targetAddr; peerPort = port; peerProtocol = "UDP"; super.messageProcessor = messageProcessor; this.myAddress = messageProcessor.getIpAddress().getHostAddress(); this.myPort = messageProcessor.getPort(); this.sipStack = sipStack; // jeand : Create a new string message parser to parse the list of messages. myParser = sipStack.getMessageParserFactory().createMessageParser(sipStack); if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack .getStackLogger() .logDebug("Creating message channel " + targetAddr.getHostAddress() + "/" + port); } }
/** * A given tx can process only a single outstanding event at a time. This semaphore gaurds * re-entrancy to the transaction. */ public boolean acquireSem() { boolean retval = false; try { if (sipStack.getStackLogger().isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("acquireSem [[[[" + this); sipStack.getStackLogger().logStackTrace(); } if (this.sipStack.maxListenerResponseTime == -1) { this.semaphore.acquire(); retval = true; } else { retval = this.semaphore.tryAcquire(this.sipStack.maxListenerResponseTime, TimeUnit.SECONDS); } if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack.getStackLogger().logDebug("acquireSem() returning : " + retval); return retval; } catch (Exception ex) { sipStack.getStackLogger().logError("Unexpected exception acquiring sem", ex); InternalErrorHandler.handleException(ex); return false; } finally { this.isSemaphoreAquired = retval; } }
/** * Send a message to a specified receiver address. * * @param msg message string to send. * @param peerAddress Address of the place to send it to. * @param peerPort the port to send it to. * @param peerProtocol protocol to use to send. * @throws IOException If there is trouble sending this message. */ protected void sendMessage( byte[] msg, InetAddress peerAddress, int peerPort, String peerProtocol, boolean retry) throws IOException { // Via is not included in the request so silently drop the reply. if (peerPort == -1) { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack .getStackLogger() .logDebug(getClass().getName() + ":sendMessage: Dropping reply!"); } throw new IOException("Receiver port not set "); } else { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack .getStackLogger() .logDebug( ":sendMessage " + peerAddress.getHostAddress() + "/" + peerPort + "\n" + " messageSize = " + msg.length); } } if (peerProtocol.compareToIgnoreCase("UDP") == 0) { DatagramPacket reply = new DatagramPacket(msg, msg.length, peerAddress, peerPort); try { DatagramSocket sock; if (sipStack.udpFlag) { sock = ((UDPMessageProcessor) messageProcessor).sock; } else { // bind to any interface and port. sock = sipStack.getNetworkLayer().createDatagramSocket(); } if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack .getStackLogger() .logDebug( "sendMessage " + peerAddress.getHostAddress() + "/" + peerPort + "\n" + new String(msg)); } sock.send(reply); if (!sipStack.udpFlag) sock.close(); } catch (IOException ex) { throw ex; } catch (Exception ex) { InternalErrorHandler.handleException(ex); } } else { // Use TCP to talk back to the sender. Socket outputSocket = sipStack.ioHandler.sendBytes( this.messageProcessor.getIpAddress(), peerAddress, peerPort, "tcp", msg, retry, this); OutputStream myOutputStream = outputSocket.getOutputStream(); myOutputStream.write(msg, 0, msg.length); myOutputStream.flush(); // The socket is cached (dont close it!); } }
public void checkLogFile() { if (logFileName == null || traceLevel < TRACE_MESSAGES) { // Dont create a log file if tracing is // disabled. return; } try { File logFile = new File(logFileName); if (!logFile.exists()) { logFile.createNewFile(); printWriter = null; } // Append buffer to the end of the file unless otherwise specified // by the user. if (printWriter == null) { boolean overwrite = Boolean.valueOf( configurationProperties.getProperty("gov.nist.javax.sip.SERVER_LOG_OVERWRITE")); FileWriter fw = new FileWriter(logFileName, !overwrite); printWriter = new PrintWriter(fw, true); printWriter.println( "<!-- " + "Use the Trace Viewer in src/tools/tracesviewer to" + " view this trace \n" + "Here are the stack configuration properties \n" + "javax.sip.IP_ADDRESS= " + configurationProperties.getProperty("javax.sip.IP_ADDRESS") + "\n" + "javax.sip.STACK_NAME= " + configurationProperties.getProperty("javax.sip.STACK_NAME") + "\n" + "javax.sip.ROUTER_PATH= " + configurationProperties.getProperty("javax.sip.ROUTER_PATH") + "\n" + "javax.sip.OUTBOUND_PROXY= " + configurationProperties.getProperty("javax.sip.OUTBOUND_PROXY") + "\n" + "-->"); printWriter.println( "<description\n logDescription=\"" + description + "\"\n name=\"" + configurationProperties.getProperty("javax.sip.STACK_NAME") + "\"\n auxInfo=\"" + auxInfo + "\"/>\n "); if (auxInfo != null) { if (sipStack.isLoggingEnabled()) { stackLogger.logDebug( "Here are the stack configuration properties \n" + "javax.sip.IP_ADDRESS= " + configurationProperties.getProperty("javax.sip.IP_ADDRESS") + "\n" + "javax.sip.ROUTER_PATH= " + configurationProperties.getProperty("javax.sip.ROUTER_PATH") + "\n" + "javax.sip.OUTBOUND_PROXY= " + configurationProperties.getProperty("javax.sip.OUTBOUND_PROXY") + "\n" + "gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS= " + configurationProperties.getProperty( "gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS") + "\n" + "gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS= " + configurationProperties.getProperty( "gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS") + "\n" + "gov.nist.javax.sip.REENTRANT_LISTENER= " + configurationProperties.getProperty("gov.nist.javax.sip.REENTRANT_LISTENER") + "gov.nist.javax.sip.THREAD_POOL_SIZE= " + configurationProperties.getProperty("gov.nist.javax.sip.THREAD_POOL_SIZE") + "\n"); stackLogger.logDebug(" ]]> "); stackLogger.logDebug("</debug>"); stackLogger.logDebug( "<description\n logDescription=\"" + description + "\"\n name=\"" + stackIpAddress + "\"\n auxInfo=\"" + auxInfo + "\"/>\n "); stackLogger.logDebug("<debug>"); stackLogger.logDebug("<![CDATA[ "); } } else { if (sipStack.isLoggingEnabled()) { stackLogger.logDebug( "Here are the stack configuration properties \n" + configurationProperties + "\n"); stackLogger.logDebug(" ]]>"); stackLogger.logDebug("</debug>"); stackLogger.logDebug( "<description\n logDescription=\"" + description + "\"\n name=\"" + stackIpAddress + "\" />\n"); stackLogger.logDebug("<debug>"); stackLogger.logDebug("<![CDATA[ "); } } } } catch (IOException ex) { } }
/** * Process an incoming datagram * * @param packet is the incoming datagram packet. */ private void processIncomingDataPacket(DatagramPacket packet) throws Exception { this.peerAddress = packet.getAddress(); int packetLength = packet.getLength(); // Read bytes and put it in a eueue. byte[] bytes = packet.getData(); byte[] msgBytes = new byte[packetLength]; System.arraycopy(bytes, 0, msgBytes, 0, packetLength); // Do debug logging. if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack .getStackLogger() .logDebug( "UDPMessageChannel: processIncomingDataPacket : peerAddress = " + peerAddress.getHostAddress() + "/" + packet.getPort() + " Length = " + packetLength); } SIPMessage sipMessage = null; try { this.receptionTime = System.currentTimeMillis(); sipMessage = myParser.parseSIPMessage(msgBytes, true, false, this); // myParser = null; } catch (ParseException ex) { // myParser = null; // let go of the parser reference. if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack.getStackLogger().logDebug("Rejecting message ! " + new String(msgBytes)); this.sipStack.getStackLogger().logDebug("error message " + ex.getMessage()); this.sipStack.getStackLogger().logException(ex); } // JvB: send a 400 response for requests (except ACK) // Currently only UDP, @todo also other transports String msgString = new String(msgBytes, 0, packetLength); if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) { String badReqRes = createBadReqRes(msgString, ex); if (badReqRes != null) { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("Sending automatic 400 Bad Request:"); sipStack.getStackLogger().logDebug(badReqRes); } try { this.sendMessage(badReqRes.getBytes(), peerAddress, packet.getPort(), "UDP", false); } catch (IOException e) { this.sipStack.getStackLogger().logException(e); } } else { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("Could not formulate automatic 400 Bad Request"); } } } return; } // No parse exception but null message - reject it and // march on (or return). // exit this message processor if the message did not parse. if (sipMessage == null) { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack.getStackLogger().logDebug("Rejecting message ! + Null message parsed."); } String key = packet.getAddress().getHostAddress() + ":" + packet.getPort(); if (pingBackRecord.get(key) == null && sipStack.getMinKeepAliveInterval() > 0) { byte[] retval = "\r\n\r\n".getBytes(); DatagramPacket keepalive = new DatagramPacket(retval, 0, retval.length, packet.getAddress(), packet.getPort()); PingBackTimerTask task = new PingBackTimerTask(packet.getAddress().getHostAddress(), packet.getPort()); this.pingBackRecord.put(key, task); this.sipStack.getTimer().schedule(task, sipStack.getMinKeepAliveInterval() * 1000); ((UDPMessageProcessor) this.messageProcessor).sock.send(keepalive); } else { sipStack.getStackLogger().logDebug("Not sending ping back"); } return; } Via topMostVia = sipMessage.getTopmostVia(); // Check for the required headers. if (sipMessage.getFrom() == null || sipMessage.getTo() == null || sipMessage.getCallId() == null || sipMessage.getCSeq() == null || topMostVia == null) { String badmsg = new String(msgBytes); if (sipStack.isLoggingEnabled()) { this.sipStack.getStackLogger().logError("bad message " + badmsg); this.sipStack .getStackLogger() .logError( ">>> Dropped Bad Msg " + "From = " + sipMessage.getFrom() + "To = " + sipMessage.getTo() + "CallId = " + sipMessage.getCallId() + "CSeq = " + sipMessage.getCSeq() + "Via = " + sipMessage.getViaHeaders()); } return; } // For a request first via header tells where the message // is coming from. // For response, just get the port from the packet. if (sipMessage instanceof SIPRequest) { Hop hop = sipStack.addressResolver.resolveAddress(topMostVia.getHop()); this.peerPort = hop.getPort(); this.peerProtocol = topMostVia.getTransport(); this.peerPacketSourceAddress = packet.getAddress(); this.peerPacketSourcePort = packet.getPort(); try { this.peerAddress = packet.getAddress(); // Check to see if the received parameter matches // the peer address and tag it appropriately. boolean hasRPort = topMostVia.hasParameter(Via.RPORT); if (hasRPort || !hop.getHost().equals(this.peerAddress.getHostAddress())) { topMostVia.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress()); } if (hasRPort) { topMostVia.setParameter(Via.RPORT, Integer.toString(this.peerPacketSourcePort)); } } catch (java.text.ParseException ex1) { InternalErrorHandler.handleException(ex1); } } else { this.peerPacketSourceAddress = packet.getAddress(); this.peerPacketSourcePort = packet.getPort(); this.peerAddress = packet.getAddress(); this.peerPort = packet.getPort(); this.peerProtocol = topMostVia.getTransport(); } this.processMessage(sipMessage); }
/** * Actually proces the parsed message. * * @param sipMessage */ public void processMessage(SIPMessage sipMessage) { if (sipMessage instanceof SIPRequest) { SIPRequest sipRequest = (SIPRequest) sipMessage; // This is a request - process it. // So far so good -- we will commit this message if // all processing is OK. if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) { this.sipStack.serverLogger.logMessage( sipMessage, this.getPeerHostPort().toString(), this.getHost() + ":" + this.myPort, false, receptionTime); } final ServerRequestInterface sipServerRequest = sipStack.newSIPServerRequest(sipRequest, this); // Drop it if there is no request returned if (sipServerRequest == null) { if (sipStack.isLoggingEnabled()) { this.sipStack .getStackLogger() .logWarning("Null request interface returned -- dropping request"); } return; } if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) this.sipStack .getStackLogger() .logDebug("About to process " + sipRequest.getFirstLine() + "/" + sipServerRequest); try { sipServerRequest.processRequest(sipRequest, this); } finally { if (sipServerRequest instanceof SIPTransaction) { SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest; if (!sipServerTx.passToListener()) { ((SIPTransaction) sipServerRequest).releaseSem(); } } } if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) this.sipStack .getStackLogger() .logDebug("Done processing " + sipRequest.getFirstLine() + "/" + sipServerRequest); // So far so good -- we will commit this message if // all processing is OK. } else { // Handle a SIP Reply message. SIPResponse sipResponse = (SIPResponse) sipMessage; try { sipResponse.checkHeaders(); } catch (ParseException ex) { if (sipStack.isLoggingEnabled()) sipStack .getStackLogger() .logError("Dropping Badly formatted response message >>> " + sipResponse); return; } ServerResponseInterface sipServerResponse = sipStack.newSIPServerResponse(sipResponse, this); if (sipServerResponse != null) { try { if (sipServerResponse instanceof SIPClientTransaction && !((SIPClientTransaction) sipServerResponse).checkFromTag(sipResponse)) { if (sipStack.isLoggingEnabled()) sipStack .getStackLogger() .logError("Dropping response message with invalid tag >>> " + sipResponse); return; } sipServerResponse.processResponse(sipResponse, this); } finally { if (sipServerResponse instanceof SIPTransaction && !((SIPTransaction) sipServerResponse).passToListener()) ((SIPTransaction) sipServerResponse).releaseSem(); } // Normal processing of message. } else { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.sipStack.getStackLogger().logDebug("null sipServerResponse!"); } } } }
/** * Extract identities from certificates exchanged over TLS, based on guidelines from * draft-ietf-sip-domain-certs-04. * * @return list of authenticated identities */ public List<String> extractCertIdentities() throws SSLPeerUnverifiedException { if (this.getMessageChannel() instanceof TLSMessageChannel) { List<String> certIdentities = new ArrayList<String>(); Certificate[] certs = getPeerCertificates(); if (certs == null) { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("No certificates available"); } return certIdentities; } for (Certificate cert : certs) { X509Certificate x509cert = (X509Certificate) cert; Collection<List<?>> subjAltNames = null; try { subjAltNames = x509cert.getSubjectAlternativeNames(); } catch (CertificateParsingException ex) { if (sipStack.isLoggingEnabled()) { sipStack.getStackLogger().logError("Error parsing TLS certificate", ex); } } // subjAltName types are defined in rfc2459 final Integer dnsNameType = 2; final Integer uriNameType = 6; if (subjAltNames != null) { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("found subjAltNames: " + subjAltNames); } // First look for a URI in the subjectAltName field // as per draft-ietf-sip-domain-certs-04 for (List<?> altName : subjAltNames) { // 0th position is the alt name type // 1st position is the alt name data if (altName.get(0).equals(uriNameType)) { SipURI altNameUri; try { altNameUri = new AddressFactoryImpl().createSipURI((String) altName.get(1)); String altHostName = altNameUri.getHost(); if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack .getStackLogger() .logDebug("found uri " + altName.get(1) + ", hostName " + altHostName); } certIdentities.add(altHostName); } catch (ParseException e) { if (sipStack.isLoggingEnabled()) { sipStack .getStackLogger() .logError("certificate contains invalid uri: " + altName.get(1)); } } } } // DNS An implementation MUST accept a domain name system // identifier as a SIP domain identity if and only if no other // identity is found that matches the "sip" URI type described // above. if (certIdentities.isEmpty()) { for (List<?> altName : subjAltNames) { if (altName.get(0).equals(dnsNameType)) { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("found dns " + altName.get(1)); } certIdentities.add(altName.get(1).toString()); } } } } else { // If and only if the subjectAltName does not appear in the // certificate, the implementation MAY examine the CN field of the // certificate. If a valid DNS name is found there, the // implementation MAY accept this value as a SIP domain identity. String dname = x509cert.getSubjectDN().getName(); String cname = ""; try { Pattern EXTRACT_CN = Pattern.compile(".*CN\\s*=\\s*([\\w*\\.]+).*"); Matcher matcher = EXTRACT_CN.matcher(dname); if (matcher.matches()) { cname = matcher.group(1); if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("found CN: " + cname + " from DN: " + dname); } certIdentities.add(cname); } } catch (Exception ex) { if (sipStack.isLoggingEnabled()) { sipStack.getStackLogger().logError("exception while extracting CN", ex); } } } } return certIdentities; } else throw new UnsupportedOperationException("Not a TLS channel"); }
/** Set the passToListener flag to true. */ public void setPassToListener() { if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { sipStack.getStackLogger().logDebug("setPassToListener()"); } this.toListener = true; }
/** * Process the message through the transaction and sends it to the SIP peer. * * @param messageToSend Message to send to the SIP peer. */ public void sendMessage(final SIPMessage messageToSend) throws IOException { // Use the peer address, port and transport // that was specified when the transaction was // created. Bug was noted by Bruce Evangelder // soleo communications. try { final RawMessageChannel channel = (RawMessageChannel) encapsulatedChannel; for (MessageProcessor messageProcessor : sipStack.getMessageProcessors()) { boolean addrmatch = messageProcessor .getIpAddress() .getHostAddress() .toString() .equals(this.getPeerAddress()); if (addrmatch && messageProcessor.getPort() == this.getPeerPort() && messageProcessor.getTransport().equalsIgnoreCase(this.getPeerProtocol())) { if (channel instanceof TCPMessageChannel) { try { Runnable processMessageTask = new Runnable() { public void run() { try { ((TCPMessageChannel) channel) .processMessage( (SIPMessage) messageToSend.clone(), getPeerInetAddress()); } catch (Exception ex) { if (getSIPStack() .getStackLogger() .isLoggingEnabled(ServerLogger.TRACE_ERROR)) { getSIPStack() .getStackLogger() .logError("Error self routing message cause by: ", ex); } } } }; getSIPStack().getSelfRoutingThreadpoolExecutor().execute(processMessageTask); } catch (Exception e) { sipStack.getStackLogger().logError("Error passing message in self routing", e); } if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack.getStackLogger().logDebug("Self routing message"); return; } if (channel instanceof RawMessageChannel) { try { Runnable processMessageTask = new Runnable() { public void run() { try { ((RawMessageChannel) channel) .processMessage((SIPMessage) messageToSend.clone()); } catch (Exception ex) { if (getSIPStack() .getStackLogger() .isLoggingEnabled(ServerLogger.TRACE_ERROR)) { getSIPStack() .getStackLogger() .logError("Error self routing message cause by: ", ex); } } } }; getSIPStack().getSelfRoutingThreadpoolExecutor().execute(processMessageTask); } catch (Exception e) { sipStack.getStackLogger().logError("Error passing message in self routing", e); } if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack.getStackLogger().logDebug("Self routing message"); return; } } } encapsulatedChannel.sendMessage(messageToSend, this.peerInetAddress, this.peerPort); } finally { this.startTransactionTimer(); } }
/** * Process an incoming datagram * * @param packet is the incoming datagram packet. */ private void processIncomingDataPacket(DatagramPacket packet) throws Exception { this.peerAddress = packet.getAddress(); int packetLength = packet.getLength(); // Read bytes and put it in a eueue. byte[] bytes = packet.getData(); byte[] msgBytes = new byte[packetLength]; System.arraycopy(bytes, 0, msgBytes, 0, packetLength); // Do debug logging. if (sipStack.isLoggingEnabled()) { this.sipStack.logWriter.logDebug( "UDPMessageChannel: processIncomingDataPacket : peerAddress = " + peerAddress.getHostAddress() + "/" + packet.getPort() + " Length = " + packetLength); } SIPMessage sipMessage = null; try { this.receptionTime = System.currentTimeMillis(); sipMessage = myParser.parseSIPMessage(msgBytes); myParser = null; } catch (ParseException ex) { myParser = null; // let go of the parser reference. if (sipStack.isLoggingEnabled()) { this.sipStack.logWriter.logDebug("Rejecting message ! " + new String(msgBytes)); this.sipStack.logWriter.logDebug("error message " + ex.getMessage()); this.sipStack.logWriter.logException(ex); } // JvB: send a 400 response for requests (except ACK) // Currently only UDP, @todo also other transports String msgString = new String(msgBytes, 0, packetLength); if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) { String badReqRes = createBadReqRes(msgString, ex); if (badReqRes != null) { if (sipStack.isLoggingEnabled()) { sipStack.getLogWriter().logDebug("Sending automatic 400 Bad Request:"); sipStack.getLogWriter().logDebug(badReqRes); } try { this.sendMessage(badReqRes.getBytes(), peerAddress, packet.getPort(), "UDP", false); } catch (IOException e) { this.sipStack.logWriter.logException(e); } } else { if (sipStack.isLoggingEnabled()) { sipStack.getLogWriter().logDebug("Could not formulate automatic 400 Bad Request"); } } } return; } // No parse exception but null message - reject it and // march on (or return). // exit this message processor if the message did not parse. if (sipMessage == null) { if (sipStack.isLoggingEnabled()) { this.sipStack.logWriter.logDebug("Rejecting message ! + Null message parsed."); } return; } ViaList viaList = sipMessage.getViaHeaders(); // Check for the required headers. if (sipMessage.getFrom() == null || sipMessage.getTo() == null || sipMessage.getCallId() == null || sipMessage.getCSeq() == null || sipMessage.getViaHeaders() == null) { String badmsg = new String(msgBytes); if (sipStack.isLoggingEnabled()) { this.sipStack.logWriter.logError("bad message " + badmsg); this.sipStack.logWriter.logError( ">>> Dropped Bad Msg " + "From = " + sipMessage.getFrom() + "To = " + sipMessage.getTo() + "CallId = " + sipMessage.getCallId() + "CSeq = " + sipMessage.getCSeq() + "Via = " + sipMessage.getViaHeaders()); } sipStack.logWriter.logError("BAD MESSAGE!"); return; } // For a request first via header tells where the message // is coming from. // For response, just get the port from the packet. if (sipMessage instanceof SIPRequest) { Via v = (Via) viaList.getFirst(); Hop hop = sipStack.addressResolver.resolveAddress(v.getHop()); this.peerPort = hop.getPort(); this.peerProtocol = v.getTransport(); this.peerPacketSourceAddress = packet.getAddress(); this.peerPacketSourcePort = packet.getPort(); try { this.peerAddress = packet.getAddress(); // Check to see if the received parameter matches // the peer address and tag it appropriately. boolean hasRPort = v.hasParameter(Via.RPORT); if (hasRPort || !hop.getHost().equals(this.peerAddress.getHostAddress())) { v.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress()); } if (hasRPort) { v.setParameter(Via.RPORT, Integer.toString(this.peerPacketSourcePort)); } } catch (java.text.ParseException ex1) { InternalErrorHandler.handleException(ex1); } } else { this.peerPacketSourceAddress = packet.getAddress(); this.peerPacketSourcePort = packet.getPort(); this.peerAddress = packet.getAddress(); this.peerPort = packet.getPort(); this.peerProtocol = ((Via) viaList.getFirst()).getTransport(); } this.processMessage(sipMessage); }
/** * A method that can be used to test if an incoming request belongs to this transction. This does * not take the transaction state into account when doing the check otherwise it is identical to * isMessagePartOfTransaction. This is useful for checking if a CANCEL belongs to this * transaction. * * @param requestToTest is the request to test. * @return true if the the request belongs to the transaction. */ public boolean doesCancelMatchTransaction(SIPRequest requestToTest) { // List of Via headers in the message to test ViaList viaHeaders; // Topmost Via header in the list Via topViaHeader; // Branch code in the topmost Via header String messageBranch; // Flags whether the select message is part of this transaction boolean transactionMatches; transactionMatches = false; if (this.getOriginalRequest() == null || this.getOriginalRequest().getMethod().equals(Request.CANCEL)) return false; // Get the topmost Via header and its branch parameter viaHeaders = requestToTest.getViaHeaders(); if (viaHeaders != null) { topViaHeader = (Via) viaHeaders.getFirst(); messageBranch = topViaHeader.getBranch(); if (messageBranch != null) { // If the branch parameter exists but // does not start with the magic cookie, if (!messageBranch.toLowerCase().startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) { // Flags this as old // (RFC2543-compatible) client // version messageBranch = null; } } // If a new branch parameter exists, if (messageBranch != null && this.getBranch() != null) { // If the branch equals the branch in // this message, if (getBranch().equalsIgnoreCase(messageBranch) && topViaHeader .getSentBy() .equals(((Via) getOriginalRequest().getViaHeaders().getFirst()).getSentBy())) { transactionMatches = true; if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack.getStackLogger().logDebug("returning true"); } } else { // If this is an RFC2543-compliant message, // If RequestURI, To tag, From tag, // CallID, CSeq number, and top Via // headers are the same, if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack.getStackLogger().logDebug("testing against " + getOriginalRequest()); if (getOriginalRequest().getRequestURI().equals(requestToTest.getRequestURI()) && getOriginalRequest().getTo().equals(requestToTest.getTo()) && getOriginalRequest().getFrom().equals(requestToTest.getFrom()) && getOriginalRequest() .getCallId() .getCallId() .equals(requestToTest.getCallId().getCallId()) && getOriginalRequest().getCSeq().getSeqNumber() == requestToTest.getCSeq().getSeqNumber() && topViaHeader.equals(getOriginalRequest().getViaHeaders().getFirst())) { transactionMatches = true; } } } // JvB: Need to pass the CANCEL to the listener! Retransmitted INVITEs // set it to false if (transactionMatches) { this.setPassToListener(); } return transactionMatches; }
/** Close the encapsulated channel. */ public void close() { this.encapsulatedChannel.close(); if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) sipStack.getStackLogger().logDebug("Closing " + this.encapsulatedChannel); }