Package gov.nist.javax.sip.stack

Source Code of gov.nist.javax.sip.stack.UDPMessageChannel

/*
* Conditions Of Use
*
* This software was developed by employees of the National Institute of
* Standards and Technology (NIST), an agency of the Federal Government.
* Pursuant to title 15 Untied States Code Section 105, works of NIST
* employees are not subject to copyright protection in the United States
* and are considered to be in the public domain.  As a result, a formal
* license is not needed to use the software.
*
* This software is provided by NIST as a service and is expressly
* provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
* AND DATA ACCURACY.  NIST does not warrant or make any representations
* regarding the use of the software or the results thereof, including but
* not limited to the correctness, accuracy, reliability or usefulness of
* the software.
*
* Permission to use this software is contingent upon your acceptance
* of the terms of this agreement
*
* .
*
*/
/*****************************************************************************
*   Product of NIST/ITL Advanced Networking Technologies Division (ANTD).    *
*****************************************************************************/

package gov.nist.javax.sip.stack;

import java.net.*;
import gov.nist.javax.sip.*;
import gov.nist.core.*;
import gov.nist.javax.sip.header.*;
import gov.nist.javax.sip.parser.*;
import gov.nist.javax.sip.message.*;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.String;
import java.text.ParseException;

import javax.sip.address.Hop;
import javax.sip.header.CSeqHeader;
import javax.sip.header.CallIdHeader;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.ToHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;

/*
* Kim Kirby (Keyvoice) suggested that duplicate checking should be added to the
* stack (later removed). Lamine Brahimi suggested a single threaded behavior
* flag be added to this. Niklas Uhrberg suggested that thread pooling support
* be added to this for performance and resource management. Peter Parnes found
* a bug with this code that was sending it into an infinite loop when a bad
* incoming message was parsed. Bug fix by viswashanti.kadiyala@antepo.com.
* Hagai Sela addded fixes for NAT traversal. Jeroen van Bemmel fixed up for
* buggy clients (such as windows messenger) and added code to return
* BAD_REQUEST. David Alique fixed an address recording bug. Jeroen van Bemmel
* fixed a performance issue where the stack was doing DNS lookups (potentially
* unnecessary). Ricardo Bora (Natural Convergence ) added code that prevents
* the stack from exitting when an exception is encountered.
*
*/

