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