Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * 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;
 
 
 
 
 /*
  * 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(s):
M. Ranganathan
Version:
1.2 $Revision: 1.65 $ $Date: 2009/11/19 05:26:57 $
 
 public class UDPMessageChannel extends MessageChannel implements
         ParseExceptionListenerRunnableRawMessageChannel {

    
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 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.

Parameters:
stack is the shared SIPStack structure
messageProcessor is the creating message processor.
    protected UDPMessageChannel(SIPTransactionStack stack,
            UDPMessageProcessor messageProcessor) {
        super. = messageProcessor;
        this. = stack;
        Thread mythread = new Thread(this);
        this. = messageProcessor.getIpAddress().getHostAddress();
        this. = messageProcessor.getPort();
        mythread.setName("UDPMessageChannelThread");
        mythread.setDaemon(true);
        mythread.start();
    }

    
Constructor. We create one of these in order to process an incoming message.

Parameters:
stack is the SIP sipStack.
messageProcessor is the creating message processor.
packet is the incoming datagram packet.
    protected UDPMessageChannel(SIPTransactionStack stack,
            UDPMessageProcessor messageProcessorDatagramPacket packet) {
        this. = packet;
        super. = messageProcessor;
        this. = stack;
        this. = messageProcessor.getIpAddress().getHostAddress();
        this. = messageProcessor.getPort();
        Thread mythread = new Thread(this);
        mythread.setDaemon(true);
        mythread.start();
    }

    
Constructor. We create one of these when we send out a message.

Parameters:
targetAddr INET address of the place where we want to send messages.
port target port (where we want to send the message).
sipStack our SIP Stack.
    protected UDPMessageChannel(InetAddress targetAddrint port,
            SIPTransactionStack sipStackUDPMessageProcessor messageProcessor) {
         = targetAddr;
         = port;
         = "UDP";
        super. = messageProcessor;
        this. = messageProcessor.getIpAddress().getHostAddress();
        this. = messageProcessor.getPort();
        this. = sipStack;
        if (sipStack.isLoggingEnabled()) {
            this..getStackLogger().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 ( == null) {
                 = new StringMsgParser();
                .setParseExceptionListener(this);
            }
            // messages that we write out to him.
            DatagramPacket packet;
            if (. != -1) {
                synchronized (((UDPMessageProcessor).) {
                    while (((UDPMessageProcessor).
                            .isEmpty()) {
                        // Check to see if we need to exit.
                        if (!((UDPMessageProcessor).)
                            return;
                        try {
                            // We're part of a thread pool. Ask the auditor to
                            // monitor this thread.
                            if (threadHandle == null) {
                                threadHandle = .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).
                                    .wait(threadHandle
                                            .getPingIntervalInMillisecs());
                        } catch (InterruptedException ex) {
                            if (!((UDPMessageProcessor).)
                                return;
                        }
                    }
                    packet = (DatagramPacket) ((UDPMessageProcessor).
                            .removeFirst();
                }
                this. = packet;
            } else {
                packet = this.;
            }
            // Process the packet. Catch and log any exception we may throw.
            try {
                processIncomingDataPacket(packet);
            } catch (Exception e) {
                .getStackLogger().logError(
                        "Error while processing incoming UDP packet"e);
            }
            if (. == -1) {
                return;
            }
        }
    }

    
Process an incoming datagram

Parameters:
packet is the incoming datagram packet.
    private void processIncomingDataPacket(DatagramPacket packet)
            throws Exception {
        this. = 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 (.isLoggingEnabled()) {
            this..getStackLogger()
                    .logDebug("UDPMessageChannel: processIncomingDataPacket : peerAddress = "
                            + .getHostAddress() + "/"
                            + packet.getPort() + " Length = " + packetLength);
        }
        SIPMessage sipMessage = null;
        try {
            this. = System.currentTimeMillis();
            sipMessage = .parseSIPMessage(msgBytes);
             = null;
        } catch (ParseException ex) {
             = null// let go of the parser reference.
            if (.isLoggingEnabled()) {
                this..getStackLogger().logDebug("Rejecting message !  "
                        + new String(msgBytes));
                this..getStackLogger().logDebug("error message "
                        + ex.getMessage());
                this..getStackLogger().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(msgStringex);
                if (badReqRes != null) {
                    if (.isLoggingEnabled()) {
                        .getStackLogger().logDebug(
                                "Sending automatic 400 Bad Request:");
                        .getStackLogger().logDebug(badReqRes);
                    }
                    try {
                        this.sendMessage(badReqRes.getBytes(), ,
                                packet.getPort(), "UDP"false);
                    } catch (IOException e) {
                        this..getStackLogger().logException(e);
                    }
                } else {
                    if (.isLoggingEnabled()) {
                        
                                .getStackLogger()
                                .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 (.isLoggingEnabled()) {
                this..getStackLogger().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 (.isLoggingEnabled()) {
                this..getStackLogger().logError("bad message " + badmsg);
                this..getStackLogger().logError(">>> Dropped Bad Msg "
                        + "From = " + sipMessage.getFrom() + "To = "
                        + sipMessage.getTo() + "CallId = "
                        + sipMessage.getCallId() + "CSeq = "
                        + sipMessage.getCSeq() + "Via = "
                        + sipMessage.getViaHeaders());
            }
            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 = (ViaviaList.getFirst();
            Hop hop = ..resolveAddress(v.getHop());
            this. = hop.getPort();
            this. = v.getTransport();
            this. = packet.getAddress();
            this. = packet.getPort();
            try {
                this. = packet.getAddress();
                // Check to see if the received parameter matches
                // the peer address and tag it appropriately.
                boolean hasRPort = v.hasParameter(.);
                if (hasRPort
                        || !hop.getHost().equals(
                                this..getHostAddress())) {
                    v.setParameter(.this.
                            .getHostAddress());
                }
                if (hasRPort) {
                    v.setParameter(., Integer
                            .toString(this.));
                }
            } catch (java.text.ParseException ex1) {
                InternalErrorHandler.handleException(ex1);
            }
        } else {
            this. = packet.getAddress();
            this. = packet.getPort();
            this. = packet.getAddress();
            this. = packet.getPort();
            this. = ((ViaviaList.getFirst()).getTransport();
        }
        this.processMessage(sipMessage);
    }

    
Actually proces the parsed message.

Parameters:
sipMessage
    public void processMessage(SIPMessage sipMessage) {
        if (sipMessage instanceof SIPRequest) {
            SIPRequest sipRequest = (SIPRequestsipMessage;
            // This is a request - process it.
            // So far so good -- we will commit this message if
            // all processing is OK.
                this...logMessage(sipMessagethis
                        .getPeerHostPort().toString(), this.getHost() + ":"
                        + this.false);
            }
            ServerRequestInterface sipServerRequest = 
                    .newSIPServerRequest(sipRequestthis);
            // Drop it if there is no request returned
            if (sipServerRequest == null) {
                if (.isLoggingEnabled()) {
                    this..getStackLogger()
                            .logWarning("Null request interface returned -- dropping request");
                }
                return;
            }
            if (.isLoggingEnabled())
                this..getStackLogger().logDebug("About to process "
                        + sipRequest.getFirstLine() + "/" + sipServerRequest);
            try {
                sipServerRequest.processRequest(sipRequestthis);
            } finally {
                if (sipServerRequest instanceof SIPTransaction) {
                    SIPServerTransaction sipServerTx = (SIPServerTransactionsipServerRequest;
                    if (!sipServerTx.passToListener()) {
                        ((SIPTransactionsipServerRequest).releaseSem();
                    }
                }
            }
            if (.isLoggingEnabled())
                this..getStackLogger().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 = (SIPResponsesipMessage;
            try {
                sipResponse.checkHeaders();
            } catch (ParseException ex) {
                if (.isLoggingEnabled())
                    .getStackLogger()
                            .logError("Dropping Badly formatted response message >>> "
                                    + sipResponse);
                return;
            }
            ServerResponseInterface sipServerResponse = 
                    .newSIPServerResponse(sipResponsethis);
            if (sipServerResponse != null) {
                try {
                    if (sipServerResponse instanceof SIPClientTransaction
                            && !((SIPClientTransactionsipServerResponse)
                                    .checkFromTag(sipResponse)) {
                        if (.isLoggingEnabled())
                            .getStackLogger()
                                    .logError("Dropping response message with invalid tag >>> "
                                            + sipResponse);
                        return;
                    }
                    sipServerResponse.processResponse(sipResponsethis);
                } finally {
                    if (sipServerResponse instanceof SIPTransaction
                            && !((SIPTransactionsipServerResponse)
                                    .passToListener())
                        ((SIPTransactionsipServerResponse).releaseSem();
                }
                // Normal processing of message.
            } else {
                if (.isLoggingEnabled()) {
                    this..getStackLogger().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.

Parameters:
ex Exception that is given to us by the parser.
Throws:
java.text.ParseException If we choose to reject the header or message.
    public void handleException(ParseException exSIPMessage sipMessage,
            Class hdrClassString headerString message)
            throws ParseException {
        if (.isLoggingEnabled())
            this..getStackLogger().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))) {
        	if (.isLoggingEnabled()) {
        		.getStackLogger().logError("BAD MESSAGE!");
            	.getStackLogger().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.

Parameters:
sipMessage Message string to send.
Throws:
java.io.IOException If there is a problem with sending the message.
    public void sendMessage(SIPMessage sipMessagethrows IOException {
        if (.isLoggingEnabled() && this..isLogStackTraceOnMessageSend()) {
            if ( sipMessage instanceof SIPRequest &&
                    ((SIPRequest)sipMessage).getRequestLine() != null) {
                /*
                 * We dont want to log empty trace messages.
                 */
                this..getStackLogger().logStackTrace(.);
            } else {
                this..getStackLogger().logStackTrace(.);
            }
        }
        // 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 : 
                    .getMessageProcessors()) {
                if (messageProcessor.getIpAddress().equals(this.)
                        && messageProcessor.getPort() == this.
                        && messageProcessor.getTransport().equals(
                                this.)) {
                    MessageChannel messageChannel = messageProcessor
                            .createMessageChannel(this.,
                                    this.);
                    if (messageChannel instanceof RawMessageChannel) {
                        ((RawMessageChannelmessageChannel)
                                .processMessage(sipMessage);
                        if (.isLoggingEnabled())
                        	.getStackLogger().logDebug("Self routing message");
                        return;
                    }
                }
            }
            byte[] msg = sipMessage.encodeAsBytesthis.getTransport() );
            sendMessage(msg,
                    sipMessage instanceof SIPRequest);
        } catch (IOException ex) {
            throw ex;
        } catch (Exception ex) {
            .getStackLogger().logError("An exception occured while sending message",ex);
            throw new IOException(
                    "An exception occured while sending message");
        } finally {
            if (.getStackLogger().isLoggingEnabled(.) && !sipMessage.isNullRequest())
                logMessage(sipMessagetime);
            else if (.getStackLogger().isLoggingEnabled(.))
                .getStackLogger().logDebug("Sent EMPTY Message");
        }
    }

    
