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 (at) 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 147 public PingBackTimerTask(String ipAddress, int port) { 148 this.ipAddress = ipAddress; 149 this.port = port; 150 pingBackRecord.put(ipAddress + ":" + port, this); 151 } 152 @Override 153 public void run() { 154 pingBackRecord.remove(ipAddress + ":" + port); 155 } 156 @Override 157 public int hashCode() { 158 return (ipAddress + ":" + port).hashCode(); 159 } 160 } 161 162 /** 163 * Constructor - takes a datagram packet and a stack structure Extracts the 164 * address of the other from the datagram packet and stashes away the 165 * pointer to the passed stack structure. 166 * 167 * @param stack 168 * is the shared SIPStack structure 169 * @param messageProcessor 170 * is the creating message processor. 171 */ 172 protected UDPMessageChannel(SIPTransactionStack stack, 173 UDPMessageProcessor messageProcessor) { 174 super.messageProcessor = messageProcessor; 175 this.sipStack = stack; 176 177 Thread mythread = new Thread(this); 178 179 this.myAddress = messageProcessor.getIpAddress().getHostAddress(); 180 this.myPort = messageProcessor.getPort(); 181 182 mythread.setName("UDPMessageChannelThread"); 183 mythread.setDaemon(true); 184 mythread.start(); 185 186 } 187 188 /** 189 * Constructor. We create one of these in order to process an incoming 190 * message. 191 * 192 * @param stack 193 * is the SIP sipStack. 194 * @param messageProcessor 195 * is the creating message processor. 196 * @param packet 197 * is the incoming datagram packet. 198 */ 199 protected UDPMessageChannel(SIPTransactionStack stack, 200 UDPMessageProcessor messageProcessor, DatagramPacket packet) { 201 202 this.incomingPacket = packet; 203 super.messageProcessor = messageProcessor; 204 this.sipStack = stack; 205 206 this.myAddress = messageProcessor.getIpAddress().getHostAddress(); 207 this.myPort = messageProcessor.getPort(); 208 Thread mythread = new Thread(this); 209 mythread.setDaemon(true); 210 mythread.setName("UDPMessageChannelThread"); 211 212 mythread.start(); 213 214 } 215 216 /** 217 * Constructor. We create one of these when we send out a message. 218 * 219 * @param targetAddr 220 * INET address of the place where we want to send messages. 221 * @param port 222 * target port (where we want to send the message). 223 * @param sipStack 224 * our SIP Stack. 225 */ 226 protected UDPMessageChannel(InetAddress targetAddr, int port, 227 SIPTransactionStack sipStack, UDPMessageProcessor messageProcessor) { 228 peerAddress = targetAddr; 229 peerPort = port; 230 peerProtocol = "UDP"; 231 super.messageProcessor = messageProcessor; 232 this.myAddress = messageProcessor.getIpAddress().getHostAddress(); 233 this.myPort = messageProcessor.getPort(); 234 this.sipStack = sipStack; 235 if (sipStack.isLoggingEnabled()) { 236 this.sipStack.getStackLogger().logDebug("Creating message channel " 237 + targetAddr.getHostAddress() + "/" + port); 238 } 239 } 240 241 /** 242 * Run method specified by runnnable. 243 */ 244 public void run() { 245 // Assume no thread pooling (bug fix by spierhj) 246 ThreadAuditor.ThreadHandle threadHandle = null; 247 248 while (true) { 249 // Create a new string message parser to parse the list of messages. 250 if (myParser == null) { 251 myParser = new StringMsgParser(); 252 myParser.setParseExceptionListener(this); 253 } 254 // messages that we write out to him. 255 DatagramPacket packet; 256 257 if (sipStack.threadPoolSize != -1) { 258 synchronized (((UDPMessageProcessor) messageProcessor).messageQueue) { 259 while (((UDPMessageProcessor) messageProcessor).messageQueue 260 .isEmpty()) { 261 // Check to see if we need to exit. 262 if (!((UDPMessageProcessor) messageProcessor).isRunning) 263 return; 264 try { 265 // We're part of a thread pool. Ask the auditor to 266 // monitor this thread. 267 if (threadHandle == null) { 268 threadHandle = sipStack.getThreadAuditor() 269 .addCurrentThread(); 270 } 271 272 // Send a heartbeat to the thread auditor 273 threadHandle.ping(); 274 275 // Wait for packets 276 // Note: getPingInterval returns 0 (infinite) if the 277 // thread auditor is disabled. 278 ((UDPMessageProcessor) messageProcessor).messageQueue 279 .wait(threadHandle 280 .getPingIntervalInMillisecs()); 281 } catch (InterruptedException ex) { 282 if (!((UDPMessageProcessor) messageProcessor).isRunning) 283 return; 284 } 285 } 286 packet = (DatagramPacket) ((UDPMessageProcessor) messageProcessor).messageQueue 287 .removeFirst(); 288 289 } 290 this.incomingPacket = packet; 291 } else { 292 packet = this.incomingPacket; 293 } 294 295 // Process the packet. Catch and log any exception we may throw. 296 try { 297 processIncomingDataPacket(packet); 298 } catch (Exception e) { 299 300 sipStack.getStackLogger().logError( 301 "Error while processing incoming UDP packet", e); 302 } 303 304 if (sipStack.threadPoolSize == -1) { 305 return; 306 } 307 } 308 } 309 310 /** 311 * Process an incoming datagram 312 * 313 * @param packet 314 * is the incoming datagram packet. 315 */ 316 private void processIncomingDataPacket(DatagramPacket packet) 317 throws Exception { 318 this.peerAddress = packet.getAddress(); 319 int packetLength = packet.getLength(); 320 // Read bytes and put it in a eueue. 321 byte[] bytes = packet.getData(); 322 byte[] msgBytes = new byte[packetLength]; 323 System.arraycopy(bytes, 0, msgBytes, 0, packetLength); 324 325 // Do debug logging. 326 if (sipStack.isLoggingEnabled()) { 327 this.sipStack.getStackLogger() 328 .logDebug("UDPMessageChannel: processIncomingDataPacket : peerAddress = " 329 + peerAddress.getHostAddress() + "/" 330 + packet.getPort() + " Length = " + packetLength); 331 332 } 333 334 SIPMessage sipMessage = null; 335 try { 336 this.receptionTime = System.currentTimeMillis(); 337 sipMessage = myParser.parseSIPMessage(msgBytes); 338 myParser = null; 339 } catch (ParseException ex) { 340 myParser = null; // let go of the parser reference. 341 if (sipStack.isLoggingEnabled()) { 342 this.sipStack.getStackLogger().logDebug("Rejecting message ! " 343 + new String(msgBytes)); 344 this.sipStack.getStackLogger().logDebug("error message " 345 + ex.getMessage()); 346 this.sipStack.getStackLogger().logException(ex); 347 } 348 349 350 // JvB: send a 400 response for requests (except ACK) 351 // Currently only UDP, @todo also other transports 352 String msgString = new String(msgBytes, 0, packetLength); 353 if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) { 354 355 String badReqRes = createBadReqRes(msgString, ex); 356 if (badReqRes != null) { 357 if (sipStack.isLoggingEnabled()) { 358 sipStack.getStackLogger().logDebug( 359 "Sending automatic 400 Bad Request:"); 360 sipStack.getStackLogger().logDebug(badReqRes); 361 } 362 try { 363 this.sendMessage(badReqRes.getBytes(), peerAddress, 364 packet.getPort(), "UDP", false); 365 } catch (IOException e) { 366 this.sipStack.getStackLogger().logException(e); 367 } 368 } else { 369 if (sipStack.isLoggingEnabled()) { 370 sipStack 371 .getStackLogger() 372 .logDebug( 373 "Could not formulate automatic 400 Bad Request"); 374 } 375 } 376 } 377 378 return; 379 } 380 // No parse exception but null message - reject it and 381 // march on (or return). 382 // exit this message processor if the message did not parse. 383 384 if (sipMessage == null) { 385 if (sipStack.isLoggingEnabled()) { 386 this.sipStack.getStackLogger().logDebug("Rejecting message ! + Null message parsed."); 387 } 388 if (pingBackRecord.get(packet.getAddress().getHostAddress() + ":" + packet.getPort()) == null ) { 389 byte[] retval = "\r\n\r\n".getBytes(); 390 DatagramPacket keepalive = new DatagramPacket(retval,0,retval.length,packet.getAddress(),packet.getPort()); 391 ((UDPMessageProcessor)this.messageProcessor).sock.send(keepalive); 392 this.sipStack.getTimer().schedule(new PingBackTimerTask(packet.getAddress().getHostAddress(), 393 packet.getPort()), 1000); 394 } 395 return; 396 } 397 ViaList viaList = sipMessage.getViaHeaders(); 398 // Check for the required headers. 399 if (sipMessage.getFrom() == null || sipMessage.getTo() == null 400 || sipMessage.getCallId() == null 401 || sipMessage.getCSeq() == null 402 || sipMessage.getViaHeaders() == null) { 403 String badmsg = new String(msgBytes); 404 if (sipStack.isLoggingEnabled()) { 405 this.sipStack.getStackLogger().logError("bad message " + badmsg); 406 this.sipStack.getStackLogger().logError(">>> Dropped Bad Msg " 407 + "From = " + sipMessage.getFrom() + "To = " 408 + sipMessage.getTo() + "CallId = " 409 + sipMessage.getCallId() + "CSeq = " 410 + sipMessage.getCSeq() + "Via = " 411 + sipMessage.getViaHeaders()); 412 } 413 return; 414 } 415 // For a request first via header tells where the message 416 // is coming from. 417 // For response, just get the port from the packet. 418 if (sipMessage instanceof SIPRequest) { 419 Via v = (Via) viaList.getFirst(); 420 Hop hop = sipStack.addressResolver.resolveAddress(v.getHop()); 421 this.peerPort = hop.getPort(); 422 this.peerProtocol = v.getTransport(); 423 424 this.peerPacketSourceAddress = packet.getAddress(); 425 this.peerPacketSourcePort = packet.getPort(); 426 try { 427 this.peerAddress = packet.getAddress(); 428 // Check to see if the received parameter matches 429 // the peer address and tag it appropriately. 430 431 432 boolean hasRPort = v.hasParameter(Via.RPORT); 433 if (hasRPort 434 || !hop.getHost().equals( 435 this.peerAddress.getHostAddress())) { 436 v.setParameter(Via.RECEIVED, this.peerAddress 437 .getHostAddress()); 438 } 439 440 if (hasRPort) { 441 v.setParameter(Via.RPORT, Integer 442 .toString(this.peerPacketSourcePort)); 443 } 444 } catch (java.text.ParseException ex1) { 445 InternalErrorHandler.handleException(ex1); 446 } 447 448 } else { 449 450 this.peerPacketSourceAddress = packet.getAddress(); 451 this.peerPacketSourcePort = packet.getPort(); 452 this.peerAddress = packet.getAddress(); 453 this.peerPort = packet.getPort(); 454 this.peerProtocol = ((Via) viaList.getFirst()).getTransport(); 455 } 456 457 this.processMessage(sipMessage); 458 459 } 460 461 /** 462 * Actually proces the parsed message. 463 * 464 * @param sipMessage 465 */ 466 public void processMessage(SIPMessage sipMessage) { 467 468 if (sipMessage instanceof SIPRequest) { 469 SIPRequest sipRequest = (SIPRequest) sipMessage; 470 471 // This is a request - process it. 472 // So far so good -- we will commit this message if 473 // all processing is OK. 474 if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) { 475 476 this.sipStack.serverLogger.logMessage(sipMessage, this 477 .getPeerHostPort().toString(), this.getHost() + ":" 478 + this.myPort, false, receptionTime); 479 480 } 481 ServerRequestInterface sipServerRequest = sipStack 482 .newSIPServerRequest(sipRequest, this); 483 // Drop it if there is no request returned 484 if (sipServerRequest == null) { 485 if (sipStack.isLoggingEnabled()) { 486 this.sipStack.getStackLogger() 487 .logWarning("Null request interface returned -- dropping request"); 488 } 489 490 491 return; 492 } 493 if (sipStack.isLoggingEnabled()) 494 this.sipStack.getStackLogger().logDebug("About to process " 495 + sipRequest.getFirstLine() + "/" + sipServerRequest); 496 try { 497 sipServerRequest.processRequest(sipRequest, this); 498 } finally { 499 if (sipServerRequest instanceof SIPTransaction) { 500 SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest; 501 if (!sipServerTx.passToListener()) { 502 ((SIPTransaction) sipServerRequest).releaseSem(); 503 } 504 } 505 } 506 if (sipStack.isLoggingEnabled()) 507 this.sipStack.getStackLogger().logDebug("Done processing " 508 + sipRequest.getFirstLine() + "/" + sipServerRequest); 509 510 // So far so good -- we will commit this message if 511 // all processing is OK. 512 513 } else { 514 // Handle a SIP Reply message. 515 SIPResponse sipResponse = (SIPResponse) sipMessage; 516 try { 517 sipResponse.checkHeaders(); 518 } catch (ParseException ex) { 519 if (sipStack.isLoggingEnabled()) 520 sipStack.getStackLogger() 521 .logError("Dropping Badly formatted response message >>> " 522 + sipResponse); 523 return; 524 } 525 ServerResponseInterface sipServerResponse = sipStack 526 .newSIPServerResponse(sipResponse, this); 527 if (sipServerResponse != null) { 528 try { 529 if (sipServerResponse instanceof SIPClientTransaction 530 && !((SIPClientTransaction) sipServerResponse) 531 .checkFromTag(sipResponse)) { 532 if (sipStack.isLoggingEnabled()) 533 sipStack.getStackLogger() 534 .logError("Dropping response message with invalid tag >>> " 535 + sipResponse); 536 return; 537 } 538 539 sipServerResponse.processResponse(sipResponse, this); 540 } finally { 541 if (sipServerResponse instanceof SIPTransaction 542 && !((SIPTransaction) sipServerResponse) 543 .passToListener()) 544 ((SIPTransaction) sipServerResponse).releaseSem(); 545 } 546 547 // Normal processing of message. 548 } else { 549 if (sipStack.isLoggingEnabled()) { 550 this.sipStack.getStackLogger().logDebug("null sipServerResponse!"); 551 } 552 } 553 554 } 555 } 556 557 /** 558 * JvB: added method to check for known buggy clients (Windows Messenger) to 559 * fix the port to which responses are sent 560 * 561 * checks for User-Agent: RTC/1.3.5470 (Messenger 5.1.0701) 562 * 563 * JvB 22/7/2006 better to take this out for the moment, it is only a 564 * problem in rare cases (unregister) 565 * 566 * private final boolean isBuggyClient( SIPRequest r ) { UserAgent uah = 567 * (UserAgent) r.getHeader( UserAgent.NAME ); if (uah!=null) { 568 * java.util.ListIterator i = uah.getProduct(); if (i.hasNext()) { String p = 569 * (String) uah.getProduct().next(); return p.startsWith( "RTC" ); } } 570 * return false; } 571 */ 572 573 /** 574 * Implementation of the ParseExceptionListener interface. 575 * 576 * @param ex 577 * Exception that is given to us by the parser. 578 * @throws ParseException 579 * If we choose to reject the header or message. 580 */ 581 public void handleException(ParseException ex, SIPMessage sipMessage, 582 Class hdrClass, String header, String message) 583 throws ParseException { 584 if (sipStack.isLoggingEnabled()) 585 this.sipStack.getStackLogger().logException(ex); 586 // Log the bad message for later reference. 587 if ((hdrClass != null) 588 && (hdrClass.equals(From.class) || hdrClass.equals(To.class) 589 || hdrClass.equals(CSeq.class) 590 || hdrClass.equals(Via.class) 591 || hdrClass.equals(CallID.class) 592 || hdrClass.equals(RequestLine.class) || hdrClass 593 .equals(StatusLine.class))) { 594 if (sipStack.isLoggingEnabled()) { 595 sipStack.getStackLogger().logError("BAD MESSAGE!"); 596 sipStack.getStackLogger().logError(message); 597 } 598 throw ex; 599 } else { 600 sipMessage.addUnparsed(header); 601 } 602 } 603 604 /** 605 * Return a reply from a pre-constructed reply. This sends the message back 606 * to the entity who caused us to create this channel in the first place. 607 * 608 * @param sipMessage 609 * Message string to send. 610 * @throws IOException 611 * If there is a problem with sending the message. 612 */ 613 public void sendMessage(SIPMessage sipMessage) throws IOException { 614 if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend()) { 615 if ( sipMessage instanceof SIPRequest && 616 ((SIPRequest)sipMessage).getRequestLine() != null) { 617 /* 618 * We dont want to log empty trace messages. 619 */ 620 this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO); 621 } else { 622 this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO); 623 } 624 } 625 626 // Test and see where we are going to send the messsage. If the message 627 // is sent back to oursleves, just 628 // shortcircuit processing. 629 long time = System.currentTimeMillis(); 630 try { 631 for (MessageProcessor messageProcessor : sipStack 632 .getMessageProcessors()) { 633 if (messageProcessor.getIpAddress().equals(this.peerAddress) 634 && messageProcessor.getPort() == this.peerPort 635 && messageProcessor.getTransport().equals( 636 this.peerProtocol)) { 637 MessageChannel messageChannel = messageProcessor 638 .createMessageChannel(this.peerAddress, 639 this.peerPort); 640 if (messageChannel instanceof RawMessageChannel) { 641 ((RawMessageChannel) messageChannel) 642 .processMessage(sipMessage); 643 if (sipStack.isLoggingEnabled()) 644 sipStack.getStackLogger().logDebug("Self routing message"); 645 return; 646 } 647 648 } 649 } 650 651 byte[] msg = sipMessage.encodeAsBytes( this.getTransport() ); 652 653 sendMessage(msg, peerAddress, peerPort, peerProtocol, 654 sipMessage instanceof SIPRequest); 655 656 } catch (IOException ex) { 657 throw ex; 658 } catch (Exception ex) { 659 sipStack.getStackLogger().logError("An exception occured while sending message",ex); 660 throw new IOException( 661 "An exception occured while sending message"); 662 } finally { 663 if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES) && !sipMessage.isNullRequest()) 664 logMessage(sipMessage, peerAddress, peerPort, time); 665 else if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_DEBUG)) 666 sipStack.getStackLogger().logDebug("Sent EMPTY Message"); 667 } 668 } 669 670 /** 671 * Send a message to a specified receiver address. 672 * 673 * @param msg 674 * string to send. 675 * @param peerAddress 676 * Address of the place to send it to. 677 * @param peerPort 678 * the port to send it to. 679 * @throws IOException 680 * If there is trouble sending this message. 681 */ 682 protected void sendMessage(byte[] msg, InetAddress peerAddress, 683 int peerPort, boolean reConnect) throws IOException { 684 // Via is not included in the request so silently drop the reply. 685 if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend() ) { 686 this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO); 687 } 688 if (peerPort == -1) { 689 if (sipStack.isLoggingEnabled()) { 690 this.sipStack.getStackLogger().logDebug(getClass().getName() 691 + ":sendMessage: Dropping reply!"); 692 } 693 throw new IOException("Receiver port not set "); 694 } else { 695 if (sipStack.isLoggingEnabled()) { 696 this.sipStack.getStackLogger().logDebug("sendMessage " + peerAddress.getHostAddress() + "/" 697 + peerPort + "\n" + "messageSize = " + msg.length + " message = " + new String(msg)) ; 698 this.sipStack.getStackLogger().logDebug("*******************\n"); 699 } 700 701 } 702 DatagramPacket reply = new DatagramPacket(msg, msg.length, peerAddress, 703 peerPort); 704 try { 705 DatagramSocket sock; 706 boolean created = false; 707 708 if (sipStack.udpFlag) { 709 // Use the socket from the message processor (for firewall 710 // support use the same socket as the message processor 711 // socket -- feature request # 18 from java.net). This also 712 // makes the whole thing run faster! 713 sock = ((UDPMessageProcessor) messageProcessor).sock; 714 715 // Bind the socket to the stack address in case there 716 // are multiple interfaces on the machine (feature reqeust 717 // by Will Scullin) 0 binds to an ephemeral port. 718 // sock = new DatagramSocket(0,sipStack.stackInetAddress); 719 } else { 720 // bind to any interface and port. 721 sock = new DatagramSocket(); 722 created = true; 723 } 724 sock.send(reply); 725 if (created) 726 sock.close(); 727 } catch (IOException ex) { 728 throw ex; 729 } catch (Exception ex) { 730 InternalErrorHandler.handleException(ex); 731 } 732 } 733 734 /** 735 * Send a message to a specified receiver address. 736 * 737 * @param msg 738 * message string to send. 739 * @param peerAddress 740 * Address of the place to send it to. 741 * @param peerPort 742 * the port to send it to. 743 * @param peerProtocol 744 * protocol to use to send. 745 * @throws IOException 746 * If there is trouble sending this message. 747 */ 748 protected void sendMessage(byte[] msg, InetAddress peerAddress, 749 int peerPort, String peerProtocol, boolean retry) 750 throws IOException { 751 // Via is not included in the request so silently drop the reply. 752 if (peerPort == -1) { 753 if (sipStack.isLoggingEnabled()) { 754 this.sipStack.getStackLogger().logDebug(getClass().getName() 755 + ":sendMessage: Dropping reply!"); 756 } 757 throw new IOException("Receiver port not set "); 758 } else { 759 if (sipStack.isLoggingEnabled()) { 760 this.sipStack.getStackLogger().logDebug( ":sendMessage " + peerAddress.getHostAddress() + "/" 761 + peerPort + "\n" + " messageSize = " + msg.length); 762 } 763 } 764 if (peerProtocol.compareToIgnoreCase("UDP") == 0) { 765 DatagramPacket reply = new DatagramPacket(msg, msg.length, 766 peerAddress, peerPort); 767 768 try { 769 DatagramSocket sock; 770 if (sipStack.udpFlag) { 771 sock = ((UDPMessageProcessor) messageProcessor).sock; 772 773 } else { 774 // bind to any interface and port. 775 sock = sipStack.getNetworkLayer().createDatagramSocket(); 776 } 777 if (sipStack.isLoggingEnabled()) { 778 this.sipStack.getStackLogger().logDebug("sendMessage " 779 + peerAddress.getHostAddress() + "/" + peerPort 780 + "\n" + new String(msg)); 781 } 782 sock.send(reply); 783 if (!sipStack.udpFlag) 784 sock.close(); 785 } catch (IOException ex) { 786 throw ex; 787 } catch (Exception ex) { 788 InternalErrorHandler.handleException(ex); 789 } 790 791 } else { 792 // Use TCP to talk back to the sender. 793 Socket outputSocket = sipStack.ioHandler.sendBytes( 794 this.messageProcessor.getIpAddress(), peerAddress, 795 peerPort, "tcp", msg, retry,this); 796 OutputStream myOutputStream = outputSocket.getOutputStream(); 797 myOutputStream.write(msg, 0, msg.length); 798 myOutputStream.flush(); 799 // The socket is cached (dont close it!); 800 } 801 } 802 803 /** 804 * get the stack pointer. 805 * 806 * @return The sip stack for this channel. 807 */ 808 public SIPTransactionStack getSIPStack() { 809 return sipStack; 810 } 811 812 /** 813 * Return a transport string. 814 * 815 * @return the string "udp" in this case. 816 */ 817 public String getTransport() { 818 return SIPConstants.UDP; 819 } 820 821 /** 822 * get the stack address for the stack that received this message. 823 * 824 * @return The stack address for our sipStack. 825 */ 826 public String getHost() { 827 return messageProcessor.getIpAddress().getHostAddress(); 828 } 829 830 /** 831 * get the port. 832 * 833 * @return Our port (on which we are getting datagram packets). 834 */ 835 public int getPort() { 836 return ((UDPMessageProcessor) messageProcessor).getPort(); 837 } 838 839 /** 840 * get the name (address) of the host that sent me the message 841 * 842 * @return The name of the sender (from the datagram packet). 843 */ 844 public String getPeerName() { 845 return peerAddress.getHostName(); 846 } 847 848 /** 849 * get the address of the host that sent me the message 850 * 851 * @return The senders ip address. 852 */ 853 public String getPeerAddress() { 854 return peerAddress.getHostAddress(); 855 } 856 857 protected InetAddress getPeerInetAddress() { 858 return peerAddress; 859 } 860 861 /** 862 * Compare two UDP Message channels for equality. 863 * 864 * @param other 865 * The other message channel with which to compare oursleves. 866 */ 867 public boolean equals(Object other) { 868 869 if (other == null) 870 return false; 871 boolean retval; 872 if (!this.getClass().equals(other.getClass())) { 873 retval = false; 874 } else { 875 UDPMessageChannel that = (UDPMessageChannel) other; 876 retval = this.getKey().equals(that.getKey()); 877 } 878 879 return retval; 880 } 881 882 public String getKey() { 883 return getKey(peerAddress, peerPort, "UDP"); 884 } 885 886 public int getPeerPacketSourcePort() { 887 return peerPacketSourcePort; 888 } 889 890 public InetAddress getPeerPacketSourceAddress() { 891 return peerPacketSourceAddress; 892 } 893 894 /** 895 * Get the logical originator of the message (from the top via header). 896 * 897 * @return topmost via header sentby field 898 */ 899 public String getViaHost() { 900 return this.myAddress; 901 } 902 903 /** 904 * Get the logical port of the message orginator (from the top via hdr). 905 * 906 * @return the via port from the topmost via header. 907 */ 908 public int getViaPort() { 909 return this.myPort; 910 } 911 912 /** 913 * Returns "false" as this is an unreliable transport. 914 */ 915 public boolean isReliable() { 916 return false; 917 } 918 919 /** 920 * UDP is not a secure protocol. 921 */ 922 public boolean isSecure() { 923 return false; 924 } 925 926 public int getPeerPort() { 927 return peerPort; 928 } 929 930 public String getPeerProtocol() { 931 return this.peerProtocol; 932 } 933 934 /** 935 * Close the message channel. 936 */ 937 public void close() { 938 } 939 940 941 } 942