Example #1
0
 /** Stop stack. Clear all the timer stuff. */
 public void stopStack() {
   this.notifyPendingRecordScanner();
   this.timer.cancel();
   this.pendingTransactions.clear();
   super.stopStack();
   // PC 2.0 Notify the PendingRecordScanner to clean up
   this.notifyPendingRecordScanner();
 }
  /**
   * Constructor - takes a datagram packet and a stack structure Extracts the address of the other
   * from the datagram packet and stashes away the pointer to the passed stack structure.
   *
   * @param packet is the UDP Packet that contains the request.
   * @param sipStack stack is the shared SipStack structure
   * @param notifier Channel notifier (not very useful for UDP).
   */
  public UDPMessageChannel(
      Datagram packet, SIPMessageStack sipStack, MessageProcessor messageProcessor) {
    incomingPacket = packet;
    stack = sipStack;
    this.messageProcessor = messageProcessor;

    myAddress = sipStack.getHostAddress();
    myPort = messageProcessor.getPort();

    Thread mythread = new Thread(this, "UDPMessageChannelThread");
    mythread.start();
  }
Example #3
0
  /** Re Initialize the stack instance. */
  protected void reInit() {
    super.reInit();
    clientTransactions = Collections.synchronizedList(new ArrayList<SIPClientTransaction>());
    serverTransactions = Collections.synchronizedList(new ArrayList<SIPServerTransaction>());
    pendingTransactions = new HashSet<SIPServerTransaction>();
    pendingRecords = Collections.synchronizedList(new ArrayList<PendingRecord>());
    clientTransactionTable = new Hashtable<String, SIPTransaction>();
    serverTransactionTable = new Hashtable<String, SIPTransaction>();
    // Dialog dable.
    this.dialogTable = new Hashtable<String, SIPDialog>();

    this.timer = new Timer();
    pendingRecordScanner = new Thread(new PendingRecordScanner(this));
    pendingRecordScanner.setDaemon(true);
    pendingRecordScanner.setName("PendingRecordScanner");
    pendingRecordScanner.start();
  }
  /**
   * 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();
  }
 /**
  * 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, SIPMessage sipMessage, Class hdrClass, String header, String message)
     throws ParseException {
   if (LogWriter.needsLogging) stack.logWriter.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))) {
     stack.logBadMessage(message);
     throw ex;
   } else {
     sipMessage.addUnparsed(header);
   }
 }
  /**
   * This gets called from the parser when a parse error is generated. The handler is supposed to
   * introspect on the error class and header name to handle the error appropriately. The error can
   * be handled by :
   *
   * <ul>
   *   <li>1. Re-throwing an exception and aborting the parse.
   *   <li>2. Ignoring the header (attach the unparseable header to the Message being parsed).
   *   <li>3. Re-Parsing the bad header and adding it to the sipMessage
   * </ul>
   *
   * @param ex - parse exception being processed.
   * @param sipMessage -- sip message being processed.
   * @param headerText -- header/RL/SL text being parsed.
   * @param messageText -- message where this header was detected.
   */
  public void handleException(
      ParseException ex, Message sipMessage, Class hdrClass, String headerText, String messageText)
      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(messageText);
      throw ex;
    } else {
      sipMessage.addUnparsed(headerText);
    }
  }
  /**
   * 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";
  }
 /**
  * Constructor - connects to the given inet address. Acknowledgement -- Lamine Brahimi (IBM
  * Zurich) sent in a bug fix for this method. A thread was being uncessarily created.
  *
  * @param inetAddr inet address to connect to.
  * @param sipStack is the sip stack from which we are created.
  * @throws IOException if we cannot connect.
  */
 protected TLSMessageChannel(
     InetAddress inetAddr,
     int port,
     SIPMessageStack sipStack,
     TLSMessageProcessor messageProcessor)
     throws IOException {
   if (LogWriter.needsLogging) {
     sipStack.logWriter.logMessage("creating new TLSMessageChannel ");
     sipStack.logWriter.logStackTrace();
   }
   this.peerAddress = inetAddr;
   this.peerPort = port;
   this.myPort = messageProcessor.getPort();
   this.peerProtocol = "TLS";
   this.stack = sipStack;
   this.tlsMessageProcessor = messageProcessor;
   this.myAddress = sipStack.getHostAddress();
   // Bug report by Vishwashanti Raj Kadiayl
   this.key = MessageChannel.getKey(peerAddress, peerPort, "TLS");
   super.messageProcessor = messageProcessor;
 }
 /**
  * Constructor - gets called from the SIPStack 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 Ptr to SIP Stack
  */
 protected TLSMessageChannel(
     SSLSocket sock, SIPMessageStack sipStack, TLSMessageProcessor msgProcessor)
     throws IOException {
   if (LogWriter.needsLogging) {
     sipStack.logWriter.logMessage("creating new TLSMessageChannel ");
     sipStack.logWriter.logStackTrace();
   }
   mySock = sock;
   peerAddress = mySock.getInetAddress();
   myAddress = sipStack.getHostAddress();
   myClientInputStream = mySock.getInputStream();
   myClientOutputStream = mySock.getOutputStream();
   mythread = new Thread(this);
   mythread.setDaemon(true);
   mythread.setName("TLSMessageChannelThread");
   // Stash away a pointer to our stack structure.
   stack = sipStack;
   this.tlsMessageProcessor = msgProcessor;
   this.myPort = this.tlsMessageProcessor.getPort();
   // Bug report by Vishwashanti Raj Kadiayl
   super.messageProcessor = msgProcessor;
   // Can drop this after response is sent potentially.
   mythread.start();
 }
  /**
   * 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(SIPMessage sipMessage) throws Exception {
    try {
      if (sipMessage.getFrom() == null
          || // sipMessage.getFrom().getTag() == null ||
          sipMessage.getTo() == null
          || sipMessage.getCallId() == null
          || sipMessage.getCSeq() == null
          || sipMessage.getViaHeaders() == null) {
        String badmsg = sipMessage.encode();
        if (LogWriter.needsLogging) {
          stack.logWriter.logMessage("bad message " + badmsg);
          stack.logWriter.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 SIPRequest) {
        Via v = (Via) viaList.first();
        if (v.hasPort()) {
          this.peerPort = v.getPort();
        } else this.peerPort = 5061;
        this.peerProtocol = v.getTransport();
        try {
          this.peerAddress = mySock.getInetAddress();
          // Check to see if the received parameter matches
          // the peer address and tag it appropriately.
          // Bug fix by [email protected]
          // Should record host address not host name
          // bug fix by  Joost Yervante Damand
          if (!v.getSentBy().getInetAddress().equals(this.peerAddress)) {
            v.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress());
            // @@@ hagai
            v.setParameter(Via.RPORT, new Integer(this.peerPort).toString());
          }
        } catch (java.net.UnknownHostException ex) {
          // Could not resolve the sender address.
          if (LogWriter.needsLogging) {
            stack.logWriter.logMessage("Rejecting message -- could not resolve Via Address");
          }
          return;
        } catch (java.text.ParseException ex) {
          InternalErrorHandler.handleException(ex);
        }
        // Use this for outgoing messages as well.
        if (!this.isCached) {
          ((TLSMessageProcessor) this.messageProcessor).cacheMessageChannel(this);
          this.isCached = true;
          String key = IOHandler.makeKey(mySock.getInetAddress(), this.peerPort);
          stack.ioHandler.putSocket(key, mySock);
        }
      }

      // Foreach part of the request header, fetch it and process it

      long receptionTime = System.currentTimeMillis();
      //

      if (sipMessage instanceof SIPRequest) {
        // This is a request - process the request.
        SIPRequest sipRequest = (SIPRequest) sipMessage;
        // Create a new sever side request processor for this
        // message and let it handle the rest.

        if (LogWriter.needsLogging) {
          stack.logWriter.logMessage("----Processing Message---");
        }

        // Check for reasonable size - reject message
        // if it is too long.
        if (stack.getMaxMessageSize() > 0
            && sipRequest.getSize()
                    + (sipRequest.getContentLength() == null
                        ? 0
                        : sipRequest.getContentLength().getContentLength())
                > stack.getMaxMessageSize()) {
          SIPResponse sipResponse = sipRequest.createResponse(SIPResponse.MESSAGE_TOO_LARGE);
          byte[] resp = sipResponse.encodeAsBytes();
          this.sendMessage(resp, false);
          throw new Exception("Message size exceeded");
        }

        ServerRequestInterface sipServerRequest = stack.newSIPServerRequest(sipRequest, this);
        sipServerRequest.processRequest(sipRequest, this);
        if (this.stack.serverLog.needsLogging(ServerLog.TRACE_MESSAGES)) {
          if (sipServerRequest.getProcessingInfo() == null) {
            stack.serverLog.logMessage(
                sipMessage,
                sipRequest.getViaHost() + ":" + sipRequest.getViaPort(),
                stack.getHostAddress() + ":" + stack.getPort(this.getTransport()),
                false,
                receptionTime);
          } else {
            this.stack.serverLog.logMessage(
                sipMessage,
                sipRequest.getViaHost() + ":" + sipRequest.getViaPort(),
                stack.getHostAddress() + ":" + stack.getPort(this.getTransport()),
                sipServerRequest.getProcessingInfo(),
                false,
                receptionTime);
          }
        }
      } else {
        SIPResponse sipResponse = (SIPResponse) sipMessage;
        // This is a response message - process it.
        // Check the size of the response.
        // If it is too large dump it silently.
        if (stack.getMaxMessageSize() > 0
            && sipResponse.getSize()
                    + (sipResponse.getContentLength() == null
                        ? 0
                        : sipResponse.getContentLength().getContentLength())
                > stack.getMaxMessageSize()) {
          if (LogWriter.needsLogging) this.stack.logWriter.logMessage("Message size exceeded");
          return;
        }
        ServerResponseInterface sipServerResponse = stack.newSIPServerResponse(sipResponse, this);
        sipServerResponse.processResponse(sipResponse, this);
      }
    } finally {
    }
  }
  /**
   * 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 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);
  }