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 /* This class is entirely derived from TCPMessageChannel, 27 * by making some minor changes. Daniel J. Martinez Manzano <dani (at) dif.um.es> 28 * made these changes. Ahmet Uyar 29 * <auyar (at) csit.fsu.edu>sent in a bug report for TCP operation of the 30 * JAIN sipStack. Niklas Uhrberg suggested that a mechanism be added to 31 * limit the number of simultaneous open connections. The TLS 32 * Adaptations were contributed by Daniel Martinez. Hagai Sela 33 * contributed a bug fix for symmetric nat. Jeroen van Bemmel 34 * added compensation for buggy clients ( Microsoft RTC clients ). 35 * Bug fixes by viswashanti.kadiyala (at) antepo.com, Joost Yervante Damand 36 * Lamine Brahimi (IBM Zurich) sent in a bug fix - a thread was being uncessarily created. 37 */ 38 39 /****************************************************************************** 40 * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * 41 ******************************************************************************/ 42 package gov.nist.javax.sip.stack; 43 44 import gov.nist.javax.sip.header.*; 45 import gov.nist.javax.sip.message.*; 46 import gov.nist.javax.sip.parser.*; 47 import gov.nist.core.*; 48 import java.net.*; 49 import java.io.*; 50 import java.text.ParseException; 51 52 import javax.net.ssl.HandshakeCompletedListener; 53 import javax.net.ssl.SSLSocket; 54 import javax.sip.address.Hop; 55 import javax.sip.message.Response; 56 57 /** 58 * This is sipStack for TLS connections. This abstracts a stream of parsed messages. The SIP 59 * sipStack starts this from the main SIPStack class for each connection that it accepts. It 60 * starts a message parser in its own thread and talks to the message parser via a pipe. The 61 * message parser calls back via the parseError or processMessage functions that are defined as 62 * part of the SIPMessageListener interface. 63 * 64 * @see gov.nist.javax.sip.parser.PipelinedMsgParser 65 * 66 * 67 * @author M. Ranganathan 68 * 69 * 70 * @version 1.2 $Revision: 1.27 $ $Date: 2010/01/10 00:13:14 $ 71 */ 72 public final class TLSMessageChannel extends MessageChannel implements SIPMessageListener, 73 Runnable, RawMessageChannel { 74 75 private Socket mySock; 76 77 private PipelinedMsgParser myParser; 78 79 private InputStream myClientInputStream; // just to pass to thread. 80 81 private String key; 82 83 protected boolean isCached; 84 85 protected boolean isRunning; 86 87 private Thread mythread; 88 89 private String myAddress; 90 91 private int myPort; 92 93 private InetAddress peerAddress; 94 95 private int peerPort; 96 97 private String peerProtocol; 98 99 // Incremented whenever a transaction gets assigned 100 // to the message channel and decremented when 101 // a transaction gets freed from the message channel. 102 // protected int useCount = 0; 103 104 private TLSMessageProcessor tlsMessageProcessor; 105 106 private SIPTransactionStack sipStack; 107 108 private HandshakeCompletedListener handshakeCompletedListener; 109 110 /** 111 * Constructor - gets called from the SIPStack class with a socket on accepting a new client. 112 * All the processing of the message is done here with the sipStack being freed up to handle 113 * new connections. The sock input is the socket that is returned from the accept. Global data 114 * that is shared by all threads is accessible in the Server structure. 115 * 116 * @param sock Socket from which to read and write messages. The socket is already connected 117 * (was created as a result of an accept). 118 * 119 * @param sipStack Ptr to SIP Stack 120 * 121 * @param msgProcessor -- the message processor that created us. 122 */ 123 124 protected TLSMessageChannel(Socket sock, SIPTransactionStack sipStack, 125 TLSMessageProcessor msgProcessor) throws IOException { 126 if (sipStack.isLoggingEnabled()) { 127 sipStack.getStackLogger().logDebug("creating new TLSMessageChannel (incoming)"); 128 sipStack.getStackLogger().logStackTrace(); 129 } 130 131 mySock = (SSLSocket) sock; 132 if ( sock instanceof SSLSocket ) { 133 134 SSLSocket sslSock = (SSLSocket) sock; 135 sslSock.setNeedClientAuth(true); 136 this.handshakeCompletedListener = new HandshakeCompletedListenerImpl(this); 137 sslSock.addHandshakeCompletedListener(this.handshakeCompletedListener); 138 sslSock.startHandshake(); 139 140 } 141 142 peerAddress = mySock.getInetAddress(); 143 myAddress = msgProcessor.getIpAddress().getHostAddress(); 144 myClientInputStream = mySock.getInputStream(); 145 146 mythread = new Thread(this); 147 mythread.setDaemon(true); 148 mythread.setName("TLSMessageChannelThread"); 149 // Stash away a pointer to our sipStack structure. 150 this.sipStack = sipStack; 151 152 this.tlsMessageProcessor = msgProcessor; 153 this.myPort = this.tlsMessageProcessor.getPort(); 154 this.peerPort = mySock.getPort(); 155 // Bug report by Vishwashanti Raj Kadiayl 156 super.messageProcessor = msgProcessor; 157 // Can drop this after response is sent potentially. 158 mythread.start(); 159 } 160 161 /** 162 * Constructor - connects to the given inet address. 163 * 164 * @param inetAddr inet address to connect to. 165 * @param sipStack is the sip sipStack from which we are created. 166 * @param messageProcessor -- the message processor that created us. 167 * @throws IOException if we cannot connect. 168 */ 169 protected TLSMessageChannel(InetAddress inetAddr, int port, SIPTransactionStack sipStack, 170 TLSMessageProcessor messageProcessor) throws IOException { 171 if (sipStack.isLoggingEnabled()) { 172 sipStack.getStackLogger().logDebug("creating new TLSMessageChannel (outgoing)"); 173 sipStack.getStackLogger().logStackTrace(); 174 } 175 this.peerAddress = inetAddr; 176 this.peerPort = port; 177 this.myPort = messageProcessor.getPort(); 178 this.peerProtocol = "TLS"; 179 this.sipStack = sipStack; 180 this.tlsMessageProcessor = messageProcessor; 181 this.myAddress = messageProcessor.getIpAddress().getHostAddress(); 182 this.key = MessageChannel.getKey(peerAddress, peerPort, "TLS"); 183 super.messageProcessor = messageProcessor; 184 185 } 186 187 /** 188 * Returns "true" as this is a reliable transport. 189 */ 190 public boolean isReliable() { 191 return true; 192 } 193 194 /** 195 * Close the message channel. 196 */ 197 public void close() { 198 try { 199 if (mySock != null) 200 mySock.close(); 201 if (sipStack.isLoggingEnabled()) 202 sipStack.getStackLogger().logDebug("Closing message Channel " + this); 203 } catch (IOException ex) { 204 if (sipStack.isLoggingEnabled()) 205 sipStack.getStackLogger().logDebug("Error closing socket " + ex); 206 } 207 } 208 209 /** 210 * Get my SIP Stack. 211 * 212 * @return The SIP Stack for this message channel. 213 */ 214 public SIPTransactionStack getSIPStack() { 215 return sipStack; 216 } 217 218 /** 219 * get the transport string. 220 * 221 * @return "tcp" in this case. 222 */ 223 public String getTransport() { 224 return "tls"; 225 } 226 227 /** 228 * get the address of the client that sent the data to us. 229 * 230 * @return Address of the client that sent us data that resulted in this channel being 231 * created. 232 */ 233 public String getPeerAddress() { 234 if (peerAddress != null) { 235 return peerAddress.getHostAddress(); 236 } else 237 return getHost(); 238 } 239 240 protected InetAddress getPeerInetAddress() { 241 return peerAddress; 242 } 243 244 public String getPeerProtocol() { 245 return this.peerProtocol; 246 } 247 248 /** 249 * Send message to whoever is connected to us. Uses the topmost via address to send to. 250 * 251 * @param msg is the message to send. 252 * @param retry 253 */ 254 private void sendMessage(byte[] msg, boolean retry) throws IOException { 255 Socket sock = this.sipStack.ioHandler.sendBytes( 256 this.getMessageProcessor().getIpAddress(), this.peerAddress, this.peerPort, 257 this.peerProtocol, msg, retry,this); 258 // Created a new socket so close the old one and stick the new 259 // one in its place but dont do this if it is a datagram socket. 260 // (could have replied via udp but received via tcp!). 261 if (sock != mySock && sock != null) { 262 try { 263 if (mySock != null) 264 mySock.close(); 265 } catch (IOException ex) { 266 } 267 mySock = sock; 268 this.myClientInputStream = mySock.getInputStream(); 269 270 Thread thread = new Thread(this); 271 thread.setDaemon(true); 272 thread.setName("TLSMessageChannelThread"); 273 thread.start(); 274 } 275 276 } 277 278 /** 279 * Return a formatted message to the client. We try to re-connect with the peer on the other 280 * end if possible. 281 * 282 * @param sipMessage Message to send. 283 * @throws IOException If there is an error sending the message 284 */ 285 public void sendMessage(SIPMessage sipMessage) throws IOException { 286 byte[] msg = sipMessage.encodeAsBytes(this.getTransport()); 287 288 long time = System.currentTimeMillis(); 289 290 this.sendMessage(msg, sipMessage instanceof SIPRequest); 291 292 if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) 293 logMessage(sipMessage, peerAddress, peerPort, time); 294 } 295 296 /** 297 * Send a message to a specified address. 298 * 299 * @param message Pre-formatted message to send. 300 * @param receiverAddress Address to send it to. 301 * @param receiverPort Receiver port. 302 * @throws IOException If there is a problem connecting or sending. 303 */ 304 public void sendMessage(byte message[], InetAddress receiverAddress, int receiverPort, 305 boolean retry) throws IOException { 306 if (message == null || receiverAddress == null) 307 throw new IllegalArgumentException("Null argument"); 308 Socket sock = this.sipStack.ioHandler.sendBytes(this.messageProcessor.getIpAddress(), 309 receiverAddress, receiverPort, "TLS", message, retry, this); 310 // 311 // Created a new socket so close the old one and s 312 // Check for null (bug fix sent in by Christophe) 313 if (sock != mySock && sock != null) { 314 try { 315 if (mySock != null) 316 mySock.close(); 317 } catch (IOException ex) { 318 /* ignore */ 319 } 320 mySock = sock; 321 this.myClientInputStream = mySock.getInputStream(); 322 323 // start a new reader on this end of the pipe. 324 Thread mythread = new Thread(this); 325 mythread.setDaemon(true); 326 mythread.setName("TLSMessageChannelThread"); 327 mythread.start(); 328 } 329 330 } 331 332 /** 333 * Exception processor for exceptions detected from the parser. (This is invoked by the parser 334 * when an error is detected). 335 * 336 * @param sipMessage -- the message that incurred the error. 337 * @param ex -- parse exception detected by the parser. 338 * @param header -- header that caused the error. 339 * @throws ParseException Thrown if we want to reject the message. 340 */ 341 public void handleException(ParseException ex, SIPMessage sipMessage, Class hdrClass, 342 String header, String message) throws ParseException { 343 if (sipStack.isLoggingEnabled()) 344 sipStack.getStackLogger().logException(ex); 345 // Log the bad message for later reference. 346 if ((hdrClass != null) 347 && (hdrClass.equals(From.class) || hdrClass.equals(To.class) 348 || hdrClass.equals(CSeq.class) || hdrClass.equals(Via.class) 349 || hdrClass.equals(CallID.class) || hdrClass.equals(RequestLine.class) || hdrClass 350 .equals(StatusLine.class))) { 351 if (sipStack.isLoggingEnabled()) 352 sipStack.getStackLogger().logDebug("Encountered bad message \n" + message); 353 // JvB: send a 400 response for requests (except ACK) 354 String msgString = sipMessage.toString(); 355 if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) { 356 357 String badReqRes = createBadReqRes(msgString, ex); 358 if (badReqRes != null) { 359 if (sipStack.isLoggingEnabled()) { 360 sipStack.getStackLogger().logDebug("Sending automatic 400 Bad Request:"); 361 sipStack.getStackLogger().logDebug(badReqRes); 362 } 363 try { 364 this.sendMessage(badReqRes.getBytes(), this.getPeerInetAddress(), this 365 .getPeerPort(), false); 366 } catch (IOException e) { 367 this.sipStack.getStackLogger().logException(e); 368 } 369 } else { 370 if (sipStack.isLoggingEnabled()) { 371 sipStack.getStackLogger().logDebug( 372 "Could not formulate automatic 400 Bad Request"); 373 } 374 } 375 } 376 throw ex; 377 } else { 378 sipMessage.addUnparsed(header); 379 } 380 } 381 382 /** 383 * Gets invoked by the parser as a callback on successful message parsing (i.e. no parser 384 * errors). 385 * 386 * @param sipMessage Message to process (this calls the application for processing the 387 * message). 388 * 389 * Jvb: note that this code is identical to TCPMessageChannel, refactor some day 390 */ 391 public void processMessage(SIPMessage sipMessage) throws Exception { 392 try { 393 if (sipMessage.getFrom() == null || sipMessage.getTo() == null 394 || sipMessage.getCallId() == null || sipMessage.getCSeq() == null 395 || sipMessage.getViaHeaders() == null) { 396 String badmsg = sipMessage.encode(); 397 if (sipStack.isLoggingEnabled()) { 398 sipStack.getStackLogger().logError("bad message " + badmsg); 399 sipStack.getStackLogger().logError(">>> Dropped Bad Msg"); 400 } 401 return; 402 } 403 404 ViaList viaList = sipMessage.getViaHeaders(); 405 // For a request 406 // first via header tells where the message is coming from. 407 // For response, this has already been recorded in the outgoing 408 // message. 409 410 if (sipMessage instanceof SIPRequest) { 411 Via v = (Via) viaList.getFirst(); 412 // the peer address and tag it appropriately. 413 Hop hop = sipStack.addressResolver.resolveAddress(v.getHop()); 414 this.peerProtocol = v.getTransport(); 415 try { 416 this.peerAddress = mySock.getInetAddress(); 417 // Check to see if the received parameter matches 418 // JvB: dont do this. It is both costly and incorrect 419 // Must set received also when it is a FQDN, regardless whether 420 // it resolves to the correct IP address 421 // InetAddress sentByAddress = InetAddress.getByName(hop.getHost()); 422 // JvB: if sender added 'rport', must always set received 423 if (v.hasParameter(Via.RPORT) 424 || !hop.getHost().equals(this.peerAddress.getHostAddress())) { 425 v.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress()); 426 } 427 // @@@ hagai 428 // JvB: technically, may only do this when Via already contains 429 // rport 430 v.setParameter(Via.RPORT, Integer.toString(this.peerPort)); 431 } catch (java.text.ParseException ex) { 432 InternalErrorHandler.handleException(ex); 433 } 434 // Use this for outgoing messages as well. 435 if (!this.isCached) { 436 ((TLSMessageProcessor) this.messageProcessor).cacheMessageChannel(this); 437 this.isCached = true; 438 String key = IOHandler.makeKey(mySock.getInetAddress(), this.peerPort); 439 sipStack.ioHandler.putSocket(key, mySock); 440 } 441 } 442 443 // Foreach part of the request header, fetch it and process it 444 445 long receptionTime = System.currentTimeMillis(); 446 // 447 448 if (sipMessage instanceof SIPRequest) { 449 // This is a request - process the request. 450 SIPRequest sipRequest = (SIPRequest) sipMessage; 451 // Create a new sever side request processor for this 452 // message and let it handle the rest. 453 454 if (sipStack.isLoggingEnabled()) { 455 sipStack.getStackLogger().logDebug("----Processing Message---"); 456 } 457 if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) { 458 459 sipStack.serverLogger.logMessage(sipMessage, this.getPeerHostPort().toString(), 460 this.messageProcessor.getIpAddress().getHostAddress() + ":" 461 + this.messageProcessor.getPort(), false, receptionTime); 462 463 } 464 // Check for reasonable size - reject message 465 // if it is too long. 466 if (sipStack.getMaxMessageSize() > 0 467 && sipRequest.getSize() 468 + (sipRequest.getContentLength() == null ? 0 : sipRequest 469 .getContentLength().getContentLength()) > sipStack 470 .getMaxMessageSize()) { 471 SIPResponse sipResponse = sipRequest 472 .createResponse(SIPResponse.MESSAGE_TOO_LARGE); 473 byte[] resp = sipResponse.encodeAsBytes(this.getTransport()); 474 this.sendMessage(resp, false); 475 throw new Exception("Message size exceeded"); 476 } 477 478 // Stack could not create a new server request interface. 479 // maybe not enough resources. 480 ServerRequestInterface sipServerRequest = sipStack.newSIPServerRequest( 481 sipRequest, this); 482 if (sipServerRequest != null) { 483 try { 484 sipServerRequest.processRequest(sipRequest, this); 485 } finally { 486 if (sipServerRequest instanceof SIPTransaction) { 487 SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest; 488 if (!sipServerTx.passToListener()) 489 ((SIPTransaction) sipServerRequest).releaseSem(); 490 } 491 } 492 } else { 493 SIPResponse response = sipRequest 494 .createResponse(Response.SERVICE_UNAVAILABLE); 495 496 RetryAfter retryAfter = new RetryAfter(); 497 498 // Be a good citizen and send a decent response code back. 499 try { 500 retryAfter.setRetryAfter((int) (10 * (Math.random()))); 501 response.setHeader(retryAfter); 502 this.sendMessage(response); 503 } catch (Exception e) { 504 // IGNore 505 } 506 if (sipStack.isLoggingEnabled()) 507 sipStack.getStackLogger() 508 .logWarning("Dropping message -- could not acquire semaphore"); 509 } 510 } else { 511 SIPResponse sipResponse = (SIPResponse) sipMessage; 512 try { 513 sipResponse.checkHeaders(); 514 } catch (ParseException ex) { 515 if (sipStack.isLoggingEnabled()) 516 sipStack.getStackLogger() 517 .logError("Dropping Badly formatted response message >>> " 518 + sipResponse); 519 return; 520 } 521 // This is a response message - process it. 522 // Check the size of the response. 523 // If it is too large dump it silently. 524 if (sipStack.getMaxMessageSize() > 0 525 && sipResponse.getSize() 526 + (sipResponse.getContentLength() == null ? 0 : sipResponse 527 .getContentLength().getContentLength()) > sipStack 528 .getMaxMessageSize()) { 529 if (sipStack.isLoggingEnabled()) 530 this.sipStack.getStackLogger().logDebug("Message size exceeded"); 531 return; 532 533 } 534 ServerResponseInterface sipServerResponse = sipStack.newSIPServerResponse( 535 sipResponse, this); 536 if (sipServerResponse != null) { 537 try { 538 if (sipServerResponse instanceof SIPClientTransaction 539 && !((SIPClientTransaction) sipServerResponse) 540 .checkFromTag(sipResponse)) { 541 if (sipStack.isLoggingEnabled()) 542 sipStack.getStackLogger() 543 .logError("Dropping response message with invalid tag >>> " 544 + sipResponse); 545 return; 546 } 547 548 sipServerResponse.processResponse(sipResponse, this); 549 } finally { 550 if (sipServerResponse instanceof SIPTransaction 551 && !((SIPTransaction) sipServerResponse).passToListener()) { 552 // Note that the semaphore is released in event 553 // scanner if the 554 // request is actually processed by the Listener. 555 ((SIPTransaction) sipServerResponse).releaseSem(); 556 } 557 } 558 } else { 559 sipStack.getStackLogger().logWarning("Could not get semaphore... dropping response"); 560 } 561 } 562 } finally { 563 } 564 } 565 566 /** 567 * This gets invoked when thread.start is called from the constructor. Implements a message 568 * loop - reading the tcp connection and processing messages until we are done or the other 569 * end has closed. 570 */ 571 public void run() { 572 Pipeline hispipe = null; 573 // Create a pipeline to connect to our message parser. 574 hispipe = new Pipeline(myClientInputStream, sipStack.readTimeout, 575 ((SIPTransactionStack) sipStack).getTimer()); 576 // Create a pipelined message parser to read and parse 577 // messages that we write out to him. 578 myParser = new PipelinedMsgParser(this, hispipe, this.sipStack.getMaxMessageSize()); 579 // Start running the parser thread. 580 myParser.processInput(); 581 // bug fix by Emmanuel Proulx 582 int bufferSize = 4096; 583 this.tlsMessageProcessor.useCount++; 584 this.isRunning = true; 585 try { 586 while (true) { 587 try { 588 byte[] msg = new byte[bufferSize]; 589 int nbytes = myClientInputStream.read(msg, 0, bufferSize); 590 // no more bytes to read... 591 if (nbytes == -1) { 592 hispipe.write("\r\n\r\n".getBytes("UTF-8")); 593 try { 594 if (sipStack.maxConnections != -1) { 595 synchronized (tlsMessageProcessor) { 596 tlsMessageProcessor.nConnections--; 597 tlsMessageProcessor.notify(); 598 } 599 } 600 hispipe.close(); 601 mySock.close(); 602 } catch (IOException ioex) { 603 } 604 return; 605 } 606 hispipe.write(msg, 0, nbytes); 607 608 } catch (IOException ex) { 609 // Terminate the message. 610 try { 611 hispipe.write("\r\n\r\n".getBytes("UTF-8")); 612 } catch (Exception e) { 613 // InternalErrorHandler.handleException(e); 614 } 615 616 try { 617 if (sipStack.isLoggingEnabled()) 618 sipStack.getStackLogger().logDebug("IOException closing sock " + ex); 619 try { 620 if (sipStack.maxConnections != -1) { 621 synchronized (tlsMessageProcessor) { 622 tlsMessageProcessor.nConnections--; 623 tlsMessageProcessor.notify(); 624 } 625 } 626 mySock.close(); 627 hispipe.close(); 628 } catch (IOException ioex) { 629 } 630 } catch (Exception ex1) { 631 // Do nothing. 632 } 633 return; 634 } catch (Exception ex) { 635 InternalErrorHandler.handleException(ex); 636 } 637 } 638 } finally { 639 this.isRunning = false; 640 this.tlsMessageProcessor.remove(this); 641 this.tlsMessageProcessor.useCount--; 642 this.myParser.close(); 643 } 644 645 } 646 647 protected void uncache() { 648 if (isCached && !isRunning) { 649 this.tlsMessageProcessor.remove(this); 650 } 651 } 652 653 /** 654 * Equals predicate. 655 * 656 * @param other is the other object to compare ourselves to for equals 657 */ 658 659 public boolean equals(Object other) { 660 661 if (!this.getClass().equals(other.getClass())) 662 return false; 663 else { 664 TLSMessageChannel that = (TLSMessageChannel) other; 665 if (this.mySock != that.mySock) 666 return false; 667 else 668 return true; 669 } 670 } 671 672 /** 673 * Get an identifying key. This key is used to cache the connection and re-use it if 674 * necessary. 675 */ 676 public String getKey() { 677 if (this.key != null) { 678 return this.key; 679 } else { 680 this.key = MessageChannel.getKey(this.peerAddress, this.peerPort, "TLS"); 681 return this.key; 682 } 683 } 684 685 /** 686 * Get the host to assign to outgoing messages. 687 * 688 * @return the host to assign to the via header. 689 */ 690 public String getViaHost() { 691 return myAddress; 692 } 693 694 /** 695 * Get the port for outgoing messages sent from the channel. 696 * 697 * @return the port to assign to the via header. 698 */ 699 public int getViaPort() { 700 return myPort; 701 } 702 703 /** 704 * Get the port of the peer to whom we are sending messages. 705 * 706 * @return the peer port. 707 */ 708 public int getPeerPort() { 709 return peerPort; 710 } 711 712 public int getPeerPacketSourcePort() { 713 return this.peerPort; 714 } 715 716 public InetAddress getPeerPacketSourceAddress() { 717 return this.peerAddress; 718 } 719 720 /** 721 * TLS Is a secure protocol. 722 */ 723 public boolean isSecure() { 724 return true; 725 } 726 727 public void setHandshakeCompletedListener( 728 HandshakeCompletedListener handshakeCompletedListenerImpl) { 729 this.handshakeCompletedListener = handshakeCompletedListenerImpl; 730 } 731 732 /** 733 * @return the handshakeCompletedListener 734 */ 735 public HandshakeCompletedListenerImpl getHandshakeCompletedListener() { 736 return (HandshakeCompletedListenerImpl) handshakeCompletedListener; 737 } 738 } 739