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