/** * 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); } } }
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); } }
/** 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(); } }
/** 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; } } }
/** * 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); } }
/** * 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); }