Home | History | Annotate | Download | only in stack
      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 	 */
     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      */
     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      */
     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      */
    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      */
    111     public abstract boolean isReliable();
    112 
    113     /**
    114      * Return true if this is a secure channel.
    115      */
    116     public abstract boolean isSecure();
    117 
    118     /**
    119      * Send the message (after it has been formatted)
    120      *
    121      * @param sipMessage Message to send.
    122      */
    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      */
    130     public abstract String getPeerAddress();
    131 
    132     protected abstract InetAddress getPeerInetAddress();
    133 
    134     protected abstract String getPeerProtocol();
    135 
    136     /**
    137      * Get the sender port ( the port of the other end that sent me the message).
    138      */
    139     public abstract int getPeerPort();
    140 
    141     public abstract int getPeerPacketSourcePort();
    142 
    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      */
    149     public abstract String getKey();
    150 
    151     /**
    152      * Get the host to assign for an outgoing Request via header.
    153      */
    154     public abstract String getViaHost();
    155 
    156     /**
    157      * Get the port to assign for the via header of an outgoing message.
    158      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    486     public MessageProcessor getMessageProcessor() {
    487         return this.messageProcessor;
    488     }
    489 }
    490