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