1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Conditions Of Use
3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software was developed by employees of the National Institute of
5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Standards and Technology (NIST), an agency of the Federal Government.
6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Pursuant to title 15 United States Code Section 105, works of NIST
7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * employees are not subject to copyright protection in the United States
8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and are considered to be in the public domain.  As a result, a formal
9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * license is not needed to use the software.
10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software is provided by NIST as a service and is expressly
12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * AND DATA ACCURACY.  NIST does not warrant or make any representations
16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * regarding the use of the software or the results thereof, including but
17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * not limited to the correctness, accuracy, reliability or usefulness of
18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the software.
19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Permission to use this software is contingent upon your acceptance
21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * of the terms of this agreement
22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * .
24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*******************************************************************************
27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *******************************************************************************/
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.stack;
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.StackLogger;
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.SipStackImpl;
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.*;
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.*;
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Enumeration;
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.concurrent.ConcurrentHashMap;
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.concurrent.Semaphore;
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.concurrent.TimeUnit;
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.net.ssl.HandshakeCompletedListener;
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.net.ssl.SSLSocket;
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * TLS support Added by Daniel J.Martinez Manzano <dani@dif.um.es>
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Low level Input output to a socket. Caches TCP connections and takes care of re-connecting to
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the remote party if the other end drops the connection
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan <br/>
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangclass IOHandler {
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private Semaphore ioSemaphore = new Semaphore(1);
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private SipStackImpl sipStack;
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static String TCP = "tcp";
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Added by Daniel J. Martinez Manzano <dani@dif.um.es>
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static String TLS = "tls";
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // A cache of client sockets that can be re-used for
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // sending tcp messages.
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private ConcurrentHashMap<String, Socket> socketTable;
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected static String makeKey(InetAddress addr, int port) {
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return addr.getHostAddress() + ":" + port;
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected IOHandler(SIPTransactionStack sipStack) {
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipStack = (SipStackImpl) sipStack;
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.socketTable = new ConcurrentHashMap<String, Socket>();
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void putSocket(String key, Socket sock) {
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        socketTable.put(key, sock);
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected Socket getSocket(String key) {
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return (Socket) socketTable.get(key);
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void removeSocket(String key) {
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        socketTable.remove(key);
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * A private function to write things out. This needs to be synchronized as writes can occur
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * from multiple threads. We write in chunks to allow the other side to synchronize for large
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * sized writes.
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private void writeChunks(OutputStream outputStream, byte[] bytes, int length)
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throws IOException {
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Chunk size is 16K - this hack is for large
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // writes over slow connections.
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (outputStream) {
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // outputStream.write(bytes,0,length);
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int chunksize = 8 * 1024;
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            for (int p = 0; p < length; p += chunksize) {
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                int chunk = p + chunksize < length ? chunksize : length - p;
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                outputStream.write(bytes, p, chunk);
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        outputStream.flush();
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates and binds, if necessary, a socket connected to the specified destination address
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * and port and then returns its local address.
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param dst the destination address that the socket would need to connect to.
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param dstPort the port number that the connection would be established with.
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param localAddress the address that we would like to bind on (null for the "any" address).
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param localPort the port that we'd like our socket to bind to (0 for a random port).
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the SocketAddress that this handler would use when connecting to the specified
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         destination address and port.
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws IOException
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SocketAddress obtainLocalAddress(InetAddress dst, int dstPort,
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            InetAddress localAddress, int localPort) throws IOException {
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String key = makeKey(dst, dstPort);
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Socket clientSock = getSocket(key);
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (clientSock == null) {
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            clientSock = sipStack.getNetworkLayer().createSocket(dst, dstPort, localAddress,
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    localPort);
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            putSocket(key, clientSock);
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return clientSock.getLocalSocketAddress();
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Send an array of bytes.
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param receiverAddress -- inet address
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param contactPort -- port to connect to.
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param transport -- tcp or udp.
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param retry -- retry to connect if the other end closed connection
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws IOException -- if there is an IO exception sending message.
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Socket sendBytes(InetAddress senderAddress, InetAddress receiverAddress,
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int contactPort, String transport, byte[] bytes, boolean retry,
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            MessageChannel messageChannel) throws IOException {
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int retry_count = 0;
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int max_retry = retry ? 2 : 1;
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Server uses TCP transport. TCP client sockets are cached
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int length = bytes.length;
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled()) {
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug(
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    "sendBytes " + transport + " inAddr " + receiverAddress.getHostAddress()
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            + " port = " + contactPort + " length = " + length);
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled() && sipStack.isLogStackTraceOnMessageSend()) {
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO);
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (transport.compareToIgnoreCase(TCP) == 0) {
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String key = makeKey(receiverAddress, contactPort);
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // This should be in a synchronized block ( reported by
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Jayashenkhar ( lucent ).
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                boolean retval = this.ioSemaphore.tryAcquire(10000, TimeUnit.MILLISECONDS);
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!retval) {
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw new IOException(
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            "Could not acquire IO Semaphore after 10 seconds -- giving up ");
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (InterruptedException ex) {
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new IOException("exception in acquiring sem");
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Socket clientSock = getSocket(key);
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (retry_count < max_retry) {
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (clientSock == null) {
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isLoggingEnabled()) {
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack.getStackLogger().logDebug("inaddr = " + receiverAddress);
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack.getStackLogger().logDebug("port = " + contactPort);
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // note that the IP Address for stack may not be
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // assigned.
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // sender address is the address of the listening point.
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // in version 1.1 all listening points have the same IP
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // address (i.e. that of the stack). In version 1.2
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // the IP address is on a per listening point basis.
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        clientSock = sipStack.getNetworkLayer().createSocket(receiverAddress,
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                contactPort, senderAddress);
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        OutputStream outputStream = clientSock.getOutputStream();
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        writeChunks(outputStream, bytes, length);
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        putSocket(key, clientSock);
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        break;
210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else {
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        try {
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            OutputStream outputStream = clientSock.getOutputStream();
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            writeChunks(outputStream, bytes, length);
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            break;
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        } catch (IOException ex) {
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            if (sipStack.isLoggingEnabled())
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                sipStack.getStackLogger().logDebug(
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        "IOException occured retryCount " + retry_count);
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // old connection is bad.
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // remove from our table.
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            removeSocket(key);
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            try {
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                clientSock.close();
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            } catch (Exception e) {
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            }
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            clientSock = null;
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            retry_count++;
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } finally {
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ioSemaphore.release();
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (clientSock == null) {
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled()) {
238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logDebug(this.socketTable.toString());
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logError(
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            "Could not connect to " + receiverAddress + ":" + contactPort);
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new IOException("Could not connect to " + receiverAddress + ":"
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + contactPort);
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return clientSock;
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Added by Daniel J. Martinez Manzano <dani@dif.um.es>
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Copied and modified from the former section for TCP
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (transport.compareToIgnoreCase(TLS) == 0) {
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String key = makeKey(receiverAddress, contactPort);
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                boolean retval = this.ioSemaphore.tryAcquire(10000, TimeUnit.MILLISECONDS);
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!retval)
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw new IOException("Timeout acquiring IO SEM");
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (InterruptedException ex) {
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new IOException("exception in acquiring sem");
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Socket clientSock = getSocket(key);
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (retry_count < max_retry) {
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (clientSock == null) {
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isLoggingEnabled()) {
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack.getStackLogger().logDebug("inaddr = " + receiverAddress);
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack.getStackLogger().logDebug("port = " + contactPort);
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        clientSock = sipStack.getNetworkLayer().createSSLSocket(receiverAddress,
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                contactPort, senderAddress);
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        SSLSocket sslsock = (SSLSocket) clientSock;
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        HandshakeCompletedListener listner = new HandshakeCompletedListenerImpl(
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                (TLSMessageChannel) messageChannel);
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        ((TLSMessageChannel) messageChannel)
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .setHandshakeCompletedListener(listner);
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sslsock.addHandshakeCompletedListener(listner);
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sslsock.setEnabledProtocols(sipStack.getEnabledProtocols());
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sslsock.startHandshake();
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        OutputStream outputStream = clientSock.getOutputStream();
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        writeChunks(outputStream, bytes, length);
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        putSocket(key, clientSock);
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        break;
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else {
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        try {
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            OutputStream outputStream = clientSock.getOutputStream();
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            writeChunks(outputStream, bytes, length);
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            break;
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        } catch (IOException ex) {
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            if (sipStack.isLoggingEnabled())
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                sipStack.getStackLogger().logException(ex);
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // old connection is bad.
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // remove from our table.
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            removeSocket(key);
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            try {
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                clientSock.close();
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            } catch (Exception e) {
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            }
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            clientSock = null;
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            retry_count++;
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } finally {
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ioSemaphore.release();
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (clientSock == null) {
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new IOException("Could not connect to " + receiverAddress + ":"
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + contactPort);
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return clientSock;
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // This is a UDP transport...
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            DatagramSocket datagramSock = sipStack.getNetworkLayer().createDatagramSocket();
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            datagramSock.connect(receiverAddress, contactPort);
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            DatagramPacket dgPacket = new DatagramPacket(bytes, 0, length, receiverAddress,
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    contactPort);
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            datagramSock.send(dgPacket);
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            datagramSock.close();
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Close all the cached connections.
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void closeAll() {
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        for (Enumeration<Socket> values = socketTable.elements(); values.hasMoreElements();) {
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Socket s = (Socket) values.nextElement();
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                s.close();
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (IOException ex) {
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
341