• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
30 package gov.nist.javax.sip.stack;
31 
32 import gov.nist.core.InternalErrorHandler;
33 import gov.nist.core.ServerLogger;
34 import gov.nist.core.StackLogger;
35 import gov.nist.core.ThreadAuditor;
36 import gov.nist.javax.sip.SIPConstants;
37 import gov.nist.javax.sip.header.CSeq;
38 import gov.nist.javax.sip.header.CallID;
39 import gov.nist.javax.sip.header.From;
40 import gov.nist.javax.sip.header.RequestLine;
41 import gov.nist.javax.sip.header.StatusLine;
42 import gov.nist.javax.sip.header.To;
43 import gov.nist.javax.sip.header.Via;
44 import gov.nist.javax.sip.header.ViaList;
45 import gov.nist.javax.sip.message.SIPMessage;
46 import gov.nist.javax.sip.message.SIPRequest;
47 import gov.nist.javax.sip.message.SIPResponse;
48 import gov.nist.javax.sip.parser.ParseExceptionListener;
49 import gov.nist.javax.sip.parser.StringMsgParser;
50 
51 import java.io.IOException;
52 import java.io.OutputStream;
53 import java.net.DatagramPacket;
54 import java.net.DatagramSocket;
55 import java.net.InetAddress;
56 import java.net.Socket;
57 import java.text.ParseException;
58 import java.util.HashSet;
59 import java.util.Hashtable;
60 import java.util.TimerTask;
61 
62 import 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  */
95 public 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 
PingBackTimerTask(String ipAddress, int port)147         public PingBackTimerTask(String ipAddress, int port) {
148             this.ipAddress = ipAddress;
149             this.port = port;
150             pingBackRecord.put(ipAddress + ":" + port, this);
151         }
152         @Override
run()153         public void run() {
154            pingBackRecord.remove(ipAddress + ":" + port);
155         }
156         @Override
hashCode()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      */
UDPMessageChannel(SIPTransactionStack stack, UDPMessageProcessor messageProcessor)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      */
UDPMessageChannel(SIPTransactionStack stack, UDPMessageProcessor messageProcessor, DatagramPacket packet)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      */
UDPMessageChannel(InetAddress targetAddr, int port, SIPTransactionStack sipStack, UDPMessageProcessor messageProcessor)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      */
run()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      */
processIncomingDataPacket(DatagramPacket packet)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      */
processMessage(SIPMessage sipMessage)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      */
handleException(ParseException ex, SIPMessage sipMessage, Class hdrClass, String header, String message)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      */
sendMessage(SIPMessage sipMessage)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      */
sendMessage(byte[] msg, InetAddress peerAddress, int peerPort, boolean reConnect)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      */
sendMessage(byte[] msg, InetAddress peerAddress, int peerPort, String peerProtocol, boolean retry)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      */
getSIPStack()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      */
getTransport()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      */
getHost()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      */
getPort()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      */
getPeerName()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      */
getPeerAddress()853     public String getPeerAddress() {
854         return peerAddress.getHostAddress();
855     }
856 
getPeerInetAddress()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      */
equals(Object other)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 
getKey()882     public String getKey() {
883         return getKey(peerAddress, peerPort, "UDP");
884     }
885 
getPeerPacketSourcePort()886     public int getPeerPacketSourcePort() {
887         return peerPacketSourcePort;
888     }
889 
getPeerPacketSourceAddress()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      */
getViaHost()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      */
getViaPort()908     public int getViaPort() {
909         return this.myPort;
910     }
911 
912     /**
913      * Returns "false" as this is an unreliable transport.
914      */
isReliable()915     public boolean isReliable() {
916         return false;
917     }
918 
919     /**
920      * UDP is not a secure protocol.
921      */
isSecure()922     public boolean isSecure() {
923         return false;
924     }
925 
getPeerPort()926     public int getPeerPort() {
927         return peerPort;
928     }
929 
getPeerProtocol()930     public String getPeerProtocol() {
931         return this.peerProtocol;
932     }
933 
934     /**
935      * Close the message channel.
936      */
close()937     public void close() {
938     }
939 
940 
941 }
942