/**
* This is the UDP Message handler that gets created when a UDP message needs to
* be processed. The message is processed by creating a String Message parser
* and invoking it on the message read from the UDP socket. The parsed structure
* is handed off via a SIP stack request for further processing. This stack
* structure isolates the message handling logic from the mechanics of sending
* and recieving messages (which could be either udp or tcp.
*
*
* @author M. Ranganathan <br/>
*
*
*
* @version 1.2 $Revision: 1.57 $ $Date: 2009/05/30 04:22:00 $
*/
public class UDPMessageChannel extends MessageChannel implements
    ParseExceptionListener, Runnable, RawMessageChannel {

  /**
   * SIP Stack structure for this channel.
   */
  protected SIPTransactionStack sipStack;

  /**
   * The parser we are using for messages received from this channel.
   */
  protected StringMsgParser myParser;

  /**
   * Where we got the stuff from
   */
  private InetAddress peerAddress;

  private String myAddress;

  private int peerPacketSourcePort;

  private InetAddress peerPacketSourceAddress;

  /**
   * Reciever port -- port of the destination.
   */
  private int peerPort;

  /**
   * Protocol to use when talking to receiver (i.e. when sending replies).
   */
  private String peerProtocol;

  protected int myPort;

  private DatagramPacket incomingPacket;

  private long receptionTime;

  /**
   * 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 stack
   *            is the shared SIPStack structure
   * @param messageProcessor
   *            is the creating message processor.
   */
  protected UDPMessageChannel(SIPTransactionStack stack,
      UDPMessageProcessor messageProcessor) {
    super.messageProcessor = messageProcessor;
    this.sipStack = stack;

    Thread mythread = new Thread(this);

    this.myAddress = messageProcessor.getIpAddress().getHostAddress();
    this.myPort = messageProcessor.getPort();

    mythread.setName("UDPMessageChannelThread");
    mythread.setDaemon(true);
    mythread.start();

  }

  /**
   * Constructor. We create one of these in order to process an incoming
   * message.
   *
   * @param stack
   *            is the SIP sipStack.
   * @param messageProcessor
   *            is the creating message processor.
   * @param packet
   *            is the incoming datagram packet.
   */
  protected UDPMessageChannel(SIPTransactionStack stack,
      UDPMessageProcessor messageProcessor, DatagramPacket packet) {

    this.incomingPacket = packet;
    super.messageProcessor = messageProcessor;
    this.sipStack = stack;

    this.myAddress = messageProcessor.getIpAddress().getHostAddress();
    this.myPort = messageProcessor.getPort();
    Thread mythread = new Thread(this);
    mythread.setDaemon(true);

    mythread.start();

  }

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

  /**
   * Run method specified by runnnable.
   */
  public void run() {
    // Assume no thread pooling (bug fix by spierhj)
    ThreadAuditor.ThreadHandle threadHandle = null;

    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 him.
      DatagramPacket packet;

      if (sipStack.threadPoolSize != -1) {
        synchronized (((UDPMessageProcessor) messageProcessor).messageQueue) {
          while (((UDPMessageProcessor) messageProcessor).messageQueue
              .isEmpty()) {
            // Check to see if we need to exit.
            if (!((UDPMessageProcessor) messageProcessor).isRunning)
              return;
            try {
              // We're part of a thread pool. Ask the auditor to
              // monitor this thread.
              if (threadHandle == null) {
                threadHandle = sipStack.getThreadAuditor()
                    .addCurrentThread();
              }

              // Send a heartbeat to the thread auditor
              threadHandle.ping();

              // Wait for packets
              // Note: getPingInterval returns 0 (infinite) if the
              // thread auditor is disabled.
              ((UDPMessageProcessor) messageProcessor).messageQueue
                  .wait(threadHandle
                      .getPingIntervalInMillisecs());
            } catch (InterruptedException ex) {
              if (!((UDPMessageProcessor) messageProcessor).isRunning)
                return;
            }
          }
          packet = (DatagramPacket) ((UDPMessageProcessor) messageProcessor).messageQueue
              .removeFirst();

        }
        this.incomingPacket = packet;
      } else {
        packet = this.incomingPacket;
      }

      // Process the packet. Catch and log any exception we may throw.
      try {
        processIncomingDataPacket(packet);
      } catch (Exception e) {
       
        sipStack.logWriter.logError(
            "Error while processing incoming UDP packet", e);
      }

      if (sipStack.threadPoolSize == -1) {
        return;
      }
    }
  }

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

  }

  /**
   * 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.logWriter.isLoggingEnabled(ServerLog.TRACE_MESSAGES)) {

        this.sipStack.serverLog.logMessage(sipMessage, this
            .getPeerHostPort().toString(), this.getHost() + ":"
            + this.myPort, false, receptionTime);

      }
      ServerRequestInterface sipServerRequest = sipStack
          .newSIPServerRequest(sipRequest, this);
      // Drop it if there is no request returned
      if (sipServerRequest == null) {
        if (sipStack.isLoggingEnabled()) {
          this.sipStack.logWriter
              .logWarning("Null request interface returned -- dropping request");
        }

       
        return;
      }
      if (sipStack.isLoggingEnabled())
        this.sipStack.logWriter.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())
        this.sipStack.logWriter.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.logWriter
              .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.logWriter
                  .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()) {
          this.sipStack.logWriter.logDebug("null sipServerResponse!");
        }
      }

    }
  }

  /**
   * JvB: added method to check for known buggy clients (Windows Messenger) to
   * fix the port to which responses are sent
   *
   * checks for User-Agent: RTC/1.3.5470 (Messenger 5.1.0701)
   *
   * JvB 22/7/2006 better to take this out for the moment, it is only a
   * problem in rare cases (unregister)
   *
   * private final boolean isBuggyClient( SIPRequest r ) { UserAgent uah =
   * (UserAgent) r.getHeader( UserAgent.NAME ); if (uah!=null) {
   * java.util.ListIterator i = uah.getProduct(); if (i.hasNext()) { String p =
   * (String) uah.getProduct().next(); return p.startsWith( "RTC" ); } }
   * return false; }
   */

  /**
   * 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.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))) {
      sipStack.logWriter.logError("BAD MESSAGE!");
      sipStack.logWriter.logError(message);
      throw ex;
    } else {
      sipMessage.addUnparsed(header);
    }
  }

  /**
   * 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.logStackTraceOnMessageSend) {
      if ( sipMessage instanceof SIPRequest &&
              ((SIPRequest)sipMessage).getRequestLine() != null) {
          /*
           * We dont want to log empty trace messages.
           */
          this.sipStack.logWriter.logStackTrace(LogWriter.TRACE_MESSAGES);
      } else {
          this.sipStack.logWriter.logStackTrace(LogWriter.TRACE_MESSAGES);
      }
    }

    // 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);
            sipStack.logWriter.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.logWriter.logError("An exception occured while sending message",ex);
      throw new IOException(
          "An exception occured while sending message");
    } finally {
      if (sipStack.logWriter.isLoggingEnabled(ServerLog.TRACE_MESSAGES))
        logMessage(sipMessage, peerAddress, peerPort, time);
    }
  }

  /**
   * 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.logStackTraceOnMessageSend ) {
      this.sipStack.logWriter.logStackTrace(LogWriter.TRACE_MESSAGES);
    }
    if (peerPort == -1) {
      if (sipStack.isLoggingEnabled()) {
        this.sipStack.logWriter.logDebug(getClass().getName()
            + ":sendMessage: Dropping reply!");
      }
      throw new IOException("Receiver port not set ");
    } else {
      if (sipStack.isLoggingEnabled()) {
        this.sipStack.logWriter.logDebug("sendMessage " + peerAddress.getHostAddress() + "/"
            + peerPort + "\n" + "messageSize =  "  + msg.length + " message = " + new String(msg)) ;
        this.sipStack.logWriter.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);
    }
  }

  /**
   * 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()) {
        this.sipStack.logWriter.logDebug(getClass().getName()
            + ":sendMessage: Dropping reply!");
      }
      throw new IOException("Receiver port not set ");
    } else {
      if (sipStack.isLoggingEnabled()) {
        this.sipStack.logWriter.logDebug( ":sendMessage " + peerAddress.getHostAddress() + "/"
            + peerPort + "\n" + " messageSize = " + msg.length
            + "\n message = "+ new String(msg));
        this.sipStack.logWriter.logDebug("*******************\n");
      }
    }
    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()) {
          this.sipStack.logWriter.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);
      OutputStream myOutputStream = outputSocket.getOutputStream();
      myOutputStream.write(msg, 0, msg.length);
      myOutputStream.flush();
      // The socket is cached (dont close it!);
    }
  }

  /**
   * get the stack pointer.
   *
   * @return The sip stack for this channel.
   */
  public SIPTransactionStack getSIPStack() {
    return sipStack;
  }

  /**
   * Return a transport string.
   *
   * @return the string "udp" in this case.
   */
  public String getTransport() {
    return SIPConstants.UDP;
  }

  /**
   * get the stack address for the stack that received this message.
   *
   * @return The stack address for our sipStack.
   */
  public String getHost() {
    return messageProcessor.getIpAddress().getHostAddress();
  }

  /**
   * get the port.
   *
   * @return Our port (on which we are getting datagram packets).
   */
  public int getPort() {
    return ((UDPMessageProcessor) messageProcessor).getPort();
  }

  /**
   * get the name (address) of the host that sent me the message
   *
   * @return The name of the sender (from the datagram packet).
   */
  public String getPeerName() {
    return peerAddress.getHostName();
  }

  /**
   * get the address of the host that sent me the message
   *
   * @return The senders ip address.
   */
  public String getPeerAddress() {
    return peerAddress.getHostAddress();
  }

  protected InetAddress getPeerInetAddress() {
    return peerAddress;
  }

  /**
   * Compare two UDP Message channels for equality.
   *
   * @param other
   *            The other message channel with which to compare oursleves.
   */
  public boolean equals(Object other) {

    if (other == null)
      return false;
    boolean retval;
    if (!this.getClass().equals(other.getClass())) {
      retval = false;
    } else {
      UDPMessageChannel that = (UDPMessageChannel) other;
      retval = this.getKey().equals(that.getKey());
    }

    return retval;
  }

  public String getKey() {
    return getKey(peerAddress, peerPort, "UDP");
  }

  public int getPeerPacketSourcePort() {
    return peerPacketSourcePort;
  }

  public InetAddress getPeerPacketSourceAddress() {
    return peerPacketSourceAddress;
  }

  /**
   * Get the logical originator of the message (from the top via header).
   *
   * @return topmost via header sentby field
   */
  public String getViaHost() {
    return this.myAddress;
  }

  /**
   * Get the logical port of the message orginator (from the top via hdr).
   *
   * @return the via port from the topmost via header.
   */
  public int getViaPort() {
    return this.myPort;
  }

  /**
   * Returns "false" as this is an unreliable transport.
   */
  public boolean isReliable() {
    return false;
  }

  /**
   * UDP is not a secure protocol.
   */
  public boolean isSecure() {
    return false;
  }

  public int getPeerPort() {
    return peerPort;
  }

  public String getPeerProtocol() {
    return this.peerProtocol;
  }

  /**
   * Close the message channel.
   */
  public void close() {
  }


}
TOP

Related Classes of gov.nist.javax.sip.stack.UDPMessageChannel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.