1/*
2 * Conditions Of Use
3 *
4 * This software was developed by employees of the National Institute of
5 * Standards and Technology (NIST), an agency of the Federal Government.
6 * Pursuant to title 15 Untied States Code Section 105, works of NIST
7 * employees are not subject to copyright protection in the United States
8 * and are considered to be in the public domain.  As a result, a formal
9 * license is not needed to use the software.
10 *
11 * This software is provided by NIST as a service and is expressly
12 * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13 * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15 * AND DATA ACCURACY.  NIST does not warrant or make any representations
16 * regarding the use of the software or the results thereof, including but
17 * not limited to the correctness, accuracy, reliability or usefulness of
18 * the software.
19 *
20 * Permission to use this software is contingent upon your acceptance
21 * of the terms of this agreement
22 *
23 * .
24 *
25 */
26/*****************************************************************************
27 *   Product of NIST/ITL Advanced Networking Technologies Division (ANTD).    *
28 *****************************************************************************/
29
30package gov.nist.javax.sip.stack;
31
32import gov.nist.core.InternalErrorHandler;
33import gov.nist.core.ServerLogger;
34import gov.nist.core.StackLogger;
35import gov.nist.core.ThreadAuditor;
36import gov.nist.javax.sip.SIPConstants;
37import gov.nist.javax.sip.header.CSeq;
38import gov.nist.javax.sip.header.CallID;
39import gov.nist.javax.sip.header.From;
40import gov.nist.javax.sip.header.RequestLine;
41import gov.nist.javax.sip.header.StatusLine;
42import gov.nist.javax.sip.header.To;
43import gov.nist.javax.sip.header.Via;
44import gov.nist.javax.sip.header.ViaList;
45import gov.nist.javax.sip.message.SIPMessage;
46import gov.nist.javax.sip.message.SIPRequest;
47import gov.nist.javax.sip.message.SIPResponse;
48import gov.nist.javax.sip.parser.ParseExceptionListener;
49import gov.nist.javax.sip.parser.StringMsgParser;
50
51import java.io.IOException;
52import java.io.OutputStream;
53import java.net.DatagramPacket;
54import java.net.DatagramSocket;
55import java.net.InetAddress;
56import java.net.Socket;
57import java.text.ParseException;
58import java.util.HashSet;
59import java.util.Hashtable;
60import java.util.TimerTask;
61
62import javax.sip.address.Hop;
63
64/*
65 * Kim Kirby (Keyvoice) suggested that duplicate checking should be added to the
66 * stack (later removed). Lamine Brahimi suggested a single threaded behavior
67 * flag be added to this. Niklas Uhrberg suggested that thread pooling support
68 * be added to this for performance and resource management. Peter Parnes found
69 * a bug with this code that was sending it into an infinite loop when a bad
70 * incoming message was parsed. Bug fix by viswashanti.kadiyala@antepo.com.
71 * Hagai Sela addded fixes for NAT traversal. Jeroen van Bemmel fixed up for
72 * buggy clients (such as windows messenger) and added code to return
73 * BAD_REQUEST. David Alique fixed an address recording bug. Jeroen van Bemmel
74 * fixed a performance issue where the stack was doing DNS lookups (potentially
75 * unnecessary). Ricardo Bora (Natural Convergence ) added code that prevents
76 * the stack from exitting when an exception is encountered.
77 *
78 */
79
80/**
81 * This is the UDP Message handler that gets created when a UDP message needs to
82 * be processed. The message is processed by creating a String Message parser
83 * and invoking it on the message read from the UDP socket. The parsed structure
84 * is handed off via a SIP stack request for further processing. This stack
85 * structure isolates the message handling logic from the mechanics of sending
86 * and recieving messages (which could be either udp or tcp.
87 *
88 *
89 * @author M. Ranganathan <br/>
90 *
91 *
92 *
93 * @version 1.2 $Revision: 1.66 $ $Date: 2010/01/14 05:15:49 $
94 */
95public class UDPMessageChannel extends MessageChannel implements
96        ParseExceptionListener, Runnable, RawMessageChannel {
97
98
99    /**
100     * SIP Stack structure for this channel.
101     */
102    protected SIPTransactionStack sipStack;
103
104    /**
105     * The parser we are using for messages received from this channel.
106     */
107    protected StringMsgParser myParser;
108
109    /**
110     * Where we got the stuff from
111     */
112    private InetAddress peerAddress;
113
114    private String myAddress;
115
116    private int peerPacketSourcePort;
117
118    private InetAddress peerPacketSourceAddress;
119
120    /**
121     * Reciever port -- port of the destination.
122     */
123    private int peerPort;
124
125    /**
126     * Protocol to use when talking to receiver (i.e. when sending replies).
127     */
128    private String peerProtocol;
129
130    protected int myPort;
131
132    private DatagramPacket incomingPacket;
133
134    private long receptionTime;
135
136    /*
137     * A table that keeps track of when the last pingback was sent to a given remote IP address
138     * and port. This is for NAT compensation. This stays in the table for 1 seconds and prevents
139     * infinite loop. If a second pingback happens in that period of time, it will be dropped.
140     */
141    private Hashtable<String,PingBackTimerTask> pingBackRecord = new Hashtable<String,PingBackTimerTask>();
142
143    class PingBackTimerTask extends TimerTask {
144        String ipAddress;
145        int port;
146
147        public PingBackTimerTask(String ipAddress, int port) {
148            this.ipAddress = ipAddress;
149            this.port = port;
150            pingBackRecord.put(ipAddress + ":" + port, this);
151        }
152        @Override
153        public void run() {
154           pingBackRecord.remove(ipAddress + ":" + port);
155        }
156        @Override
157        public int hashCode() {
158            return (ipAddress + ":" + port).hashCode();
159        }
160    }
161
162    /**
163     * Constructor - takes a datagram packet and a stack structure Extracts the
164     * address of the other from the datagram packet and stashes away the
165     * pointer to the passed stack structure.
166     *
167     * @param stack
168     *            is the shared SIPStack structure
169     * @param messageProcessor
170     *            is the creating message processor.
171     */
172    protected UDPMessageChannel(SIPTransactionStack stack,
173            UDPMessageProcessor messageProcessor) {
174        super.messageProcessor = messageProcessor;
175        this.sipStack = stack;
176
177        Thread mythread = new Thread(this);
178
179        this.myAddress = messageProcessor.getIpAddress().getHostAddress();
180        this.myPort = messageProcessor.getPort();
181
182        mythread.setName("UDPMessageChannelThread");
183        mythread.setDaemon(true);
184        mythread.start();
185
186    }
187
188    /**
189     * Constructor. We create one of these in order to process an incoming
190     * message.
191     *
192     * @param stack
193     *            is the SIP sipStack.
194     * @param messageProcessor
195     *            is the creating message processor.
196     * @param packet
197     *            is the incoming datagram packet.
198     */
199    protected UDPMessageChannel(SIPTransactionStack stack,
200            UDPMessageProcessor messageProcessor, DatagramPacket packet) {
201
202        this.incomingPacket = packet;
203        super.messageProcessor = messageProcessor;
204        this.sipStack = stack;
205
206        this.myAddress = messageProcessor.getIpAddress().getHostAddress();
207        this.myPort = messageProcessor.getPort();
208        Thread mythread = new Thread(this);
209        mythread.setDaemon(true);
210        mythread.setName("UDPMessageChannelThread");
211
212        mythread.start();
213
214    }
215
216    /**
217     * Constructor. We create one of these when we send out a message.
218     *
219     * @param targetAddr
220     *            INET address of the place where we want to send messages.
221     * @param port
222     *            target port (where we want to send the message).
223     * @param sipStack
224     *            our SIP Stack.
225     */
226    protected UDPMessageChannel(InetAddress targetAddr, int port,
227            SIPTransactionStack sipStack, UDPMessageProcessor messageProcessor) {
228        peerAddress = targetAddr;
229        peerPort = port;
230        peerProtocol = "UDP";
231        super.messageProcessor = messageProcessor;
232        this.myAddress = messageProcessor.getIpAddress().getHostAddress();
233        this.myPort = messageProcessor.getPort();
234        this.sipStack = sipStack;
235        if (sipStack.isLoggingEnabled()) {
236            this.sipStack.getStackLogger().logDebug("Creating message channel "
237                    + targetAddr.getHostAddress() + "/" + port);
238        }
239    }
240
241    /**
242     * Run method specified by runnnable.
243     */
244    public void run() {
245        // Assume no thread pooling (bug fix by spierhj)
246        ThreadAuditor.ThreadHandle threadHandle = null;
247
248        while (true) {
249            // Create a new string message parser to parse the list of messages.
250            if (myParser == null) {
251                myParser = new StringMsgParser();
252                myParser.setParseExceptionListener(this);
253            }
254            // messages that we write out to him.
255            DatagramPacket packet;
256
257            if (sipStack.threadPoolSize != -1) {
258                synchronized (((UDPMessageProcessor) messageProcessor).messageQueue) {
259                    while (((UDPMessageProcessor) messageProcessor).messageQueue
260                            .isEmpty()) {
261                        // Check to see if we need to exit.
262                        if (!((UDPMessageProcessor) messageProcessor).isRunning)
263                            return;
264                        try {
265                            // We're part of a thread pool. Ask the auditor to
266                            // monitor this thread.
267                            if (threadHandle == null) {
268                                threadHandle = sipStack.getThreadAuditor()
269                                        .addCurrentThread();
270                            }
271
272                            // Send a heartbeat to the thread auditor
273                            threadHandle.ping();
274
275                            // Wait for packets
276                            // Note: getPingInterval returns 0 (infinite) if the
277                            // thread auditor is disabled.
278                            ((UDPMessageProcessor) messageProcessor).messageQueue
279                                    .wait(threadHandle
280                                            .getPingIntervalInMillisecs());
281                        } catch (InterruptedException ex) {
282                            if (!((UDPMessageProcessor) messageProcessor).isRunning)
283                                return;
284                        }
285                    }
286                    packet = (DatagramPacket) ((UDPMessageProcessor) messageProcessor).messageQueue
287                            .removeFirst();
288
289                }
290                this.incomingPacket = packet;
291            } else {
292                packet = this.incomingPacket;
293            }
294
295            // Process the packet. Catch and log any exception we may throw.
296            try {
297                processIncomingDataPacket(packet);
298            } catch (Exception e) {
299
300                sipStack.getStackLogger().logError(
301                        "Error while processing incoming UDP packet", e);
302            }
303
304            if (sipStack.threadPoolSize == -1) {
305                return;
306            }
307        }
308    }
309
310    /**
311     * Process an incoming datagram
312     *
313     * @param packet
314     *            is the incoming datagram packet.
315     */
316    private void processIncomingDataPacket(DatagramPacket packet)
317            throws Exception {
318        this.peerAddress = packet.getAddress();
319        int packetLength = packet.getLength();
320        // Read bytes and put it in a eueue.
321        byte[] bytes = packet.getData();
322        byte[] msgBytes = new byte[packetLength];
323        System.arraycopy(bytes, 0, msgBytes, 0, packetLength);
324
325        // Do debug logging.
326        if (sipStack.isLoggingEnabled()) {
327            this.sipStack.getStackLogger()
328                    .logDebug("UDPMessageChannel: processIncomingDataPacket : peerAddress = "
329                            + peerAddress.getHostAddress() + "/"
330                            + packet.getPort() + " Length = " + packetLength);
331
332        }
333
334        SIPMessage sipMessage = null;
335        try {
336            this.receptionTime = System.currentTimeMillis();
337            sipMessage = myParser.parseSIPMessage(msgBytes);
338            myParser = null;
339        } catch (ParseException ex) {
340            myParser = null; // let go of the parser reference.
341            if (sipStack.isLoggingEnabled()) {
342                this.sipStack.getStackLogger().logDebug("Rejecting message !  "
343                        + new String(msgBytes));
344                this.sipStack.getStackLogger().logDebug("error message "
345                        + ex.getMessage());
346                this.sipStack.getStackLogger().logException(ex);
347            }
348
349
350            // JvB: send a 400 response for requests (except ACK)
351            // Currently only UDP, @todo also other transports
352            String msgString = new String(msgBytes, 0, packetLength);
353            if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) {
354
355                String badReqRes = createBadReqRes(msgString, ex);
356                if (badReqRes != null) {
357                    if (sipStack.isLoggingEnabled()) {
358                        sipStack.getStackLogger().logDebug(
359                                "Sending automatic 400 Bad Request:");
360                        sipStack.getStackLogger().logDebug(badReqRes);
361                    }
362                    try {
363                        this.sendMessage(badReqRes.getBytes(), peerAddress,
364                                packet.getPort(), "UDP", false);
365                    } catch (IOException e) {
366                        this.sipStack.getStackLogger().logException(e);
367                    }
368                } else {
369                    if (sipStack.isLoggingEnabled()) {
370                        sipStack
371                                .getStackLogger()
372                                .logDebug(
373                                        "Could not formulate automatic 400 Bad Request");
374                    }
375                }
376            }
377
378            return;
379        }
380        // No parse exception but null message - reject it and
381        // march on (or return).
382        // exit this message processor if the message did not parse.
383
384        if (sipMessage == null) {
385            if (sipStack.isLoggingEnabled()) {
386                this.sipStack.getStackLogger().logDebug("Rejecting message !  + Null message parsed.");
387            }
388            if (pingBackRecord.get(packet.getAddress().getHostAddress() + ":" + packet.getPort()) == null ) {
389                byte[] retval = "\r\n\r\n".getBytes();
390                DatagramPacket keepalive = new DatagramPacket(retval,0,retval.length,packet.getAddress(),packet.getPort());
391                ((UDPMessageProcessor)this.messageProcessor).sock.send(keepalive);
392                this.sipStack.getTimer().schedule(new PingBackTimerTask(packet.getAddress().getHostAddress(),
393                            packet.getPort()), 1000);
394            }
395            return;
396        }
397        ViaList viaList = sipMessage.getViaHeaders();
398        // Check for the required headers.
399        if (sipMessage.getFrom() == null || sipMessage.getTo() == null
400                || sipMessage.getCallId() == null
401                || sipMessage.getCSeq() == null
402                || sipMessage.getViaHeaders() == null) {
403            String badmsg = new String(msgBytes);
404            if (sipStack.isLoggingEnabled()) {
405                this.sipStack.getStackLogger().logError("bad message " + badmsg);
406                this.sipStack.getStackLogger().logError(">>> Dropped Bad Msg "
407                        + "From = " + sipMessage.getFrom() + "To = "
408                        + sipMessage.getTo() + "CallId = "
409                        + sipMessage.getCallId() + "CSeq = "
410                        + sipMessage.getCSeq() + "Via = "
411                        + sipMessage.getViaHeaders());
412            }
413            return;
414        }
415        // For a request first via header tells where the message
416        // is coming from.
417        // For response, just get the port from the packet.
418        if (sipMessage instanceof SIPRequest) {
419            Via v = (Via) viaList.getFirst();
420            Hop hop = sipStack.addressResolver.resolveAddress(v.getHop());
421            this.peerPort = hop.getPort();
422            this.peerProtocol = v.getTransport();
423
424            this.peerPacketSourceAddress = packet.getAddress();
425            this.peerPacketSourcePort = packet.getPort();
426            try {
427                this.peerAddress = packet.getAddress();
428                // Check to see if the received parameter matches
429                // the peer address and tag it appropriately.
430
431
432                boolean hasRPort = v.hasParameter(Via.RPORT);
433                if (hasRPort
434                        || !hop.getHost().equals(
435                                this.peerAddress.getHostAddress())) {
436                    v.setParameter(Via.RECEIVED, this.peerAddress
437                            .getHostAddress());
438                }
439
440                if (hasRPort) {
441                    v.setParameter(Via.RPORT, Integer
442                            .toString(this.peerPacketSourcePort));
443                }
444            } catch (java.text.ParseException ex1) {
445                InternalErrorHandler.handleException(ex1);
446            }
447
448        } else {
449
450            this.peerPacketSourceAddress = packet.getAddress();
451            this.peerPacketSourcePort = packet.getPort();
452            this.peerAddress = packet.getAddress();
453            this.peerPort = packet.getPort();
454            this.peerProtocol = ((Via) viaList.getFirst()).getTransport();
455        }
456
457        this.processMessage(sipMessage);
458
459    }
460
461    /**
462     * Actually proces the parsed message.
463     *
464     * @param sipMessage
465     */
466    public void processMessage(SIPMessage sipMessage) {
467
468        if (sipMessage instanceof SIPRequest) {
469            SIPRequest sipRequest = (SIPRequest) sipMessage;
470
471            // This is a request - process it.
472            // So far so good -- we will commit this message if
473            // all processing is OK.
474            if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) {
475
476                this.sipStack.serverLogger.logMessage(sipMessage, this
477                        .getPeerHostPort().toString(), this.getHost() + ":"
478                        + this.myPort, false, receptionTime);
479
480            }
481            ServerRequestInterface sipServerRequest = sipStack
482                    .newSIPServerRequest(sipRequest, this);
483            // Drop it if there is no request returned
484            if (sipServerRequest == null) {
485                if (sipStack.isLoggingEnabled()) {
486                    this.sipStack.getStackLogger()
487                            .logWarning("Null request interface returned -- dropping request");
488                }
489
490
491                return;
492            }
493            if (sipStack.isLoggingEnabled())
494                this.sipStack.getStackLogger().logDebug("About to process "
495                        + sipRequest.getFirstLine() + "/" + sipServerRequest);
496            try {
497                sipServerRequest.processRequest(sipRequest, this);
498            } finally {
499                if (sipServerRequest instanceof SIPTransaction) {
500                    SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest;
501                    if (!sipServerTx.passToListener()) {
502                        ((SIPTransaction) sipServerRequest).releaseSem();
503                    }
504                }
505            }
506            if (sipStack.isLoggingEnabled())
507                this.sipStack.getStackLogger().logDebug("Done processing "
508                        + sipRequest.getFirstLine() + "/" + sipServerRequest);
509
510            // So far so good -- we will commit this message if
511            // all processing is OK.
512
513        } else {
514            // Handle a SIP Reply message.
515            SIPResponse sipResponse = (SIPResponse) sipMessage;
516            try {
517                sipResponse.checkHeaders();
518            } catch (ParseException ex) {
519                if (sipStack.isLoggingEnabled())
520                    sipStack.getStackLogger()
521                            .logError("Dropping Badly formatted response message >>> "
522                                    + sipResponse);
523                return;
524            }
525            ServerResponseInterface sipServerResponse = sipStack
526                    .newSIPServerResponse(sipResponse, this);
527            if (sipServerResponse != null) {
528                try {
529                    if (sipServerResponse instanceof SIPClientTransaction
530                            && !((SIPClientTransaction) sipServerResponse)
531                                    .checkFromTag(sipResponse)) {
532                        if (sipStack.isLoggingEnabled())
533                            sipStack.getStackLogger()
534                                    .logError("Dropping response message with invalid tag >>> "
535                                            + sipResponse);
536                        return;
537                    }
538
539                    sipServerResponse.processResponse(sipResponse, this);
540                } finally {
541                    if (sipServerResponse instanceof SIPTransaction
542                            && !((SIPTransaction) sipServerResponse)
543                                    .passToListener())
544                        ((SIPTransaction) sipServerResponse).releaseSem();
545                }
546
547                // Normal processing of message.
548            } else {
549                if (sipStack.isLoggingEnabled()) {
550                    this.sipStack.getStackLogger().logDebug("null sipServerResponse!");
551                }
552            }
553
554        }
555    }
556
557    /**
558     * JvB: added method to check for known buggy clients (Windows Messenger) to
559     * fix the port to which responses are sent
560     *
561     * checks for User-Agent: RTC/1.3.5470 (Messenger 5.1.0701)
562     *
563     * JvB 22/7/2006 better to take this out for the moment, it is only a
564     * problem in rare cases (unregister)
565     *
566     * private final boolean isBuggyClient( SIPRequest r ) { UserAgent uah =
567     * (UserAgent) r.getHeader( UserAgent.NAME ); if (uah!=null) {
568     * java.util.ListIterator i = uah.getProduct(); if (i.hasNext()) { String p =
569     * (String) uah.getProduct().next(); return p.startsWith( "RTC" ); } }
570     * return false; }
571     */
572
573    /**
574     * Implementation of the ParseExceptionListener interface.
575     *
576     * @param ex
577     *            Exception that is given to us by the parser.
578     * @throws ParseException
579     *             If we choose to reject the header or message.
580     */
581    public void handleException(ParseException ex, SIPMessage sipMessage,
582            Class hdrClass, String header, String message)
583            throws ParseException {
584        if (sipStack.isLoggingEnabled())
585            this.sipStack.getStackLogger().logException(ex);
586        // Log the bad message for later reference.
587        if ((hdrClass != null)
588                && (hdrClass.equals(From.class) || hdrClass.equals(To.class)
589                        || hdrClass.equals(CSeq.class)
590                        || hdrClass.equals(Via.class)
591                        || hdrClass.equals(CallID.class)
592                        || hdrClass.equals(RequestLine.class) || hdrClass
593                        .equals(StatusLine.class))) {
594        	if (sipStack.isLoggingEnabled()) {
595        		sipStack.getStackLogger().logError("BAD MESSAGE!");
596            	sipStack.getStackLogger().logError(message);
597        	}
598            throw ex;
599        } else {
600            sipMessage.addUnparsed(header);
601        }
602    }
603
604    /**
605     * Return a reply from a pre-constructed reply. This sends the message back
606     * to the entity who caused us to create this channel in the first place.
607     *
608     * @param sipMessage
609     *            Message string to send.
610     * @throws IOException
611     *             If there is a problem with sending the message.
612     */
613    public void sendMessage(SIPMessage sipMessage) throws IOException {
614        if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend()) {
615            if ( sipMessage instanceof SIPRequest &&
616                    ((SIPRequest)sipMessage).getRequestLine() != null) {
617                /*
618                 * We dont want to log empty trace messages.
619                 */
620                this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO);
621            } else {
622                this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO);
623            }
624        }
625
626        // Test and see where we are going to send the messsage. If the message
627        // is sent back to oursleves, just
628        // shortcircuit processing.
629        long time = System.currentTimeMillis();
630        try {
631            for (MessageProcessor messageProcessor : sipStack
632                    .getMessageProcessors()) {
633                if (messageProcessor.getIpAddress().equals(this.peerAddress)
634                        && messageProcessor.getPort() == this.peerPort
635                        && messageProcessor.getTransport().equals(
636                                this.peerProtocol)) {
637                    MessageChannel messageChannel = messageProcessor
638                            .createMessageChannel(this.peerAddress,
639                                    this.peerPort);
640                    if (messageChannel instanceof RawMessageChannel) {
641                        ((RawMessageChannel) messageChannel)
642                                .processMessage(sipMessage);
643                        if (sipStack.isLoggingEnabled())
644                        	sipStack.getStackLogger().logDebug("Self routing message");
645                        return;
646                    }
647
648                }
649            }
650
651            byte[] msg = sipMessage.encodeAsBytes( this.getTransport() );
652
653            sendMessage(msg, peerAddress, peerPort, peerProtocol,
654                    sipMessage instanceof SIPRequest);
655
656        } catch (IOException ex) {
657            throw ex;
658        } catch (Exception ex) {
659            sipStack.getStackLogger().logError("An exception occured while sending message",ex);
660            throw new IOException(
661                    "An exception occured while sending message");
662        } finally {
663            if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES) && !sipMessage.isNullRequest())
664                logMessage(sipMessage, peerAddress, peerPort, time);
665            else if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_DEBUG))
666                sipStack.getStackLogger().logDebug("Sent EMPTY Message");
667        }
668    }
669
670    /**
671     * Send a message to a specified receiver address.
672     *
673     * @param msg
674     *            string to send.
675     * @param peerAddress
676     *            Address of the place to send it to.
677     * @param peerPort
678     *            the port to send it to.
679     * @throws IOException
680     *             If there is trouble sending this message.
681     */
682    protected void sendMessage(byte[] msg, InetAddress peerAddress,
683            int peerPort, boolean reConnect) throws IOException {
684        // Via is not included in the request so silently drop the reply.
685        if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend() ) {
686            this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO);
687        }
688        if (peerPort == -1) {
689            if (sipStack.isLoggingEnabled()) {
690                this.sipStack.getStackLogger().logDebug(getClass().getName()
691                        + ":sendMessage: Dropping reply!");
692            }
693            throw new IOException("Receiver port not set ");
694        } else {
695            if (sipStack.isLoggingEnabled()) {
696                this.sipStack.getStackLogger().logDebug("sendMessage " + peerAddress.getHostAddress() + "/"
697                        + peerPort + "\n" + "messageSize =  "  + msg.length + " message = " + new String(msg)) ;
698                this.sipStack.getStackLogger().logDebug("*******************\n");
699            }
700
701        }
702        DatagramPacket reply = new DatagramPacket(msg, msg.length, peerAddress,
703                peerPort);
704        try {
705            DatagramSocket sock;
706            boolean created = false;
707
708            if (sipStack.udpFlag) {
709                // Use the socket from the message processor (for firewall
710                // support use the same socket as the message processor
711                // socket -- feature request # 18 from java.net). This also
712                // makes the whole thing run faster!
713                sock = ((UDPMessageProcessor) messageProcessor).sock;
714
715                // Bind the socket to the stack address in case there
716                // are multiple interfaces on the machine (feature reqeust
717                // by Will Scullin) 0 binds to an ephemeral port.
718                // sock = new DatagramSocket(0,sipStack.stackInetAddress);
719            } else {
720                // bind to any interface and port.
721                sock = new DatagramSocket();
722                created = true;
723            }
724            sock.send(reply);
725            if (created)
726                sock.close();
727        } catch (IOException ex) {
728            throw ex;
729        } catch (Exception ex) {
730            InternalErrorHandler.handleException(ex);
731        }
732    }
733
734    /**
735     * Send a message to a specified receiver address.
736     *
737     * @param msg
738     *            message string to send.
739     * @param peerAddress
740     *            Address of the place to send it to.
741     * @param peerPort
742     *            the port to send it to.
743     * @param peerProtocol
744     *            protocol to use to send.
745     * @throws IOException
746     *             If there is trouble sending this message.
747     */
748    protected void sendMessage(byte[] msg, InetAddress peerAddress,
749            int peerPort, String peerProtocol, boolean retry)
750            throws IOException {
751        // Via is not included in the request so silently drop the reply.
752        if (peerPort == -1) {
753            if (sipStack.isLoggingEnabled()) {
754                this.sipStack.getStackLogger().logDebug(getClass().getName()
755                        + ":sendMessage: Dropping reply!");
756            }
757            throw new IOException("Receiver port not set ");
758        } else {
759            if (sipStack.isLoggingEnabled()) {
760                this.sipStack.getStackLogger().logDebug( ":sendMessage " + peerAddress.getHostAddress() + "/"
761                        + peerPort + "\n" + " messageSize = " + msg.length);
762            }
763        }
764        if (peerProtocol.compareToIgnoreCase("UDP") == 0) {
765            DatagramPacket reply = new DatagramPacket(msg, msg.length,
766                    peerAddress, peerPort);
767
768            try {
769                DatagramSocket sock;
770                if (sipStack.udpFlag) {
771                    sock = ((UDPMessageProcessor) messageProcessor).sock;
772
773                } else {
774                    // bind to any interface and port.
775                    sock = sipStack.getNetworkLayer().createDatagramSocket();
776                }
777                if (sipStack.isLoggingEnabled()) {
778                    this.sipStack.getStackLogger().logDebug("sendMessage "
779                            + peerAddress.getHostAddress() + "/" + peerPort
780                            + "\n" + new String(msg));
781                }
782                sock.send(reply);
783                if (!sipStack.udpFlag)
784                    sock.close();
785            } catch (IOException ex) {
786                throw ex;
787            } catch (Exception ex) {
788                InternalErrorHandler.handleException(ex);
789            }
790
791        } else {
792            // Use TCP to talk back to the sender.
793            Socket outputSocket = sipStack.ioHandler.sendBytes(
794                    this.messageProcessor.getIpAddress(), peerAddress,
795                    peerPort, "tcp", msg, retry,this);
796            OutputStream myOutputStream = outputSocket.getOutputStream();
797            myOutputStream.write(msg, 0, msg.length);
798            myOutputStream.flush();
799            // The socket is cached (dont close it!);
800        }
801    }
802
803    /**
804     * get the stack pointer.
805     *
806     * @return The sip stack for this channel.
807     */
808    public SIPTransactionStack getSIPStack() {
809        return sipStack;
810    }
811
812    /**
813     * Return a transport string.
814     *
815     * @return the string "udp" in this case.
816     */
817    public String getTransport() {
818        return SIPConstants.UDP;
819    }
820
821    /**
822     * get the stack address for the stack that received this message.
823     *
824     * @return The stack address for our sipStack.
825     */
826    public String getHost() {
827        return messageProcessor.getIpAddress().getHostAddress();
828    }
829
830    /**
831     * get the port.
832     *
833     * @return Our port (on which we are getting datagram packets).
834     */
835    public int getPort() {
836        return ((UDPMessageProcessor) messageProcessor).getPort();
837    }
838
839    /**
840     * get the name (address) of the host that sent me the message
841     *
842     * @return The name of the sender (from the datagram packet).
843     */
844    public String getPeerName() {
845        return peerAddress.getHostName();
846    }
847
848    /**
849     * get the address of the host that sent me the message
850     *
851     * @return The senders ip address.
852     */
853    public String getPeerAddress() {
854        return peerAddress.getHostAddress();
855    }
856
857    protected InetAddress getPeerInetAddress() {
858        return peerAddress;
859    }
860
861    /**
862     * Compare two UDP Message channels for equality.
863     *
864     * @param other
865     *            The other message channel with which to compare oursleves.
866     */
867    public boolean equals(Object other) {
868
869        if (other == null)
870            return false;
871        boolean retval;
872        if (!this.getClass().equals(other.getClass())) {
873            retval = false;
874        } else {
875            UDPMessageChannel that = (UDPMessageChannel) other;
876            retval = this.getKey().equals(that.getKey());
877        }
878
879        return retval;
880    }
881
882    public String getKey() {
883        return getKey(peerAddress, peerPort, "UDP");
884    }
885
886    public int getPeerPacketSourcePort() {
887        return peerPacketSourcePort;
888    }
889
890    public InetAddress getPeerPacketSourceAddress() {
891        return peerPacketSourceAddress;
892    }
893
894    /**
895     * Get the logical originator of the message (from the top via header).
896     *
897     * @return topmost via header sentby field
898     */
899    public String getViaHost() {
900        return this.myAddress;
901    }
902
903    /**
904     * Get the logical port of the message orginator (from the top via hdr).
905     *
906     * @return the via port from the topmost via header.
907     */
908    public int getViaPort() {
909        return this.myPort;
910    }
911
912    /**
913     * Returns "false" as this is an unreliable transport.
914     */
915    public boolean isReliable() {
916        return false;
917    }
918
919    /**
920     * UDP is not a secure protocol.
921     */
922    public boolean isSecure() {
923        return false;
924    }
925
926    public int getPeerPort() {
927        return peerPort;
928    }
929
930    public String getPeerProtocol() {
931        return this.peerProtocol;
932    }
933
934    /**
935     * Close the message channel.
936     */
937    public void close() {
938    }
939
940
941}
942