/** Close the message channel. */ public void close() { try { if (LogWriter.needsLogging) LogWriter.logMessage("Closing message Channel " + this); if (mySock != null) { try { String addr = mySock.getAddress(); int port = mySock.getPort(); stack.ioHandler.removeAndCloseSocket(stack.ioHandler.makeKey(addr, port)); } catch (IOException e) { if (LogWriter.needsLogging) LogWriter.logMessage("Socket was already closed for " + this); } mySock = null; } else { if (LogWriter.needsLogging) LogWriter.logMessage("Socket was already null for " + this); } } catch (Exception ex) { if (LogWriter.needsLogging) { LogWriter.logMessage("Exception closing message Channel " + this); LogWriter.logException(ex); } } finally { this.isRunning = false; uncache(); } }
/** * Exception processor for exceptions detected from the application. * * @param ex The exception that was generated. */ public void handleException(SIPServerException ex) { // Return a parse error message to the client on the other end // if he is still alive. int rc = ex.getRC(); String msgString = ex.getMessage(); if (rc != 0) { // Do we have a valid Return code ? -- // in this case format the message. Request request = (Request) ex.getSIPMessage(); Response response = request.createResponse(rc); try { sendMessage(response); } catch (IOException ioex) { if (LogWriter.needsLogging) LogWriter.logException(ioex); } } else { // Otherwise, message is already formatted -- // just return it try { sendMessage(msgString.getBytes(), false); } catch (IOException ioex) { if (LogWriter.needsLogging) LogWriter.logException(ioex); } } }
/** Run method specified by runnable. */ public void run() { while (true) { // Create a new string message parser to parse the list of messages. if (myParser == null) { myParser = new StringMsgParser(); myParser.setParseExceptionListener(this); } // messages that we write out to the peer. Datagram packet; if (stack.threadPoolSize != -1) { synchronized (((UDPMessageProcessor) messageProcessor).messageQueue) { while (((UDPMessageProcessor) messageProcessor).messageQueue.isEmpty()) { // Check to see if we need to exit. if (!((UDPMessageProcessor) messageProcessor).running) return; try { // Wait for packets ((UDPMessageProcessor) messageProcessor).messageQueue.wait(); } catch (InterruptedException ex) { if (!((UDPMessageProcessor) messageProcessor).running) return; } } packet = (Datagram) ((UDPMessageProcessor) messageProcessor).messageQueue.firstElement(); ((UDPMessageProcessor) messageProcessor).messageQueue.removeElementAt(0); } incomingPacket = packet; } else { packet = incomingPacket; } if (LogWriter.needsLogging) { LogWriter.logMessage( LogWriter.TRACE_DEBUG, "Processing new incoming datagram " + packet.getLength()); } // Process the packet. Catch and log any exception we may throw. try { processIncomingDataPacket(packet); } catch (Throwable e) { if (LogWriter.needsLogging) { LogWriter.logMessage( LogWriter.TRACE_EXCEPTION, "Exception processing incoming UDP packet"); LogWriter.logException((Exception) e); } } if (stack.threadPoolSize == -1) { return; } } }
/** * This gets invoked when thread.start is called from the constructor. Implements a message loop - * reading the tcp connection and processing messages until we are done or the other end has * closed. */ public void run() { if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_DEBUG, "New TCP Message Channel Thread started " + this + " " + Thread.currentThread()); // Removed by ArnauVP: in MIDP it's not reliable to read in blocks // from inputstreams; thus the Pipe was useless for byte-to-byte reads, // and was giving sync problems when reading from the pipe (duplicate bytes). // Create a pipeline to connect to our message parser. // Pipeline hispipe = null; // hispipe = new Pipeline(myClientInputStream, stack.readTimeout, // ((SIPTransactionStack) stack).getTimer()); // Create a pipelined message parser to read from inputStream // and parse SIP messages from the bytes. myParser = new PipelinedMsgParser( this, myClientInputStream, this.messageProcessor.getMaximumMessageSize()); myParser.setMessageChannel(this); // Start running the parser thread. myParser.processInput(); // Changed by ArnauVP: using a buffer in some implementations of MIDP, // the call to read(msg) would not return from until BUFFER_SIZE bytes were available, // thus delaying the processing of the responses by the application and causing timeout. // bug fix by Emmanuel Proulx // int bufferSize = 4096; this.tcpMessageProcessor.useCount++; this.isRunning = true; }
/** * Constructor - gets called from the SIPMessageStack class with a socket on accepting a new * client. All the processing of the message is done here with the stack being freed up to handle * new connections. The sock input is the socket that is returned from the accept. Global data * that is shared by all threads is accessible in the Server structure. * * @param sock Socket from which to read and write messages. The socket is already connected (was * created as a result of an accept). * @param sipStack the SIP Stack * @param channelNotifier Notifier (optional) that gets called when the channel is opened or * closed. */ protected TCPMessageChannel( SocketConnection sock, SIPMessageStack sipStack, TCPMessageProcessor msgProcessor) throws IOException { stack = sipStack; mySock = sock; myAddress = sipStack.getHostAddress(); peerAddress = sock.getAddress(); myClientInputStream = sock.openInputStream(); myClientOutputStream = sock.openOutputStream(); if (LogWriter.needsLogging) { LogWriter.logMessage("Creating new TCPMessageChannel " + this); LogWriter.logMessage( LogWriter.TRACE_DEBUG, "Channel parameters: " + "stack: " + stack + "\n" + "processor: " + msgProcessor + "\n" + "localAddress: " + myAddress + "\n" + "peerAddress: " + peerAddress + "\n" + "IS " + myClientInputStream + " Socket " + mySock); } stack.ioHandler.putSocket( stack.ioHandler.makeKey(mySock.getAddress(), mySock.getPort()), mySock, myClientOutputStream, myClientInputStream); mythread = new Thread(this, "TCPMessageChannel - incoming connection"); this.tcpMessageProcessor = msgProcessor; this.myPort = this.tcpMessageProcessor.getPort(); // Bug report by Vishwashanti Raj Kadiayl super.messageProcessor = msgProcessor; mythread.start(); }
public void closeFromParser() { try { if (LogWriter.needsLogging) LogWriter.logMessage("Closing message Channel " + this + " from Parser"); if (mySock != null) { try { String addr = mySock.getAddress(); int port = mySock.getPort(); stack.ioHandler.removeAndCloseSocket(stack.ioHandler.makeKey(addr, port)); } catch (IOException e) { if (LogWriter.needsLogging) LogWriter.logMessage("Socket was already closed for " + this); } mySock = null; } else { if (LogWriter.needsLogging) LogWriter.logMessage("Socket was already null for " + this); } } catch (Exception ex) { if (LogWriter.needsLogging && !stack.toExit) { LogWriter.logMessage( LogWriter.TRACE_EXCEPTION, "Exception closing message Channel " + this); LogWriter.logException(ex); } } finally { this.isRunning = false; uncache(); this.tcpMessageProcessor.useCount--; if (LogWriter.needsLogging) LogWriter.logMessage("TCP Message Processor use count: " + tcpMessageProcessor.useCount); } }
/** * Exception processor for exceptions detected from the parser. (This is invoked by the parser * when an error is detected). * * @param sipMessage -- the message that incurred the error. * @param ex -- parse exception detected by the parser. * @param header -- header that caused the error. * @throws ParseException Thrown if we want to reject the message. */ public void handleException( ParseException ex, Message sipMessage, Class hdrClass, String header, String message) throws ParseException { if (LogWriter.needsLogging) LogWriter.logException(ex); // Log the bad message for later reference. if (hdrClass.equals(FromHeader.clazz) || hdrClass.equals(ToHeader.clazz) || hdrClass.equals(CSeqHeader.clazz) || hdrClass.equals(ViaHeader.clazz) || hdrClass.equals(CallIdHeader.clazz) || hdrClass.equals(RequestLine.clazz) || hdrClass.equals(StatusLine.clazz)) { stack.logBadMessage(message); throw ex; } else { sipMessage.addUnparsed(header); } }
/** * Constructor. We create one of these when we send out a message. * * @param targetAddr internet address of the place where we want to send messages. * @param port target port (where we want to send the message). * @param stack our SIP Stack. */ public UDPMessageChannel( String targetAddr, int port, SIPMessageStack sipStack, UDPMessageProcessor processor) { if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_DEBUG, "DEBUG, UDPMessageChannel, UDPMessageChannel()," + " Creating message channel on " + targetAddr + "/" + port); stack = sipStack; this.peerPort = port; this.peerAddress = targetAddr; this.messageProcessor = processor; this.myPort = processor.getPort(); this.myAddress = sipStack.getHostAddress(); this.peerProtocol = "UDP"; }
/** * Send a message to a specified receiver address. * * @param msg message string to send. * @param receiverAddress Address of the place to send it to. * @param receiverPort the port to send it to. * @throws IOException If there is trouble sending this message. */ protected void sendMessage( byte[] msg, String receiverAddress, int receiverPort, boolean reconnect) throws IOException { // msg += "\r\n\r\n"; // Via is not included in the request so silently drop the reply. if (receiverPort == -1) { if (LogWriter.needsLogging) LogWriter.logMessage( "DEBUG, UDPMessageChannel, sendMessage()," + " The message is not sent: the receiverPort=-1"); throw new IOException("Receiver port not set "); } try { DatagramConnection socket; boolean created = false; if (stack.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! socket = ((UDPMessageProcessor) messageProcessor).dc; } else { // bind to any interface and port. // format: datagram://address:port String url = "datagram://" + peerAddress + ":" + peerPort; socket = (DatagramConnection) Connector.open(url); created = true; } Datagram reply = socket.newDatagram(msg, msg.length); socket.send(reply); if (created) socket.close(); } catch (IOException ex) { throw ex; } catch (Exception ex) { InternalErrorHandler.handleException(ex); } }
/** * Constructor - connects to the given inet address. Acknowledgement -- Lamine Brahimi (IBM * Zurich) sent in a bug fix for this method. A thread was being unnecessarily created. * * @param inetAddr inet address to connect to. * @param sipStack is the sip stack from which we are created. * @param messageProcessor to whom a parsed message is passed * @throws IOException if we cannot connect. */ protected TCPMessageChannel( String inetAddr, int port, SIPMessageStack sipStack, TCPMessageProcessor messageProcessor) throws IOException { this.peerAddress = inetAddr; this.peerPort = port; this.myPort = messageProcessor.getPort(); this.peerProtocol = "TCP"; this.stack = sipStack; this.tcpMessageProcessor = messageProcessor; this.myAddress = sipStack.getHostAddress(); // Bug report by Vishwashanti Raj Kadiayl super.messageProcessor = messageProcessor; this.key = "TCP" + ":" + stack.ioHandler.makeKey(peerAddress, peerPort); if (LogWriter.needsLogging) LogWriter.logMessage( "Created new TCP Message Channel " + this + " with key " + key + "\nprocessor: " + messageProcessor); }
/** * Gets invoked by the parser as a callback on successful message parsing (i.e. no parser errors). * * @param sipMessage Mesage to process (this calls the application for processing the message). */ public void processMessage(Message sipMessage) { if (!stack.isAlive()) { if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_DEBUG, "MsgChannel " + this + " is dropping message as the stack is closing"); return; // drop messages when closing, avoid Exceptions } try { if (LogWriter.needsLogging) LogWriter.logMessage( "[TCPMessageChannel]-> Processing incoming message: " + sipMessage.getFirstLine()); if (sipMessage.getFromHeader() == null || sipMessage.getTo() == null || sipMessage.getCallId() == null || sipMessage.getCSeqHeader() == null || sipMessage.getViaHeaders() == null) { String badmsg = sipMessage.encode(); if (LogWriter.needsLogging) { ServerLog.logMessage("bad message " + badmsg); ServerLog.logMessage(">>> Dropped Bad Msg"); } stack.logBadMessage(badmsg); return; } ViaList viaList = sipMessage.getViaHeaders(); // For a request // first via header tells where the message is coming from. // For response, this has already been recorded in the outgoing // message. if (sipMessage instanceof Request) { ViaHeader v = (ViaHeader) viaList.first(); if (v.hasPort()) { viaPort = v.getPort(); } else { viaPort = SIPMessageStack.DEFAULT_PORT; } this.peerProtocol = v.getTransport(); try { if (peerPort == -1) peerPort = mySock.getPort(); this.peerAddress = mySock.getAddress(); // Log this because it happens when the remote host identifies // as a FQDN but this is not resolvable to an IP by the OS. // S40 doesn't have DNS settings, for instance, so if the APN // is not able to resolve all the addresses of the SIP/IMS core, // this problem will appear. if (peerAddress == null && LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_EXCEPTION, "WARNING! Socket.getAddress() returned 'null'!!!"); // Be warned, the host comparison may fail if socket.getAddress() // returns a domain name as the Via Host will be a numeric IP. // FIXME: No idea. Doing a DNS lookup or reverse DNS lookup // can be misleading because they can be non-matching, that is, // DNS(peerAddressName) != ReverseDNS(peerAddressIP) if (v.hasParameter(ViaHeader.RPORT) || !v.getHost().equals(this.peerAddress)) { if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_MESSAGES, "WARNING! \"Received\" parameter " + "has been temporarily disabled. Response will be sent to topmost Via Host: " + v.getHost()); this.peerAddress = v.getHost(); // if (LogWriter.needsLogging) // LogWriter.logMessage(LogWriter.TRACE_MESSAGES, "Adding // \"received\" parameter" + // " to incoming request with value: " + peerAddress + // " because it doesn't match the Via host " + v.getHost()); // v.setParameter(ViaHeader.RECEIVED, this.peerAddress); } if (v.hasParameter(ViaHeader.RPORT)) v.setParameter(ViaHeader.RPORT, Integer.toString(this.peerPort)); /* * If socket is invalid, close it because it is useless and dangerous. * Also if we ran out of slots for new sockets, as this could prevent * incoming connections from being accepted. */ if (mySock.getAddress() == null || (stack.maxConnections != -1 && tcpMessageProcessor.getNumConnections() >= stack.maxConnections)) { stack.ioHandler.disposeSocket(mySock, myClientInputStream, myClientOutputStream); mySock = null; myClientInputStream = null; myClientOutputStream = null; if (stack.maxConnections != -1) { synchronized (tcpMessageProcessor) { tcpMessageProcessor.decreaseNumConnections(); tcpMessageProcessor.notify(); } } } // reuse socket even for outgoing requests else if (!this.isCached) { ((TCPMessageProcessor) this.messageProcessor).cacheMessageChannel(this); String key = "TCP" + ":" + stack.ioHandler.makeKey(peerAddress, peerPort); stack.ioHandler.putSocket(key, mySock, myClientOutputStream, myClientInputStream); } } catch (IOException e) { e.printStackTrace(); } } // System.out.println("receiver address = " + receiverAddress); // For each part of the request header, fetch it and process it long receptionTime = System.currentTimeMillis(); if (sipMessage instanceof Request) { // This is a request - process the request. Request sipRequest = (Request) sipMessage; // Create a new sever side request processor for this // message and let it handle the rest. if (LogWriter.needsLogging) { LogWriter.logMessage("----Processing Message---"); } // TODO: check maximum size of request SIPServerRequestInterface sipServerRequest = stack.newSIPServerRequest(sipRequest, this); if (sipServerRequest != null) { try { sipServerRequest.processRequest(sipRequest, this); ServerLog.logMessage( sipMessage, sipRequest.getViaHost() + ":" + sipRequest.getViaPort(), stack.getHostAddress() + ":" + stack.getPort(this.getTransport()), false, receptionTime); } catch (SIPServerException ex) { ServerLog.logMessage( sipMessage, sipRequest.getViaHost() + ":" + sipRequest.getViaPort(), stack.getHostAddress() + ":" + stack.getPort(this.getTransport()), ex.getMessage(), false, receptionTime); handleException(ex); } } else { if (LogWriter.needsLogging) LogWriter.logMessage("Dropping request -- null sipServerRequest"); } } else { // This is a response message - process it. Response sipResponse = (Response) sipMessage; // TODO: check maximum size of the response SIPServerResponseInterface sipServerResponse = stack.newSIPServerResponse(sipResponse, this); if (LogWriter.needsLogging) LogWriter.logMessage("got a response interface " + sipServerResponse); try { // Responses with no ClienTransaction associated will not be processed // as they may cause a NPE in the EventScanner thread. if (sipServerResponse != null) sipServerResponse.processResponse(sipResponse, this); else { if (LogWriter.needsLogging) { LogWriter.logMessage("null sipServerResponse!"); } } } catch (SIPServerException ex) { // An error occured processing the message -- just log it. ServerLog.logMessage( sipMessage, getPeerAddress().toString() + ":" + getPeerPort(), stack.getHostAddress() + ":" + stack.getPort(this.getTransport()), ex.getMessage(), false, receptionTime); // Ignore errors while processing responses?? } } } catch (Exception ee) { if (stack.isAlive()) { throw new RuntimeException(ee.getClass() + ":" + ee.getMessage()); } // else ignore exceptions } finally { // this.tcpMessageProcessor.useCount --; } }
/** * Send message to whoever is connected to us. Uses the topmost via address to send to. * * @param message is the message to send. */ private void sendMessage(byte[] msg, boolean retry) throws IOException { int portToUse; if (viaPort != -1) portToUse = viaPort; else portToUse = peerPort; if (!this.isRunning && !this.isCached) { if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_MESSAGES, "Tried to send message through a Message Channel that is no longer running. Create a new one."); TCPMessageChannel newChannel = (TCPMessageChannel) this.tcpMessageProcessor.createMessageChannel(this.peerAddress, portToUse); newChannel.sendMessage(msg, retry); return; } SocketConnection sock = stack.ioHandler.sendBytes(this.peerAddress, portToUse, this.peerProtocol, msg, retry); /*Fix: don't replace the original socket (where the incoming request came from) with the one created to send the response to the port specified by the VIA header. This would cause a NPE later, as the 'via socket' will be closed shortly after sending the response. Thanks to Janos Vig (Genaker) for detecting this. */ if (sock != null && (mySock == null || (sock != mySock && sock.getPort() == mySock.getPort()))) { try { if (mySock != null) { if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_MESSAGES, "Closing socket on TCPMessageChannel and replacing with new one"); // Closing the IO streams will also stop the parser reading from them if (myClientOutputStream != null) myClientOutputStream.close(); if (myClientInputStream != null) myClientInputStream.close(); mySock.close(); } else { if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_DEBUG, "TCP Msg channel " + this + " socket was null!"); } } catch (IOException ex) { ex.printStackTrace(); } // replace the old references of socket and IO streams // to the ones pointing to the newly created socket. mySock = sock; myClientOutputStream = stack.ioHandler.getSocketOutputStream(mySock); myClientInputStream = stack.ioHandler.getSocketInputStream(mySock); if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_DEBUG, "Creating new Thread from Message Channel " + this + " and new socket " + sock + " IS " + myClientInputStream); Thread thread = new Thread(this); thread.start(); } }
/** * Send a message to a specified receiver address. * * @param msg message string to send. * @param receiverAddress Address of the place to send it to. * @param receiverPort the port to send it to. * @param receiverProtocol protocol to use to send. * @param retry try if connection was not successful at fi * @throws IOException If there is trouble sending this message. */ protected void sendMessage( byte[] msg, String receiverAddress, int receiverPort, String receiverProtocol, boolean retry) throws IOException { if (LogWriter.needsLogging) LogWriter.logMessage( "Sending message to [" + receiverAddress + ":" + receiverPort + "/" + receiverProtocol + "]\n" + new String(msg) + " to be sent to "); // msg += "\r\n\r\n"; // Via is not included in the request so silently drop the reply. if (receiverPort == -1) { if (LogWriter.needsLogging) LogWriter.logMessage( "DEBUG, UDPMessageChannel, sendMessage()," + " The message is not sent: the receiverPort=-1"); throw new IOException("Receiver port not set "); } if (Utils.compareToIgnoreCase(receiverProtocol, "UDP") == 0) { try { DatagramConnection socket; Datagram reply; boolean created = false; if (stack.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! socket = ((UDPMessageProcessor) messageProcessor).dc; // ArnauVP: this has the problem that the datagram created from this (inbound) connection // doesn't have an address assigned. Let's do it. reply = socket.newDatagram(msg, msg.length); reply.setAddress("datagram://" + peerAddress + ":" + peerPort); } else { // bind to any interface and port. // format: datagram://address:port socket = stack.getNetworkLayer().createDatagramSocket(peerAddress, peerPort); reply = socket.newDatagram(msg, msg.length); created = true; } if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_DEBUG, "UDPMessageChannel, sendMessage()," + " Sending message over UDP, using socket " + socket + " created " + created + " destination " + reply.getAddress()); socket.send(reply); if (created) socket.close(); } catch (IOException ex) { throw ex; } catch (Exception ex) { InternalErrorHandler.handleException(ex); } } else { // Use TCP to talk back to the sender. SocketConnection outputSocket = stack.ioHandler.sendBytes(peerAddress, peerPort, "tcp", msg, retry); OutputStream myOutputStream = stack.ioHandler.getSocketOutputStream(outputSocket); myOutputStream.write(msg, 0, msg.length); myOutputStream.flush(); // The socket is cached (don't close it!); } }
/** * Actually process the parsed SIP message. * * @param sipMessage */ public void processMessage(Message sipMessage) { if (sipMessage instanceof Request) { Request sipRequest = (Request) sipMessage; // This is a request - process it. SIPServerRequestInterface sipServerRequest = stack.newSIPServerRequest(sipRequest, this); // Drop it if there is no request returned if (sipServerRequest == null) { if (LogWriter.needsLogging) { LogWriter.logMessage("Null request interface returned"); } return; } try { if (LogWriter.needsLogging) LogWriter.logMessage( "About to process " + sipRequest.getFirstLine() + "/" + sipServerRequest); sipServerRequest.processRequest(sipRequest, this); if (LogWriter.needsLogging) LogWriter.logMessage( "Done processing " + sipRequest.getFirstLine() + "/" + sipServerRequest); // So far so good -- we will commit this message if // all processing is OK. if (ServerLog.needsLogging(ServerLog.TRACE_MESSAGES)) { if (sipServerRequest.getProcessingInfo() == null) { ServerLog.logMessage( sipMessage, sipRequest.getViaHost() + ":" + sipRequest.getViaPort(), stack.getHostAddress() + ":" + stack.getPort(this.getTransport()), false, new Long(receptionTime).toString()); } else { ServerLog.logMessage( sipMessage, sipRequest.getViaHost() + ":" + sipRequest.getViaPort(), stack.getHostAddress() + ":" + stack.getPort(this.getTransport()), sipServerRequest.getProcessingInfo(), false, new Long(receptionTime).toString()); } } } catch (SIPServerException ex) { if (ServerLog.needsLogging(ServerLog.TRACE_MESSAGES)) { ServerLog.logMessage( sipMessage, sipRequest.getViaHost() + ":" + sipRequest.getViaPort(), stack.getHostAddress() + ":" + stack.getPort(this.getTransport()), ex.getMessage(), false, new Long(receptionTime).toString()); } handleException(ex); } } else { // Handle a SIP Response message. Response sipResponse = (Response) sipMessage; SIPServerResponseInterface sipServerResponse = stack.newSIPServerResponse(sipResponse, this); try { if (sipServerResponse != null) { sipServerResponse.processResponse(sipResponse, this); // Normal processing of message. } else { if (LogWriter.needsLogging) { LogWriter.logMessage("null sipServerResponse!"); } } } catch (SIPServerException ex) { if (ServerLog.needsLogging(ServerLog.TRACE_MESSAGES)) { this.logResponse(sipResponse, receptionTime, ex.getMessage() + "-- Dropped!"); } ServerLog.logException(ex); } } }
/** * Process an incoming datagram * * @param packet is the incoming datagram packet. */ private void processIncomingDataPacket(Datagram packet) throws Exception { // For a request first via header tells where the message // is coming from. // For response, just get the port from the packet. // format: address:port String address = packet.getAddress(); try { int firstColon = address.indexOf("//"); int secondColon = address.indexOf(":", firstColon + 1); this.peerAddress = address.substring(firstColon + 2, secondColon); if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_DEBUG, "UDPMessageChannel, run(), sender address:" + peerAddress); String senderPortString = address.substring(address.indexOf(";") + 1, address.indexOf("|")); this.peerPacketSourcePort = Integer.parseInt(senderPortString); if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_DEBUG, "UDPMessageChannel, run(), sender port:" + peerPacketSourcePort); } catch (NumberFormatException e) { if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_EXCEPTION, "UDPMessageChannel, run(), exception raised: " + e.getMessage()); e.printStackTrace(); peerPacketSourcePort = -1; } int packetLength = packet.getLength(); // Read bytes and put it in a queue. byte[] msgBytes = packet.getData(); // Do debug logging. if (LogWriter.needsLogging) { LogWriter.logMessage( LogWriter.TRACE_DEBUG, "UDPMessageChannel: processIncomingDataPacket : peerAddress = " + peerAddress + "/" + peerPacketSourcePort + " Length = " + packetLength + " msgBytes " + msgBytes); } Message sipMessage = null; try { receptionTime = System.currentTimeMillis(); sipMessage = myParser.parseSIPMessage(msgBytes); myParser = null; } catch (ParseException ex) { myParser = null; // let go of the parser reference. if (LogWriter.needsLogging) { LogWriter.logMessage(LogWriter.TRACE_DEBUG, "Rejecting message ! " + new String(msgBytes)); LogWriter.logMessage(LogWriter.TRACE_DEBUG, "error message " + ex.getMessage()); LogWriter.logException(ex); } // TODO: do this on TCP too // JvB: send a 400 response for requests (except ACK) String msgString = new String(msgBytes, 0, packetLength); if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) { String badReqRes = create400Response(msgString, ex); if (badReqRes != null) { if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_DEBUG, "Sending automatic 400 Bad Request: " + badReqRes); try { this.sendMessage(badReqRes.getBytes(), peerAddress, peerPacketSourcePort, "UDP", false); } catch (IOException e) { LogWriter.logException(e); } } else { if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_DEBUG, "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 (LogWriter.needsLogging) LogWriter.logMessage(LogWriter.TRACE_DEBUG, "Rejecting message ! + Null message parsed."); return; } ViaList viaList = sipMessage.getViaHeaders(); // Check for the required headers. if (sipMessage.getFromHeader() == null || // sipMessage.getFromHeader().getTag() == null || sipMessage.getTo() == null || sipMessage.getCallId() == null || sipMessage.getCSeqHeader() == null || sipMessage.getViaHeaders() == null) { String badmsg = new String(msgBytes); if (LogWriter.needsLogging) { LogWriter.logMessage("bad message " + badmsg); LogWriter.logMessage( ">>> Dropped Bad Msg " + "FromHeader = " + sipMessage.getFromHeader() + "ToHeader = " + sipMessage.getTo() + "CallId = " + sipMessage.getCallId() + "CSeqHeader = " + sipMessage.getCSeqHeader() + "Via = " + sipMessage.getViaHeaders()); } stack.logBadMessage(badmsg); 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 Request) { ViaHeader v = (ViaHeader) viaList.first(); if (v.hasPort()) this.peerPort = v.getPort(); else this.peerPort = SIPMessageStack.DEFAULT_PORT; this.peerProtocol = v.getTransport(); boolean hasRPort = v.hasParameter(ViaHeader.RPORT); // Be warned, the host comparison may fail if socket.getAddress() // returns a domain name as the Via Host will be a numeric IP. // FIXME: No idea. Doing a DNS lookup or reverse DNS lookup // can be misleading because they can be non-matching, that is, // DNS(peerAddressName) != ReverseDNS(peerAddressIP) if (hasRPort || !this.peerAddress.equals(v.getHost())) { if (LogWriter.needsLogging) LogWriter.logMessage( LogWriter.TRACE_MESSAGES, "WARNING! \"Received\" parameter " + "has been temporarily disabled. Response will be sent to topmost Via Host: " + v.getHost()); this.peerAddress = v.getHost(); // if (LogWriter.needsLogging) // LogWriter.logMessage(LogWriter.TRACE_MESSAGES, "Adding \"received\" // parameter" + // " to incoming request with value: " + peerAddress + // " because it doesn't match the Via host " + v.getHost()); // v.setParameter(ViaHeader.RECEIVED, this.peerAddress); } if (hasRPort) { v.setParameter(ViaHeader.RPORT, Integer.toString(peerPacketSourcePort)); this.peerPort = peerPacketSourcePort; } } else { this.peerPort = this.peerPacketSourcePort; this.peerProtocol = ((ViaHeader) viaList.getFirst()).getTransport(); } processMessage(sipMessage); }