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 package gov.nist.javax.sip; 30 31 import gov.nist.core.InternalErrorHandler; 32 import gov.nist.javax.sip.DialogTimeoutEvent.Reason; 33 import gov.nist.javax.sip.address.RouterExt; 34 import gov.nist.javax.sip.header.CallID; 35 import gov.nist.javax.sip.header.Via; 36 import gov.nist.javax.sip.message.SIPMessage; 37 import gov.nist.javax.sip.message.SIPRequest; 38 import gov.nist.javax.sip.message.SIPResponse; 39 import gov.nist.javax.sip.stack.HopImpl; 40 import gov.nist.javax.sip.stack.MessageChannel; 41 import gov.nist.javax.sip.stack.SIPClientTransaction; 42 import gov.nist.javax.sip.stack.SIPDialog; 43 import gov.nist.javax.sip.stack.SIPDialogErrorEvent; 44 import gov.nist.javax.sip.stack.SIPDialogEventListener; 45 import gov.nist.javax.sip.stack.SIPServerTransaction; 46 import gov.nist.javax.sip.stack.SIPTransaction; 47 import gov.nist.javax.sip.stack.SIPTransactionErrorEvent; 48 import gov.nist.javax.sip.stack.SIPTransactionEventListener; 49 50 import java.io.IOException; 51 import java.text.ParseException; 52 import java.util.EventObject; 53 import java.util.Iterator; 54 import java.util.TooManyListenersException; 55 import java.util.concurrent.ConcurrentHashMap; 56 57 import javax.sip.ClientTransaction; 58 import javax.sip.Dialog; 59 import javax.sip.DialogState; 60 import javax.sip.InvalidArgumentException; 61 import javax.sip.ListeningPoint; 62 import javax.sip.ObjectInUseException; 63 import javax.sip.RequestEvent; 64 import javax.sip.ResponseEvent; 65 import javax.sip.ServerTransaction; 66 import javax.sip.SipException; 67 import javax.sip.SipListener; 68 import javax.sip.SipStack; 69 import javax.sip.Timeout; 70 import javax.sip.TimeoutEvent; 71 import javax.sip.Transaction; 72 import javax.sip.TransactionAlreadyExistsException; 73 import javax.sip.TransactionState; 74 import javax.sip.TransactionUnavailableException; 75 import javax.sip.address.Hop; 76 import javax.sip.header.CallIdHeader; 77 import javax.sip.message.Request; 78 import javax.sip.message.Response; 79 80 /* 81 * Contributions (bug fixes) made by: Daniel J. Martinez Manzano, Hagai Sela. 82 * Bug reports by Shanti Kadiyala, Rhys Ulerich,Victor Hugo 83 */ 84 /** 85 * Implementation of the JAIN-SIP provider interface. 86 * 87 * @version 1.2 $Revision: 1.82 $ $Date: 2009/11/24 17:16:59 $ 88 * 89 * @author M. Ranganathan <br/> 90 * 91 * 92 */ 93 94 public class SipProviderImpl implements javax.sip.SipProvider, gov.nist.javax.sip.SipProviderExt, 95 SIPTransactionEventListener, SIPDialogEventListener { 96 97 private SipListener sipListener; 98 99 protected SipStackImpl sipStack; 100 101 /* 102 * A set of listening points associated with the provider At most one LP per 103 * transport 104 */ 105 private ConcurrentHashMap listeningPoints; 106 107 private EventScanner eventScanner; 108 109 private String address; 110 111 private int port; 112 113 private boolean automaticDialogSupportEnabled ; 114 /** 115 * A string containing the 0.0.0.0 IPv4 ANY address. 116 */ 117 private String IN_ADDR_ANY = "0.0.0.0"; 118 119 /** 120 * A string containing the ::0 IPv6 ANY address. 121 */ 122 private String IN6_ADDR_ANY = "::0"; 123 124 private boolean dialogErrorsAutomaticallyHandled = true; 125 SipProviderImpl()126 private SipProviderImpl() { 127 128 } 129 130 /** 131 * Stop processing messages for this provider. Post an empty message to our 132 * message processing queue that signals us to quit. 133 */ stop()134 protected void stop() { 135 // Put an empty event in the queue and post ourselves a message. 136 if (sipStack.isLoggingEnabled()) 137 sipStack.getStackLogger().logDebug("Exiting provider"); 138 for (Iterator it = listeningPoints.values().iterator(); it.hasNext();) { 139 ListeningPointImpl listeningPoint = (ListeningPointImpl) it.next(); 140 listeningPoint.removeSipProvider(); 141 } 142 this.eventScanner.stop(); 143 144 } 145 146 /* 147 * (non-Javadoc) 148 * 149 * @see javax.sip.SipProvider#getListeningPoint(java.lang.String) 150 */ getListeningPoint(String transport)151 public ListeningPoint getListeningPoint(String transport) { 152 if (transport == null) 153 throw new NullPointerException("Null transport param"); 154 return (ListeningPoint) this.listeningPoints.get(transport 155 .toUpperCase()); 156 } 157 158 /** 159 * Handle the SIP event - because we have only one listener and we are 160 * already in the context of a separate thread, we dont need to enque the 161 * event and signal another thread. 162 * 163 * @param sipEvent 164 * is the event to process. 165 * 166 */ 167 handleEvent(EventObject sipEvent, SIPTransaction transaction)168 public void handleEvent(EventObject sipEvent, SIPTransaction transaction) { 169 if (sipStack.isLoggingEnabled()) { 170 sipStack.getStackLogger().logDebug( 171 "handleEvent " + sipEvent + "currentTransaction = " 172 + transaction + "this.sipListener = " 173 + this.getSipListener() + "sipEvent.source = " 174 + sipEvent.getSource()); 175 if (sipEvent instanceof RequestEvent) { 176 Dialog dialog = ((RequestEvent) sipEvent).getDialog(); 177 if ( sipStack.isLoggingEnabled()) sipStack.getStackLogger().logDebug("Dialog = " + dialog); 178 } else if (sipEvent instanceof ResponseEvent) { 179 Dialog dialog = ((ResponseEvent) sipEvent).getDialog(); 180 if (sipStack.isLoggingEnabled() ) sipStack.getStackLogger().logDebug("Dialog = " + dialog); 181 } 182 sipStack.getStackLogger().logStackTrace(); 183 } 184 185 EventWrapper eventWrapper = new EventWrapper(sipEvent, transaction); 186 187 if (!sipStack.reEntrantListener) { 188 // Run the event in the context of a single thread. 189 this.eventScanner.addEvent(eventWrapper); 190 } else { 191 // just call the delivery method 192 this.eventScanner.deliverEvent(eventWrapper); 193 } 194 } 195 196 /** Creates a new instance of SipProviderImpl */ SipProviderImpl(SipStackImpl sipStack)197 protected SipProviderImpl(SipStackImpl sipStack) { 198 this.eventScanner = sipStack.getEventScanner(); // for quick access. 199 this.sipStack = sipStack; 200 this.eventScanner.incrementRefcount(); 201 this.listeningPoints = new ConcurrentHashMap<String,ListeningPointImpl>(); 202 this.automaticDialogSupportEnabled = this.sipStack 203 .isAutomaticDialogSupportEnabled(); 204 this.dialogErrorsAutomaticallyHandled = this.sipStack.isAutomaticDialogErrorHandlingEnabled(); 205 } 206 207 /* 208 * (non-Javadoc) 209 * 210 * @see java.lang.Object#clone() 211 */ clone()212 protected Object clone() throws java.lang.CloneNotSupportedException { 213 throw new java.lang.CloneNotSupportedException(); 214 } 215 216 217 /* 218 * (non-Javadoc) 219 * 220 * @see javax.sip.SipProvider#addSipListener(javax.sip.SipListener) 221 */ addSipListener(SipListener sipListener)222 public void addSipListener(SipListener sipListener) 223 throws TooManyListenersException { 224 225 if (sipStack.sipListener == null) { 226 sipStack.sipListener = sipListener; 227 } else if (sipStack.sipListener != sipListener) { 228 throw new TooManyListenersException( 229 "Stack already has a listener. Only one listener per stack allowed"); 230 } 231 232 if (sipStack.isLoggingEnabled()) 233 sipStack.getStackLogger().logDebug("add SipListener " + sipListener); 234 this.sipListener = sipListener; 235 236 } 237 238 /* 239 * This method is deprecated (non-Javadoc) 240 * 241 * @see javax.sip.SipProvider#getListeningPoint() 242 */ 243 getListeningPoint()244 public ListeningPoint getListeningPoint() { 245 if (this.listeningPoints.size() > 0) 246 return (ListeningPoint) this.listeningPoints.values().iterator() 247 .next(); 248 else 249 return null; 250 } 251 252 /* 253 * (non-Javadoc) 254 * 255 * @see javax.sip.SipProvider#getNewCallId() 256 */ getNewCallId()257 public CallIdHeader getNewCallId() { 258 String callId = Utils.getInstance().generateCallIdentifier(this.getListeningPoint() 259 .getIPAddress()); 260 CallID callid = new CallID(); 261 try { 262 callid.setCallId(callId); 263 } catch (java.text.ParseException ex) { 264 } 265 return callid; 266 267 } 268 269 /* 270 * (non-Javadoc) 271 * 272 * @see javax.sip.SipProvider#getNewClientTransaction(javax.sip.message.Request) 273 */ getNewClientTransaction(Request request)274 public ClientTransaction getNewClientTransaction(Request request) 275 throws TransactionUnavailableException { 276 if (request == null) 277 throw new NullPointerException("null request"); 278 if (!sipStack.isAlive()) 279 throw new TransactionUnavailableException("Stack is stopped"); 280 281 SIPRequest sipRequest = (SIPRequest) request; 282 if (sipRequest.getTransaction() != null) 283 throw new TransactionUnavailableException( 284 "Transaction already assigned to request"); 285 if ( sipRequest.getMethod().equals(Request.ACK)) { 286 throw new TransactionUnavailableException ("Cannot create client transaction for " + Request.ACK); 287 } 288 // Be kind and assign a via header for this provider if the user is 289 // sloppy 290 if (sipRequest.getTopmostVia() == null) { 291 ListeningPointImpl lp = (ListeningPointImpl) this 292 .getListeningPoint("udp"); 293 Via via = lp.getViaHeader(); 294 request.setHeader(via); 295 } 296 // Give the request a quick check to see if all headers are assigned. 297 try { 298 sipRequest.checkHeaders(); 299 } catch (ParseException ex) { 300 throw new TransactionUnavailableException(ex.getMessage(), ex); 301 } 302 303 /* 304 * User decided to give us his own via header branch. Lets see if it 305 * results in a clash. If so reject the request. 306 */ 307 if (sipRequest.getTopmostVia().getBranch() != null 308 && sipRequest.getTopmostVia().getBranch().startsWith( 309 SIPConstants.BRANCH_MAGIC_COOKIE) 310 && sipStack.findTransaction((SIPRequest) request, false) != null) { 311 throw new TransactionUnavailableException( 312 "Transaction already exists!"); 313 } 314 315 316 317 318 if (request.getMethod().equalsIgnoreCase(Request.CANCEL)) { 319 SIPClientTransaction ct = (SIPClientTransaction) sipStack 320 .findCancelTransaction((SIPRequest) request, false); 321 if (ct != null) { 322 ClientTransaction retval = sipStack.createClientTransaction( 323 (SIPRequest) request, ct.getMessageChannel()); 324 325 ((SIPTransaction) retval).addEventListener(this); 326 sipStack.addTransaction((SIPClientTransaction) retval); 327 if (ct.getDialog() != null) { 328 ((SIPClientTransaction) retval).setDialog((SIPDialog) ct 329 .getDialog(), sipRequest.getDialogId(false)); 330 331 } 332 return retval; 333 } 334 335 } 336 if (sipStack.isLoggingEnabled()) 337 sipStack.getStackLogger().logDebug( 338 "could not find existing transaction for " 339 + ((SIPRequest) request).getFirstLine() 340 + " creating a new one "); 341 342 // Could not find a dialog or the route is not set in dialog. 343 344 Hop hop = null; 345 try { 346 hop = sipStack.getNextHop((SIPRequest) request); 347 if (hop == null) 348 throw new TransactionUnavailableException( 349 "Cannot resolve next hop -- transaction unavailable"); 350 } catch (SipException ex) { 351 throw new TransactionUnavailableException( 352 "Cannot resolve next hop -- transaction unavailable", ex); 353 } 354 String transport = hop.getTransport(); 355 ListeningPointImpl listeningPoint = (ListeningPointImpl) this 356 .getListeningPoint(transport); 357 358 String dialogId = sipRequest.getDialogId(false); 359 SIPDialog dialog = sipStack.getDialog(dialogId); 360 if (dialog != null && dialog.getState() == DialogState.TERMINATED) { 361 362 // throw new TransactionUnavailableException 363 // ("Found a terminated dialog -- possible re-use of old tag 364 // parameters"); 365 sipStack.removeDialog(dialog); 366 367 } 368 369 // An out of dialog route was found. Assign this to the 370 // client transaction. 371 372 try { 373 // Set the brannch id before you ask for a tx. 374 // If the user has set his own branch Id and the 375 // branch id starts with a valid prefix, then take it. 376 // otherwise, generate one. If branch ID checking has 377 // been requested, set the branch ID. 378 String branchId = null; 379 if (sipRequest.getTopmostVia().getBranch() == null 380 || !sipRequest.getTopmostVia().getBranch().startsWith( 381 SIPConstants.BRANCH_MAGIC_COOKIE) 382 || sipStack.checkBranchId() ) { 383 branchId = Utils.getInstance().generateBranchId(); 384 385 sipRequest.getTopmostVia().setBranch(branchId); 386 } 387 Via topmostVia = sipRequest.getTopmostVia(); 388 389 //set port and transport if user hasn't already done this. 390 if(topmostVia.getTransport() == null) 391 topmostVia.setTransport(transport); 392 393 if(topmostVia.getPort() == -1) 394 topmostVia.setPort(listeningPoint.getPort()); 395 branchId = sipRequest.getTopmostVia().getBranch(); 396 397 SIPClientTransaction ct = (SIPClientTransaction) sipStack 398 .createMessageChannel(sipRequest, listeningPoint 399 .getMessageProcessor(), hop); 400 if (ct == null) 401 throw new TransactionUnavailableException("Cound not create tx"); 402 ct.setNextHop(hop); 403 ct.setOriginalRequest(sipRequest); 404 ct.setBranch(branchId); 405 // if the stack supports dialogs then 406 if (sipStack.isDialogCreated(request.getMethod())) { 407 // create a new dialog to contain this transaction 408 // provided this is necessary. 409 // This could be a re-invite 410 // in which case the dialog is re-used. 411 // (but noticed by Brad Templeton) 412 if (dialog != null) 413 ct.setDialog(dialog, sipRequest.getDialogId(false)); 414 else if (this.isAutomaticDialogSupportEnabled()) { 415 SIPDialog sipDialog = sipStack.createDialog(ct); 416 ct.setDialog(sipDialog, sipRequest.getDialogId(false)); 417 } 418 } else { 419 if (dialog != null) { 420 ct.setDialog(dialog, sipRequest.getDialogId(false)); 421 } 422 423 } 424 425 // The provider is the event listener for all transactions. 426 ct.addEventListener(this); 427 return (ClientTransaction) ct; 428 } catch (IOException ex) { 429 430 throw new TransactionUnavailableException( 431 "Could not resolve next hop or listening point unavailable! ", 432 ex); 433 434 } catch (java.text.ParseException ex) { 435 InternalErrorHandler.handleException(ex); 436 throw new TransactionUnavailableException( 437 "Unexpected Exception FIXME! ", ex); 438 } catch (InvalidArgumentException ex) { 439 InternalErrorHandler.handleException(ex); 440 throw new TransactionUnavailableException( 441 "Unexpected Exception FIXME! ", ex); 442 } 443 444 } 445 446 /* 447 * (non-Javadoc) 448 * 449 * @see javax.sip.SipProvider#getNewServerTransaction(javax.sip.message.Request) 450 */ getNewServerTransaction(Request request)451 public ServerTransaction getNewServerTransaction(Request request) 452 throws TransactionAlreadyExistsException, 453 TransactionUnavailableException { 454 455 if (!sipStack.isAlive()) 456 throw new TransactionUnavailableException("Stack is stopped"); 457 SIPServerTransaction transaction = null; 458 SIPRequest sipRequest = (SIPRequest) request; 459 try { 460 sipRequest.checkHeaders(); 461 } catch (ParseException ex) { 462 throw new TransactionUnavailableException(ex.getMessage(), ex); 463 } 464 465 if ( request.getMethod().equals(Request.ACK)) { 466 if ( sipStack.isLoggingEnabled()) 467 sipStack.getStackLogger().logError("Creating server transaction for ACK -- makes no sense!"); 468 throw new TransactionUnavailableException("Cannot create Server transaction for ACK "); 469 } 470 /* 471 * Got a notify. 472 */ 473 if (sipRequest.getMethod().equals(Request.NOTIFY) 474 && sipRequest.getFromTag() != null 475 && sipRequest.getToTag() == null) { 476 477 SIPClientTransaction ct = sipStack.findSubscribeTransaction( 478 sipRequest, (ListeningPointImpl) this.getListeningPoint()); 479 /* Issue 104 */ 480 if (ct == null && ! sipStack.deliverUnsolicitedNotify) { 481 throw new TransactionUnavailableException( 482 "Cannot find matching Subscription (and gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY not set)"); 483 } 484 } 485 if ( !sipStack.acquireSem()) { 486 throw new TransactionUnavailableException( 487 "Transaction not available -- could not acquire stack lock"); 488 } 489 try { 490 if (sipStack.isDialogCreated(sipRequest.getMethod())) { 491 if (sipStack.findTransaction((SIPRequest) request, true) != null) 492 throw new TransactionAlreadyExistsException( 493 "server transaction already exists!"); 494 495 transaction = (SIPServerTransaction) ((SIPRequest) request) 496 .getTransaction(); 497 if (transaction == null) 498 throw new TransactionUnavailableException( 499 "Transaction not available"); 500 if (transaction.getOriginalRequest() == null) 501 transaction.setOriginalRequest(sipRequest); 502 try { 503 sipStack.addTransaction(transaction); 504 } catch (IOException ex) { 505 throw new TransactionUnavailableException( 506 "Error sending provisional response"); 507 } 508 // So I can handle timeouts. 509 transaction.addEventListener(this); 510 if (isAutomaticDialogSupportEnabled()) { 511 // If automatic dialog support is enabled then 512 // this tx gets his own dialog. 513 String dialogId = sipRequest.getDialogId(true); 514 SIPDialog dialog = sipStack.getDialog(dialogId); 515 if (dialog == null) { 516 dialog = sipStack.createDialog(transaction); 517 518 } 519 transaction.setDialog(dialog, sipRequest.getDialogId(true)); 520 if (sipRequest.getMethod().equals(Request.INVITE) && this.isDialogErrorsAutomaticallyHandled()) { 521 sipStack.putInMergeTable(transaction, sipRequest); 522 } 523 dialog.addRoute(sipRequest); 524 if (dialog.getRemoteTag() != null 525 && dialog.getLocalTag() != null) { 526 this.sipStack.putDialog(dialog); 527 } 528 } 529 530 } else { 531 if (isAutomaticDialogSupportEnabled()) { 532 /* 533 * Under automatic dialog support, dialog is tied into a transaction. You cannot 534 * create a server tx except for dialog creating transactions. After that, all 535 * subsequent transactions are created for you by the stack. 536 */ 537 transaction = (SIPServerTransaction) sipStack.findTransaction( 538 (SIPRequest) request, true); 539 if (transaction != null) 540 throw new TransactionAlreadyExistsException( 541 "Transaction exists! "); 542 transaction = (SIPServerTransaction) ((SIPRequest) request) 543 .getTransaction(); 544 if (transaction == null) 545 throw new TransactionUnavailableException( 546 "Transaction not available!"); 547 if (transaction.getOriginalRequest() == null) 548 transaction.setOriginalRequest(sipRequest); 549 // Map the transaction. 550 try { 551 sipStack.addTransaction(transaction); 552 } catch (IOException ex) { 553 throw new TransactionUnavailableException( 554 "Could not send back provisional response!"); 555 } 556 557 // If there is a dialog already assigned then just update the 558 // dialog state. 559 String dialogId = sipRequest.getDialogId(true); 560 SIPDialog dialog = sipStack.getDialog(dialogId); 561 if (dialog != null) { 562 dialog.addTransaction(transaction); 563 dialog.addRoute(sipRequest); 564 transaction.setDialog(dialog, sipRequest.getDialogId(true)); 565 } 566 567 } else { 568 transaction = (SIPServerTransaction) sipStack.findTransaction( 569 (SIPRequest) request, true); 570 if (transaction != null) 571 throw new TransactionAlreadyExistsException( 572 "Transaction exists! "); 573 transaction = (SIPServerTransaction) ((SIPRequest) request) 574 .getTransaction(); 575 if (transaction != null) { 576 if (transaction.getOriginalRequest() == null) 577 transaction.setOriginalRequest(sipRequest); 578 // Map the transaction. 579 sipStack.mapTransaction(transaction); 580 581 // If there is a dialog already assigned then just 582 // assign the dialog to the transaction. 583 String dialogId = sipRequest.getDialogId(true); 584 SIPDialog dialog = sipStack.getDialog(dialogId); 585 if (dialog != null) { 586 dialog.addTransaction(transaction); 587 dialog.addRoute(sipRequest); 588 transaction.setDialog(dialog, sipRequest 589 .getDialogId(true)); 590 } 591 592 return transaction; 593 } else { 594 // tx does not exist so create the tx. 595 596 MessageChannel mc = (MessageChannel) sipRequest 597 .getMessageChannel(); 598 transaction = sipStack.createServerTransaction(mc); 599 if (transaction == null) 600 throw new TransactionUnavailableException( 601 "Transaction unavailable -- too many servrer transactions"); 602 603 transaction.setOriginalRequest(sipRequest); 604 sipStack.mapTransaction(transaction); 605 606 // If there is a dialog already assigned then just 607 // assign the dialog to the transaction. 608 String dialogId = sipRequest.getDialogId(true); 609 SIPDialog dialog = sipStack.getDialog(dialogId); 610 if (dialog != null) { 611 dialog.addTransaction(transaction); 612 dialog.addRoute(sipRequest); 613 transaction.setDialog(dialog, sipRequest 614 .getDialogId(true)); 615 } 616 617 return transaction; 618 } 619 } 620 621 } 622 return transaction; 623 } finally { 624 sipStack.releaseSem(); 625 } 626 627 } 628 629 /* 630 * (non-Javadoc) 631 * 632 * @see javax.sip.SipProvider#getSipStack() 633 */ getSipStack()634 public SipStack getSipStack() { 635 return (SipStack) this.sipStack; 636 } 637 638 /* 639 * (non-Javadoc) 640 * 641 * @see javax.sip.SipProvider#removeSipListener(javax.sip.SipListener) 642 */ removeSipListener(SipListener sipListener)643 public void removeSipListener(SipListener sipListener) { 644 if (sipListener == this.getSipListener()) { 645 this.sipListener = null; 646 } 647 648 boolean found = false; 649 650 for (Iterator<SipProviderImpl> it = sipStack.getSipProviders(); it.hasNext();) { 651 SipProviderImpl nextProvider = (SipProviderImpl) it.next(); 652 if (nextProvider.getSipListener() != null) 653 found = true; 654 } 655 if (!found) { 656 sipStack.sipListener = null; 657 } 658 } 659 660 /* 661 * (non-Javadoc) 662 * 663 * @see javax.sip.SipProvider#sendRequest(javax.sip.message.Request) 664 */ sendRequest(Request request)665 public void sendRequest(Request request) throws SipException { 666 if (!sipStack.isAlive()) 667 throw new SipException("Stack is stopped."); 668 669 // mranga: added check to ensure we are not sending empty (keepalive) 670 // message. 671 if (((SIPRequest) request).getRequestLine() != null 672 && request.getMethod().equals(Request.ACK)) { 673 Dialog dialog = sipStack.getDialog(((SIPRequest) request) 674 .getDialogId(false)); 675 if (dialog != null && dialog.getState() != null) { 676 if (sipStack.isLoggingEnabled()) 677 sipStack.getStackLogger().logWarning( 678 "Dialog exists -- you may want to use Dialog.sendAck() " 679 + dialog.getState()); 680 } 681 } 682 Hop hop = sipStack.getRouter((SIPRequest) request).getNextHop(request); 683 if (hop == null) 684 throw new SipException("could not determine next hop!"); 685 SIPRequest sipRequest = (SIPRequest) request; 686 // Check if we have a valid via. 687 // Null request is used to send default proxy keepalive messages. 688 if ((!sipRequest.isNullRequest()) && sipRequest.getTopmostVia() == null) 689 throw new SipException("Invalid SipRequest -- no via header!"); 690 691 try { 692 /* 693 * JvB: Via branch should already be OK, dont touch it here? Some 694 * apps forward statelessly, and then it's not set. So set only when 695 * not set already, dont overwrite CANCEL branch here.. 696 */ 697 if (!sipRequest.isNullRequest()) { 698 Via via = sipRequest.getTopmostVia(); 699 String branch = via.getBranch(); 700 if (branch == null || branch.length() == 0) { 701 via.setBranch(sipRequest.getTransactionId()); 702 } 703 } 704 MessageChannel messageChannel = null; 705 if (this.listeningPoints.containsKey(hop.getTransport() 706 .toUpperCase())) 707 messageChannel = sipStack.createRawMessageChannel( 708 this.getListeningPoint(hop.getTransport()).getIPAddress(), 709 this.getListeningPoint(hop.getTransport()).getPort(), hop); 710 if (messageChannel != null) { 711 messageChannel.sendMessage((SIPMessage) sipRequest,hop); 712 } else { 713 throw new SipException( 714 "Could not create a message channel for " 715 + hop.toString()); 716 } 717 } catch (IOException ex) { 718 if (sipStack.isLoggingEnabled()) { 719 sipStack.getStackLogger().logException(ex); 720 } 721 722 throw new SipException( 723 "IO Exception occured while Sending Request", ex); 724 725 } catch (ParseException ex1) { 726 InternalErrorHandler.handleException(ex1); 727 } finally { 728 if (sipStack.isLoggingEnabled()) 729 sipStack.getStackLogger().logDebug( 730 "done sending " + request.getMethod() + " to hop " 731 + hop); 732 } 733 } 734 735 /* 736 * (non-Javadoc) 737 * 738 * @see javax.sip.SipProvider#sendResponse(javax.sip.message.Response) 739 */ sendResponse(Response response)740 public void sendResponse(Response response) throws SipException { 741 if (!sipStack.isAlive()) 742 throw new SipException("Stack is stopped"); 743 SIPResponse sipResponse = (SIPResponse) response; 744 Via via = sipResponse.getTopmostVia(); 745 if (via == null) 746 throw new SipException("No via header in response!"); 747 SIPServerTransaction st = (SIPServerTransaction) sipStack.findTransaction((SIPMessage)response, true); 748 if ( st != null && st.getState() != TransactionState.TERMINATED && this.isAutomaticDialogSupportEnabled()) { 749 throw new SipException("Transaction exists -- cannot send response statelessly"); 750 } 751 String transport = via.getTransport(); 752 753 // check to see if Via has "received paramaeter". If so 754 // set the host to the via parameter. Else set it to the 755 // Via host. 756 String host = via.getReceived(); 757 758 if (host == null) 759 host = via.getHost(); 760 761 // Symmetric nat support 762 int port = via.getRPort(); 763 if (port == -1) { 764 port = via.getPort(); 765 if (port == -1) { 766 if (transport.equalsIgnoreCase("TLS")) 767 port = 5061; 768 else 769 port = 5060; 770 } 771 } 772 773 // for correct management of IPv6 addresses. 774 if (host.indexOf(":") > 0) 775 if (host.indexOf("[") < 0) 776 host = "[" + host + "]"; 777 778 Hop hop = sipStack.getAddressResolver().resolveAddress( 779 new HopImpl(host, port, transport)); 780 781 try { 782 ListeningPointImpl listeningPoint = (ListeningPointImpl) this 783 .getListeningPoint(transport); 784 if (listeningPoint == null) 785 throw new SipException( 786 "whoopsa daisy! no listening point found for transport " 787 + transport); 788 MessageChannel messageChannel = sipStack.createRawMessageChannel( 789 this.getListeningPoint(hop.getTransport()).getIPAddress(), 790 listeningPoint.port, hop); 791 messageChannel.sendMessage(sipResponse); 792 } catch (IOException ex) { 793 throw new SipException(ex.getMessage()); 794 } 795 } 796 797 /* 798 * (non-Javadoc) 799 * 800 * @see javax.sip.SipProvider#setListeningPoint(javax.sip.ListeningPoint) 801 */ setListeningPoint(ListeningPoint listeningPoint)802 public synchronized void setListeningPoint(ListeningPoint listeningPoint) { 803 if (listeningPoint == null) 804 throw new NullPointerException("Null listening point"); 805 ListeningPointImpl lp = (ListeningPointImpl) listeningPoint; 806 lp.sipProvider = this; 807 String transport = lp.getTransport().toUpperCase(); 808 this.address = listeningPoint.getIPAddress(); 809 this.port = listeningPoint.getPort(); 810 // This is the first listening point. 811 this.listeningPoints.clear(); 812 this.listeningPoints.put(transport, listeningPoint); 813 814 } 815 816 /* 817 * (non-Javadoc) 818 * 819 * @see javax.sip.SipProvider#getNewDialog(javax.sip.Transaction) 820 */ 821 getNewDialog(Transaction transaction)822 public Dialog getNewDialog(Transaction transaction) throws SipException { 823 if (transaction == null) 824 throw new NullPointerException("Null transaction!"); 825 826 if (!sipStack.isAlive()) 827 throw new SipException("Stack is stopped."); 828 829 if (isAutomaticDialogSupportEnabled()) 830 throw new SipException(" Error - AUTOMATIC_DIALOG_SUPPORT is on"); 831 832 if (!sipStack.isDialogCreated(transaction.getRequest().getMethod())) 833 throw new SipException("Dialog cannot be created for this method " 834 + transaction.getRequest().getMethod()); 835 836 SIPDialog dialog = null; 837 SIPTransaction sipTransaction = (SIPTransaction) transaction; 838 839 if (transaction instanceof ServerTransaction) { 840 SIPServerTransaction st = (SIPServerTransaction) transaction; 841 Response response = st.getLastResponse(); 842 if (response != null) { 843 if (response.getStatusCode() != 100) 844 throw new SipException( 845 "Cannot set dialog after response has been sent"); 846 } 847 SIPRequest sipRequest = (SIPRequest) transaction.getRequest(); 848 String dialogId = sipRequest.getDialogId(true); 849 dialog = sipStack.getDialog(dialogId); 850 if (dialog == null) { 851 dialog = sipStack.createDialog((SIPTransaction) transaction); 852 // create and register the dialog and add the inital route set. 853 dialog.addTransaction(sipTransaction); 854 dialog.addRoute(sipRequest); 855 sipTransaction.setDialog(dialog, null); 856 857 } else { 858 sipTransaction.setDialog(dialog, sipRequest.getDialogId(true)); 859 } 860 if (sipRequest.getMethod().equals(Request.INVITE) && this.isDialogErrorsAutomaticallyHandled()) { 861 sipStack.putInMergeTable(st, sipRequest); 862 } 863 } else { 864 865 SIPClientTransaction sipClientTx = (SIPClientTransaction) transaction; 866 867 SIPResponse response = sipClientTx.getLastResponse(); 868 869 if (response == null) { 870 // A response has not yet been received, then set this up as the 871 // default dialog. 872 SIPRequest request = (SIPRequest) sipClientTx.getRequest(); 873 874 String dialogId = request.getDialogId(false); 875 dialog = sipStack.getDialog(dialogId); 876 if (dialog != null) { 877 throw new SipException("Dialog already exists!"); 878 } else { 879 dialog = sipStack.createDialog(sipTransaction); 880 } 881 sipClientTx.setDialog(dialog, null); 882 883 } else { 884 throw new SipException( 885 "Cannot call this method after response is received!"); 886 } 887 } 888 dialog.addEventListener(this); 889 return dialog; 890 891 } 892 893 /** 894 * Invoked when an error has ocurred with a transaction. Propagate up to the 895 * listeners. 896 * 897 * @param transactionErrorEvent 898 * Error event. 899 */ transactionErrorEvent( SIPTransactionErrorEvent transactionErrorEvent)900 public void transactionErrorEvent( 901 SIPTransactionErrorEvent transactionErrorEvent) { 902 SIPTransaction transaction = (SIPTransaction) transactionErrorEvent 903 .getSource(); 904 905 if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TRANSPORT_ERROR) { 906 // There must be a way to inform the TU here!! 907 if (sipStack.isLoggingEnabled()) { 908 sipStack.getStackLogger().logDebug( 909 "TransportError occured on " + transaction); 910 } 911 // Treat this like a timeout event. (Suggestion from Christophe). 912 Object errorObject = transactionErrorEvent.getSource(); 913 Timeout timeout = Timeout.TRANSACTION; 914 TimeoutEvent ev = null; 915 916 if (errorObject instanceof SIPServerTransaction) { 917 ev = new TimeoutEvent(this, (ServerTransaction) errorObject, 918 timeout); 919 } else { 920 SIPClientTransaction clientTx = (SIPClientTransaction) errorObject; 921 Hop hop = clientTx.getNextHop(); 922 if ( sipStack.getRouter() instanceof RouterExt ) { 923 ((RouterExt) sipStack.getRouter()).transactionTimeout(hop); 924 } 925 ev = new TimeoutEvent(this, (ClientTransaction) errorObject, 926 timeout); 927 } 928 // Handling transport error like timeout 929 this.handleEvent(ev, (SIPTransaction) errorObject); 930 } else if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TIMEOUT_ERROR) { 931 // This is a timeout event. 932 Object errorObject = transactionErrorEvent.getSource(); 933 Timeout timeout = Timeout.TRANSACTION; 934 TimeoutEvent ev = null; 935 936 if (errorObject instanceof SIPServerTransaction) { 937 ev = new TimeoutEvent(this, (ServerTransaction) errorObject, 938 timeout); 939 } else { 940 SIPClientTransaction clientTx = (SIPClientTransaction) errorObject; 941 Hop hop = clientTx.getNextHop(); 942 if ( sipStack.getRouter() instanceof RouterExt ) { 943 ((RouterExt) sipStack.getRouter()).transactionTimeout(hop); 944 } 945 946 ev = new TimeoutEvent(this, (ClientTransaction) errorObject, 947 timeout); 948 } 949 this.handleEvent(ev, (SIPTransaction) errorObject); 950 951 } else if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TIMEOUT_RETRANSMIT) { 952 // This is a timeout retransmit event. 953 // We should never get this if retransmit filter is 954 // enabled (ie. in that case the stack should handle. 955 // all retransmits. 956 Object errorObject = transactionErrorEvent.getSource(); 957 Transaction tx = (Transaction) errorObject; 958 959 if (tx.getDialog() != null) 960 InternalErrorHandler.handleException("Unexpected event !", 961 this.sipStack.getStackLogger()); 962 963 Timeout timeout = Timeout.RETRANSMIT; 964 TimeoutEvent ev = null; 965 966 if (errorObject instanceof SIPServerTransaction) { 967 ev = new TimeoutEvent(this, (ServerTransaction) errorObject, 968 timeout); 969 } else { 970 ev = new TimeoutEvent(this, (ClientTransaction) errorObject, 971 timeout); 972 } 973 this.handleEvent(ev, (SIPTransaction) errorObject); 974 } 975 } 976 977 /* 978 * (non-Javadoc) 979 * @see gov.nist.javax.sip.stack.SIPDialogEventListener#dialogErrorEvent(gov.nist.javax.sip.stack.SIPDialogErrorEvent) 980 */ dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent)981 public synchronized void dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent) { 982 SIPDialog sipDialog = (SIPDialog) dialogErrorEvent.getSource(); 983 Reason reason = Reason.AckNotReceived; 984 if (dialogErrorEvent.getErrorID() == SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT) { 985 reason= Reason.AckNotSent; 986 } else if (dialogErrorEvent.getErrorID() == SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT) { 987 reason = Reason.ReInviteTimeout; 988 } 989 if (sipStack.isLoggingEnabled()) { 990 sipStack.getStackLogger().logDebug( 991 "Dialog TimeoutError occured on " + sipDialog); 992 } 993 DialogTimeoutEvent ev = new DialogTimeoutEvent(this, sipDialog, reason); 994 // Handling transport error like timeout 995 this.handleEvent(ev, null); 996 } 997 998 /* 999 * (non-Javadoc) 1000 * 1001 * @see javax.sip.SipProvider#getListeningPoints() 1002 */ getListeningPoints()1003 public synchronized ListeningPoint[] getListeningPoints() { 1004 1005 ListeningPoint[] retval = new ListeningPointImpl[this.listeningPoints 1006 .size()]; 1007 this.listeningPoints.values().toArray(retval); 1008 return retval; 1009 } 1010 1011 /* 1012 * (non-Javadoc) 1013 * 1014 * @see javax.sip.SipProvider#addListeningPoint(javax.sip.ListeningPoint) 1015 */ addListeningPoint(ListeningPoint listeningPoint)1016 public synchronized void addListeningPoint(ListeningPoint listeningPoint) 1017 throws ObjectInUseException { 1018 ListeningPointImpl lp = (ListeningPointImpl) listeningPoint; 1019 if (lp.sipProvider != null && lp.sipProvider != this) 1020 throw new ObjectInUseException( 1021 "Listening point assigned to another provider"); 1022 String transport = lp.getTransport().toUpperCase(); 1023 if (this.listeningPoints.isEmpty()) { 1024 // first one -- record the IP address/port of the LP 1025 1026 this.address = listeningPoint.getIPAddress(); 1027 this.port = listeningPoint.getPort(); 1028 } else { 1029 if ((!this.address.equals(listeningPoint.getIPAddress())) 1030 || this.port != listeningPoint.getPort()) 1031 throw new ObjectInUseException( 1032 "Provider already has different IP Address associated"); 1033 1034 } 1035 if (this.listeningPoints.containsKey(transport) 1036 && this.listeningPoints.get(transport) != listeningPoint) 1037 throw new ObjectInUseException( 1038 "Listening point already assigned for transport!"); 1039 1040 // This is for backwards compatibility. 1041 lp.sipProvider = this; 1042 1043 this.listeningPoints.put(transport, lp); 1044 1045 } 1046 1047 /* 1048 * (non-Javadoc) 1049 * 1050 * @see javax.sip.SipProvider#removeListeningPoint(javax.sip.ListeningPoint) 1051 */ removeListeningPoint(ListeningPoint listeningPoint)1052 public synchronized void removeListeningPoint(ListeningPoint listeningPoint) 1053 throws ObjectInUseException { 1054 ListeningPointImpl lp = (ListeningPointImpl) listeningPoint; 1055 if (lp.messageProcessor.inUse()) 1056 throw new ObjectInUseException("Object is in use"); 1057 this.listeningPoints.remove(lp.getTransport().toUpperCase()); 1058 1059 } 1060 1061 /** 1062 * Remove all the listening points for this sip provider. This is called 1063 * when the stack removes the Provider 1064 */ removeListeningPoints()1065 public synchronized void removeListeningPoints() { 1066 for (Iterator it = this.listeningPoints.values().iterator(); it 1067 .hasNext();) { 1068 ListeningPointImpl lp = (ListeningPointImpl) it.next(); 1069 lp.messageProcessor.stop(); 1070 it.remove(); 1071 } 1072 1073 } 1074 1075 /* 1076 * (non-Javadoc) 1077 * 1078 * @see javax.sip.SipProvider#setAutomaticDialogSupportEnabled(boolean) 1079 */ setAutomaticDialogSupportEnabled( boolean automaticDialogSupportEnabled)1080 public void setAutomaticDialogSupportEnabled( 1081 boolean automaticDialogSupportEnabled) { 1082 this.automaticDialogSupportEnabled = automaticDialogSupportEnabled; 1083 if ( this.automaticDialogSupportEnabled ) { 1084 this.dialogErrorsAutomaticallyHandled = true; 1085 } 1086 } 1087 1088 /** 1089 * @return Returns the automaticDialogSupportEnabled. 1090 */ isAutomaticDialogSupportEnabled()1091 public boolean isAutomaticDialogSupportEnabled() { 1092 return automaticDialogSupportEnabled; 1093 } 1094 1095 /* 1096 * (non-Javadoc) 1097 * @see gov.nist.javax.sip.SipProviderExt#setDialogErrorsAutomaticallyHandled() 1098 */ setDialogErrorsAutomaticallyHandled()1099 public void setDialogErrorsAutomaticallyHandled() { 1100 this.dialogErrorsAutomaticallyHandled = true; 1101 } 1102 isDialogErrorsAutomaticallyHandled()1103 public boolean isDialogErrorsAutomaticallyHandled() { 1104 return this.dialogErrorsAutomaticallyHandled; 1105 } 1106 1107 1108 /** 1109 * @return the sipListener 1110 */ getSipListener()1111 public SipListener getSipListener() { 1112 return sipListener; 1113 } 1114 1115 1116 } 1117