Send a message to a specified receiver address.

Parameters:
msg string to send.
peerAddress Address of the place to send it to.
peerPort the port to send it to.
Throws:
java.io.IOException If there is trouble sending this message.
    protected void sendMessage(byte[] msgInetAddress peerAddress,
            int peerPortboolean reConnectthrows IOException {
        // Via is not included in the request so silently drop the reply.
        if (.isLoggingEnabled() && this..isLogStackTraceOnMessageSend() ) {
        }
        if (peerPort == -1) {
            if (.isLoggingEnabled()) {
                this..getStackLogger().logDebug(getClass().getName()
                        + ":sendMessage: Dropping reply!");
            }
            throw new IOException("Receiver port not set ");
        } else {
            if (.isLoggingEnabled()) {
                this..getStackLogger().logDebug("sendMessage " + peerAddress.getHostAddress() + "/"
                        + peerPort + "\n" + "messageSize =  "  + msg.length + " message = " + new String(msg)) ;
                this..getStackLogger().logDebug("*******************\n");
            }
        }
        DatagramPacket reply = new DatagramPacket(msgmsg.lengthpeerAddress,
                peerPort);
        try {
            DatagramSocket sock;
            boolean created = false;
            if (.) {
                // 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).;
                // 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.

Parameters:
msg message string to send.
peerAddress Address of the place to send it to.
peerPort the port to send it to.
peerProtocol protocol to use to send.
Throws:
java.io.IOException If there is trouble sending this message.
    protected void sendMessage(byte[] msgInetAddress peerAddress,
            int peerPortString peerProtocolboolean retry)
            throws IOException {
        // Via is not included in the request so silently drop the reply.
        if (peerPort == -1) {
            if (.isLoggingEnabled()) {
                this..getStackLogger().logDebug(getClass().getName()
                        + ":sendMessage: Dropping reply!");
            }
            throw new IOException("Receiver port not set ");
        } else {
            if (.isLoggingEnabled()) {
                this..getStackLogger().logDebug":sendMessage " + peerAddress.getHostAddress() + "/"
                        + peerPort + "\n" + " messageSize = " + msg.length);
            }
        }
        if (peerProtocol.compareToIgnoreCase("UDP") == 0) {
            DatagramPacket reply = new DatagramPacket(msgmsg.length,
                    peerAddresspeerPort);
            try {
                DatagramSocket sock;
                if (.) {
                    sock = ((UDPMessageProcessor).;
                } else {
                    // bind to any interface and port.
                    sock = .getNetworkLayer().createDatagramSocket();
                }
                if (.isLoggingEnabled()) {
                    this..getStackLogger().logDebug("sendMessage "
                            + peerAddress.getHostAddress() + "/" + peerPort
                            + "\n" + new String(msg));
                }
                sock.send(reply);
                if (!.)
                    sock.close();
            } catch (IOException ex) {
                throw ex;
            } catch (Exception ex) {
                InternalErrorHandler.handleException(ex);
            }
        } else {
            // Use TCP to talk back to the sender.
            Socket outputSocket = ..sendBytes(
                    this..getIpAddress(), peerAddress,
                    peerPort"tcp"msgretry,this);
            OutputStream myOutputStream = outputSocket.getOutputStream();
            myOutputStream.write(msg, 0, msg.length);
            myOutputStream.flush();
            // The socket is cached (dont close it!);
        }
    }

    
get the stack pointer.

Returns:
The sip stack for this channel.
    public SIPTransactionStack getSIPStack() {
        return ;
    }

    
Return a transport string.

Returns:
the string "udp" in this case.
    public String getTransport() {
        return .;
    }

    
get the stack address for the stack that received this message.

Returns:
The stack address for our sipStack.
    public String getHost() {
        return .getIpAddress().getHostAddress();
    }

    
get the port.

Returns:
Our port (on which we are getting datagram packets).
    public int getPort() {
        return ((UDPMessageProcessor).getPort();
    }

    
get the name (address) of the host that sent me the message

Returns:
The name of the sender (from the datagram packet).
    public String getPeerName() {
        return .getHostName();
    }

    
get the address of the host that sent me the message

Returns:
The senders ip address.
    public String getPeerAddress() {
        return .getHostAddress();
    }
    protected InetAddress getPeerInetAddress() {
        return ;
    }

    
Compare two UDP Message channels for equality.

Parameters:
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 = (UDPMessageChannelother;
            retval = this.getKey().equals(that.getKey());
        }
        return retval;
    }
    public String getKey() {
        return getKey("UDP");
    }
    public int getPeerPacketSourcePort() {
        return ;
    }
        return ;
    }

    
Get the logical originator of the message (from the top via header).

Returns:
topmost via header sentby field
    public String getViaHost() {
        return this.;
    }

    
Get the logical port of the message orginator (from the top via hdr).

Returns:
the via port from the topmost via header.
    public int getViaPort() {
        return this.;
    }

    
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 ;
    }
    public String getPeerProtocol() {
        return this.;
    }

    
Close the message channel.
    public void close() {
    }
New to GrepCode? Check out our FAQ X