• 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.Host;
33 import gov.nist.core.HostPort;
34 import gov.nist.core.InternalErrorHandler;
35 import gov.nist.core.ServerLogger;
36 import gov.nist.javax.sip.address.AddressImpl;
37 import gov.nist.javax.sip.header.ContentLength;
38 import gov.nist.javax.sip.header.ContentType;
39 import gov.nist.javax.sip.header.Via;
40 import gov.nist.javax.sip.message.MessageFactoryImpl;
41 import gov.nist.javax.sip.message.SIPMessage;
42 import gov.nist.javax.sip.message.SIPRequest;
43 import gov.nist.javax.sip.message.SIPResponse;
44 
45 import java.io.IOException;
46 import java.net.InetAddress;
47 import java.text.ParseException;
48 
49 import javax.sip.address.Hop;
50 import javax.sip.header.CSeqHeader;
51 import javax.sip.header.CallIdHeader;
52 import javax.sip.header.ContactHeader;
53 import javax.sip.header.ContentLengthHeader;
54 import javax.sip.header.ContentTypeHeader;
55 import javax.sip.header.FromHeader;
56 import javax.sip.header.ServerHeader;
57 import javax.sip.header.ToHeader;
58 import javax.sip.header.ViaHeader;
59 
60 /**
61  * Message channel abstraction for the SIP stack.
62  *
63  * @author M. Ranganathan <br/> Contains additions for support of symmetric NAT contributed by
64  *         Hagai.
65  *
66  * @version 1.2 $Revision: 1.28 $ $Date: 2009/11/14 20:06:18 $
67  *
68  *
69  */
70 public abstract class MessageChannel {
71 
72     // Incremented whenever a transaction gets assigned
73     // to the message channel and decremented when
74     // a transaction gets freed from the message channel.
75 	protected int useCount;
76 
77 	/**
78 	 * Hook method, overridden by subclasses
79 	 */
uncache()80 	protected void uncache() {}
81 
82     /**
83      * Message processor to whom I belong (if set).
84      */
85     protected transient MessageProcessor messageProcessor;
86 
87     /**
88      * Close the message channel.
89      */
close()90     public abstract void close();
91 
92     /**
93      * Get the SIPStack object from this message channel.
94      *
95      * @return SIPStack object of this message channel
96      */
getSIPStack()97     public abstract SIPTransactionStack getSIPStack();
98 
99     /**
100      * Get transport string of this message channel.
101      *
102      * @return Transport string of this message channel.
103      */
getTransport()104     public abstract String getTransport();
105 
106     /**
107      * Get whether this channel is reliable or not.
108      *
109      * @return True if reliable, false if not.
110      */
isReliable()111     public abstract boolean isReliable();
112 
113     /**
114      * Return true if this is a secure channel.
115      */
isSecure()116     public abstract boolean isSecure();
117 
118     /**
119      * Send the message (after it has been formatted)
120      *
121      * @param sipMessage Message to send.
122      */
sendMessage(SIPMessage sipMessage)123     public abstract void sendMessage(SIPMessage sipMessage) throws IOException;
124 
125     /**
126      * Get the peer address of the machine that sent us this message.
127      *
128      * @return a string contianing the ip address or host name of the sender of the message.
129      */
getPeerAddress()130     public abstract String getPeerAddress();
131 
getPeerInetAddress()132     protected abstract InetAddress getPeerInetAddress();
133 
getPeerProtocol()134     protected abstract String getPeerProtocol();
135 
136     /**
137      * Get the sender port ( the port of the other end that sent me the message).
138      */
getPeerPort()139     public abstract int getPeerPort();
140 
getPeerPacketSourcePort()141     public abstract int getPeerPacketSourcePort();
142 
getPeerPacketSourceAddress()143     public abstract InetAddress getPeerPacketSourceAddress();
144 
145     /**
146      * Generate a key which identifies the message channel. This allows us to cache the message
147      * channel.
148      */
getKey()149     public abstract String getKey();
150 
151     /**
152      * Get the host to assign for an outgoing Request via header.
153      */
getViaHost()154     public abstract String getViaHost();
155 
156     /**
157      * Get the port to assign for the via header of an outgoing message.
158      */
getViaPort()159     public abstract int getViaPort();
160 
161     /**
162      * Send the message (after it has been formatted), to a specified address and a specified port
163      *
164      * @param message Message to send.
165      * @param receiverAddress Address of the receiver.
166      * @param receiverPort Port of the receiver.
167      */
sendMessage(byte[] message, InetAddress receiverAddress, int receiverPort, boolean reconnectFlag)168     protected abstract void sendMessage(byte[] message, InetAddress receiverAddress,
169             int receiverPort, boolean reconnectFlag) throws IOException;
170 
171     /**
172      * Get the host of this message channel.
173      *
174      * @return host of this messsage channel.
175      */
getHost()176     public String getHost() {
177         return this.getMessageProcessor().getIpAddress().getHostAddress();
178     }
179 
180     /**
181      * Get port of this message channel.
182      *
183      * @return Port of this message channel.
184      */
getPort()185     public int getPort() {
186         if (this.messageProcessor != null)
187             return messageProcessor.getPort();
188         else
189             return -1;
190     }
191 
192     /**
193      * Send a formatted message to the specified target.
194      *
195      * @param sipMessage Message to send.
196      * @param hop hop to send it to.
197      * @throws IOException If there is an error sending the message
198      */
sendMessage(SIPMessage sipMessage, Hop hop)199     public void sendMessage(SIPMessage sipMessage, Hop hop) throws IOException {
200         long time = System.currentTimeMillis();
201         InetAddress hopAddr = InetAddress.getByName(hop.getHost());
202 
203         try {
204 
205             for (MessageProcessor messageProcessor : getSIPStack().getMessageProcessors()) {
206                 if (messageProcessor.getIpAddress().equals(hopAddr)
207                         && messageProcessor.getPort() == hop.getPort()
208                         && messageProcessor.getTransport().equals(hop.getTransport())) {
209                     MessageChannel messageChannel = messageProcessor.createMessageChannel(
210                             hopAddr, hop.getPort());
211                     if (messageChannel instanceof RawMessageChannel) {
212                         ((RawMessageChannel) messageChannel).processMessage(sipMessage);
213                         if (getSIPStack().isLoggingEnabled())
214                         	getSIPStack().getStackLogger().logDebug("Self routing message");
215                         return;
216                     }
217 
218                 }
219             }
220             byte[] msg = sipMessage.encodeAsBytes(this.getTransport());
221 
222             this.sendMessage(msg, hopAddr, hop.getPort(), sipMessage instanceof SIPRequest);
223 
224         } catch (IOException ioe) {
225             throw ioe;
226         } catch (Exception ex) {
227         	if (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_ERROR)) {
228         		this.getSIPStack().getStackLogger().logError("Error self routing message cause by: ", ex);
229         	}
230         	// TODO: When moving to Java 6, use the IOExcpetion(message, exception) constructor
231             throw new IOException("Error self routing message");
232         } finally {
233 
234             if (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))
235                 logMessage(sipMessage, hopAddr, hop.getPort(), time);
236         }
237     }
238 
239     /**
240      * Send a message given SIP message.
241      *
242      * @param sipMessage is the messge to send.
243      * @param receiverAddress is the address to which we want to send
244      * @param receiverPort is the port to which we want to send
245      */
sendMessage(SIPMessage sipMessage, InetAddress receiverAddress, int receiverPort)246     public void sendMessage(SIPMessage sipMessage, InetAddress receiverAddress, int receiverPort)
247             throws IOException {
248         long time = System.currentTimeMillis();
249         byte[] bytes = sipMessage.encodeAsBytes(this.getTransport());
250         sendMessage(bytes, receiverAddress, receiverPort, sipMessage instanceof SIPRequest);
251         logMessage(sipMessage, receiverAddress, receiverPort, time);
252     }
253 
254     /**
255      * Convenience function to get the raw IP source address of a SIP message as a String.
256      */
getRawIpSourceAddress()257     public String getRawIpSourceAddress() {
258         String sourceAddress = getPeerAddress();
259         String rawIpSourceAddress = null;
260         try {
261             InetAddress sourceInetAddress = InetAddress.getByName(sourceAddress);
262             rawIpSourceAddress = sourceInetAddress.getHostAddress();
263         } catch (Exception ex) {
264             InternalErrorHandler.handleException(ex);
265         }
266         return rawIpSourceAddress;
267     }
268 
269     /**
270      * generate a key given the inet address port and transport.
271      */
getKey(InetAddress inetAddr, int port, String transport)272     public static String getKey(InetAddress inetAddr, int port, String transport) {
273         return (transport + ":" + inetAddr.getHostAddress() + ":" + port).toLowerCase();
274     }
275 
276     /**
277      * Generate a key given host and port.
278      */
getKey(HostPort hostPort, String transport)279     public static String getKey(HostPort hostPort, String transport) {
280         return (transport + ":" + hostPort.getHost().getHostname() + ":" + hostPort.getPort())
281                 .toLowerCase();
282     }
283 
284     /**
285      * Get the hostport structure of this message channel.
286      */
getHostPort()287     public HostPort getHostPort() {
288         HostPort retval = new HostPort();
289         retval.setHost(new Host(this.getHost()));
290         retval.setPort(this.getPort());
291         return retval;
292     }
293 
294     /**
295      * Get the peer host and port.
296      *
297      * @return a HostPort structure for the peer.
298      */
getPeerHostPort()299     public HostPort getPeerHostPort() {
300         HostPort retval = new HostPort();
301         retval.setHost(new Host(this.getPeerAddress()));
302         retval.setPort(this.getPeerPort());
303         return retval;
304     }
305 
306     /**
307      * Get the Via header for this transport. Note that this does not set a branch identifier.
308      *
309      * @return a via header for outgoing messages sent from this channel.
310      */
getViaHeader()311     public Via getViaHeader() {
312         Via channelViaHeader;
313 
314         channelViaHeader = new Via();
315         try {
316             channelViaHeader.setTransport(getTransport());
317         } catch (ParseException ex) {
318         }
319         channelViaHeader.setSentBy(getHostPort());
320         return channelViaHeader;
321     }
322 
323     /**
324      * Get the via header host:port structure. This is extracted from the topmost via header of
325      * the request.
326      *
327      * @return a host:port structure
328      */
getViaHostPort()329     public HostPort getViaHostPort() {
330         HostPort retval = new HostPort();
331         retval.setHost(new Host(this.getViaHost()));
332         retval.setPort(this.getViaPort());
333         return retval;
334     }
335 
336     /**
337      * Log a message sent to an address and port via the default interface.
338      *
339      * @param sipMessage is the message to log.
340      * @param address is the inet address to which the message is sent.
341      * @param port is the port to which the message is directed.
342      */
logMessage(SIPMessage sipMessage, InetAddress address, int port, long time)343     protected void logMessage(SIPMessage sipMessage, InetAddress address, int port, long time) {
344         if (!getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))
345             return;
346 
347         // Default port.
348         if (port == -1)
349             port = 5060;
350         getSIPStack().serverLogger.logMessage(sipMessage, this.getHost() + ":" + this.getPort(),
351                 address.getHostAddress().toString() + ":" + port, true, time);
352     }
353 
354     /**
355      * Log a response received at this message channel. This is used for processing incoming
356      * responses to a client transaction.
357      *
358      * @param receptionTime is the time at which the response was received.
359      * @param status is the processing status of the message.
360      *
361      */
logResponse(SIPResponse sipResponse, long receptionTime, String status)362     public void logResponse(SIPResponse sipResponse, long receptionTime, String status) {
363         int peerport = getPeerPort();
364         if (peerport == 0 && sipResponse.getContactHeaders() != null) {
365             ContactHeader contact = (ContactHeader) sipResponse.getContactHeaders().getFirst();
366             peerport = ((AddressImpl) contact.getAddress()).getPort();
367 
368         }
369         String from = getPeerAddress().toString() + ":" + peerport;
370         String to = this.getHost() + ":" + getPort();
371         this.getSIPStack().serverLogger.logMessage(sipResponse, from, to, status, false,
372                 receptionTime);
373     }
374 
375     /**
376      * Creates a response to a bad request (ie one that causes a ParseException)
377      *
378      * @param badReq
379      * @return message bytes, null if unable to formulate response
380      */
createBadReqRes(String badReq, ParseException pe)381     protected final String createBadReqRes(String badReq, ParseException pe) {
382 
383         StringBuffer buf = new StringBuffer(512);
384         buf.append("SIP/2.0 400 Bad Request (" + pe.getLocalizedMessage() + ')');
385 
386         // We need the following headers: all Vias, CSeq, Call-ID, From, To
387         if (!copyViaHeaders(badReq, buf))
388             return null;
389         if (!copyHeader(CSeqHeader.NAME, badReq, buf))
390             return null;
391         if (!copyHeader(CallIdHeader.NAME, badReq, buf))
392             return null;
393         if (!copyHeader(FromHeader.NAME, badReq, buf))
394             return null;
395         if (!copyHeader(ToHeader.NAME, badReq, buf))
396             return null;
397 
398         // Should add a to-tag if not already present...
399         int toStart = buf.indexOf(ToHeader.NAME);
400         if (toStart != -1 && buf.indexOf("tag", toStart) == -1) {
401             buf.append(";tag=badreq");
402         }
403 
404         // Let's add a Server header too..
405         ServerHeader s = MessageFactoryImpl.getDefaultServerHeader();
406         if ( s != null ) {
407             buf.append("\r\n" + s.toString());
408         }
409         int clength = badReq.length();
410         if (! (this instanceof UDPMessageChannel) ||
411                 clength + buf.length() + ContentTypeHeader.NAME.length()
412                 + ": message/sipfrag\r\n".length() +
413                 ContentLengthHeader.NAME.length()  < 1300) {
414 
415             /*
416              * Check to see we are within one UDP packet.
417              */
418             ContentTypeHeader cth = new ContentType("message", "sipfrag");
419             buf.append("\r\n" + cth.toString());
420             ContentLength clengthHeader = new ContentLength(clength);
421             buf.append("\r\n" + clengthHeader.toString());
422             buf.append("\r\n\r\n" + badReq);
423         } else {
424             ContentLength clengthHeader = new ContentLength(0);
425             buf.append("\r\n" + clengthHeader.toString());
426         }
427 
428         return buf.toString();
429     }
430 
431     /**
432      * Copies a header from a request
433      *
434      * @param name
435      * @param fromReq
436      * @param buf
437      * @return
438      *
439      * Note: some limitations here: does not work for short forms of headers, or continuations;
440      * problems when header names appear in other parts of the request
441      */
copyHeader(String name, String fromReq, StringBuffer buf)442     private static final boolean copyHeader(String name, String fromReq, StringBuffer buf) {
443         int start = fromReq.indexOf(name);
444         if (start != -1) {
445             int end = fromReq.indexOf("\r\n", start);
446             if (end != -1) {
447                 // XX Assumes no continuation here...
448                 buf.append(fromReq.subSequence(start - 2, end)); // incl CRLF
449                 // in front
450                 return true;
451             }
452         }
453         return false;
454     }
455 
456     /**
457      * Copies all via headers from a request
458      *
459      * @param fromReq
460      * @param buf
461      * @return
462      *
463      * Note: some limitations here: does not work for short forms of headers, or continuations
464      */
copyViaHeaders(String fromReq, StringBuffer buf)465     private static final boolean copyViaHeaders(String fromReq, StringBuffer buf) {
466         int start = fromReq.indexOf(ViaHeader.NAME);
467         boolean found = false;
468         while (start != -1) {
469             int end = fromReq.indexOf("\r\n", start);
470             if (end != -1) {
471                 // XX Assumes no continuation here...
472                 buf.append(fromReq.subSequence(start - 2, end)); // incl CRLF
473                 // in front
474                 found = true;
475                 start = fromReq.indexOf(ViaHeader.NAME, end);
476             } else {
477                 return false;
478             }
479         }
480         return found;
481     }
482 
483     /**
484      * Get the message processor.
485      */
getMessageProcessor()486     public MessageProcessor getMessageProcessor() {
487         return this.messageProcessor;
488     }
489 }
490