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@dif.um.es>
28 * made these changes. Ahmet Uyar
29 * <auyar@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@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 ******************************************************************************/
42package gov.nist.javax.sip.stack;
43
44import gov.nist.javax.sip.header.*;
45import gov.nist.javax.sip.message.*;
46import gov.nist.javax.sip.parser.*;
47import gov.nist.core.*;
48import java.net.*;
49import java.io.*;
50import java.text.ParseException;
51
52import javax.net.ssl.HandshakeCompletedListener;
53import javax.net.ssl.SSLSocket;
54import javax.sip.address.Hop;
55import 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 */
72public 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