14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.jndi.ldap;
27
28 import java.io.BufferedInputStream;
29 import java.io.BufferedOutputStream;
30 import java.io.InterruptedIOException;
31 import java.io.IOException;
32 import java.io.OutputStream;
33 import java.io.InputStream;
34 import java.net.Socket;
35 import javax.net.ssl.SSLSocket;
36
37 import javax.naming.CommunicationException;
38 import javax.naming.ServiceUnavailableException;
39 import javax.naming.NamingException;
40 import javax.naming.InterruptedNamingException;
41
42 import javax.naming.ldap.Control;
43
44 import java.lang.reflect.Method;
45 import java.lang.reflect.Constructor;
46 import java.lang.reflect.InvocationTargetException;
47 import java.util.Arrays;
48 import sun.misc.IOUtils;
49 //import javax.net.SocketFactory;
50
51 /**
52 * A thread that creates a connection to an LDAP server.
53 * After the connection, the thread reads from the connection.
54 * A caller can invoke methods on the instance to read LDAP responses
55 * and to send LDAP requests.
56 * <p>
57 * There is a one-to-one correspondence between an LdapClient and
58 * a Connection. Access to Connection and its methods is only via
59 * LdapClient with two exceptions: SASL authentication and StartTLS.
60 * SASL needs to access Connection's socket IO streams (in order to do encryption
61 * of the security layer). StartTLS needs to do replace IO streams
62 * and close the IO streams on nonfatal close. The code for SASL
63 * authentication can be treated as being the same as from LdapClient
64 * because the SASL code is only ever called from LdapClient, from
65 * inside LdapClient's synchronized authenticate() method. StartTLS is called
66 * directly by the application but should only occur when the underlying
67 * connection is quiet.
68 * <p>
69 * In terms of synchronization, worry about data structures
202 //
203 try {
204 sock = createSocket(host, port, socketFactory, connectTimeout);
205
206 if (debug) {
207 System.err.println("Connection: opening socket: " + host + "," + port);
208 }
209
210 inStream = new BufferedInputStream(sock.getInputStream());
211 outStream = new BufferedOutputStream(sock.getOutputStream());
212
213 } catch (InvocationTargetException e) {
214 Throwable realException = e.getTargetException();
215 // realException.printStackTrace();
216
217 CommunicationException ce =
218 new CommunicationException(host + ":" + port);
219 ce.setRootCause(realException);
220 throw ce;
221 } catch (Exception e) {
222 // Class.forName() seems to do more error checking
223 // and will throw IllegalArgumentException and such.
224 // That's why we need to have a catch all here and
225 // ignore generic exceptions.
226 // Also catches all IO errors generated by socket creation.
227 CommunicationException ce =
228 new CommunicationException(host + ":" + port);
229 ce.setRootCause(e);
230 throw ce;
231 }
232
233 worker = Obj.helper.createThread(this);
234 worker.setDaemon(true);
235 worker.start();
236 }
237
238 /*
239 * Create an InetSocketAddress using the specified hostname and port number.
240 */
241 private Object createInetSocketAddress(String host, int port)
242 throws NoSuchMethodException {
243
244 try {
245 Class<?> inetSocketAddressClass =
246 Class.forName("java.net.InetSocketAddress");
247
248 Constructor<?> inetSocketAddressCons =
249 inetSocketAddressClass.getConstructor(new Class<?>[]{
250 String.class, int.class});
251
252 return inetSocketAddressCons.newInstance(new Object[]{
253 host, new Integer(port)});
254
255 } catch (ClassNotFoundException |
256 InstantiationException |
257 InvocationTargetException |
258 IllegalAccessException e) {
259 throw new NoSuchMethodException();
260
261 }
262 }
263
264 /*
265 * Create a Socket object using the specified socket factory and time limit.
266 *
267 * If a timeout is supplied and unconnected sockets are supported then
268 * an unconnected socket is created and the timeout is applied when
269 * connecting the socket. If a timeout is supplied but unconnected sockets
270 * are not supported then the timeout is ignored and a connected socket
271 * is created.
272 */
273 private Socket createSocket(String host, int port, String socketFactory,
274 int connectTimeout) throws Exception {
275
276 Socket socket = null;
277
278 if (socketFactory != null) {
279
280 // create the factory
281
282 Class<?> socketFactoryClass = Obj.helper.loadClass(socketFactory);
283 Method getDefault =
284 socketFactoryClass.getMethod("getDefault", new Class<?>[]{});
285 Object factory = getDefault.invoke(null, new Object[]{});
286
287 // create the socket
288
289 Method createSocket = null;
290
291 if (connectTimeout > 0) {
292
293 try {
294 createSocket = socketFactoryClass.getMethod("createSocket",
295 new Class<?>[]{});
296
297 Method connect = Socket.class.getMethod("connect",
298 new Class<?>[]{Class.forName("java.net.SocketAddress"),
299 int.class});
300 Object endpoint = createInetSocketAddress(host, port);
301
302 // unconnected socket
303 socket =
304 (Socket)createSocket.invoke(factory, new Object[]{});
305
306 if (debug) {
307 System.err.println("Connection: creating socket with " +
308 "a timeout using supplied socket factory");
309 }
310
311 // connected socket
312 connect.invoke(socket, new Object[]{
313 endpoint, new Integer(connectTimeout)});
314
315 } catch (NoSuchMethodException e) {
316 // continue (but ignore connectTimeout)
317 }
318 }
319
320 if (socket == null) {
321 createSocket = socketFactoryClass.getMethod("createSocket",
322 new Class<?>[]{String.class, int.class});
323
324 if (debug) {
325 System.err.println("Connection: creating socket using " +
326 "supplied socket factory");
327 }
328 // connected socket
329 socket = (Socket) createSocket.invoke(factory,
330 new Object[]{host, new Integer(port)});
331 }
332 } else {
333
334 if (connectTimeout > 0) {
335
336 try {
337 Constructor<Socket> socketCons =
338 Socket.class.getConstructor(new Class<?>[]{});
339
340 Method connect = Socket.class.getMethod("connect",
341 new Class<?>[]{Class.forName("java.net.SocketAddress"),
342 int.class});
343 Object endpoint = createInetSocketAddress(host, port);
344
345 socket = socketCons.newInstance(new Object[]{});
346
347 if (debug) {
348 System.err.println("Connection: creating socket with " +
349 "a timeout");
350 }
351 connect.invoke(socket, new Object[]{
352 endpoint, new Integer(connectTimeout)});
353
354 } catch (NoSuchMethodException e) {
355 // continue (but ignore connectTimeout)
356 }
357 }
358
359 if (socket == null) {
360 if (debug) {
361 System.err.println("Connection: creating socket");
362 }
363 // connected socket
364 socket = new Socket(host, port);
365 }
366 }
367
368 // For LDAP connect timeouts on LDAP over SSL connections must treat
369 // the SSL handshake following socket connection as part of the timeout.
370 // So explicitly set a socket read timeout, trigger the SSL handshake,
371 // then reset the timeout.
372 if (connectTimeout > 0 && socket instanceof SSLSocket) {
373 SSLSocket sslSocket = (SSLSocket) socket;
374 int socketTimeout = sslSocket.getSoTimeout();
375
376 sslSocket.setSoTimeout(connectTimeout); // reuse full timeout value
377 sslSocket.startHandshake();
|
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.jndi.ldap;
27
28 import java.io.BufferedInputStream;
29 import java.io.BufferedOutputStream;
30 import java.io.InterruptedIOException;
31 import java.io.IOException;
32 import java.io.OutputStream;
33 import java.io.InputStream;
34 import java.net.InetSocketAddress;
35 import java.net.Socket;
36 import javax.net.ssl.SSLSocket;
37
38 import javax.naming.CommunicationException;
39 import javax.naming.ServiceUnavailableException;
40 import javax.naming.NamingException;
41 import javax.naming.InterruptedNamingException;
42
43 import javax.naming.ldap.Control;
44
45 import java.lang.reflect.Method;
46 import java.lang.reflect.InvocationTargetException;
47 import java.util.Arrays;
48 import sun.misc.IOUtils;
49 import javax.net.SocketFactory;
50
51 /**
52 * A thread that creates a connection to an LDAP server.
53 * After the connection, the thread reads from the connection.
54 * A caller can invoke methods on the instance to read LDAP responses
55 * and to send LDAP requests.
56 * <p>
57 * There is a one-to-one correspondence between an LdapClient and
58 * a Connection. Access to Connection and its methods is only via
59 * LdapClient with two exceptions: SASL authentication and StartTLS.
60 * SASL needs to access Connection's socket IO streams (in order to do encryption
61 * of the security layer). StartTLS needs to do replace IO streams
62 * and close the IO streams on nonfatal close. The code for SASL
63 * authentication can be treated as being the same as from LdapClient
64 * because the SASL code is only ever called from LdapClient, from
65 * inside LdapClient's synchronized authenticate() method. StartTLS is called
66 * directly by the application but should only occur when the underlying
67 * connection is quiet.
68 * <p>
69 * In terms of synchronization, worry about data structures
202 //
203 try {
204 sock = createSocket(host, port, socketFactory, connectTimeout);
205
206 if (debug) {
207 System.err.println("Connection: opening socket: " + host + "," + port);
208 }
209
210 inStream = new BufferedInputStream(sock.getInputStream());
211 outStream = new BufferedOutputStream(sock.getOutputStream());
212
213 } catch (InvocationTargetException e) {
214 Throwable realException = e.getTargetException();
215 // realException.printStackTrace();
216
217 CommunicationException ce =
218 new CommunicationException(host + ":" + port);
219 ce.setRootCause(realException);
220 throw ce;
221 } catch (Exception e) {
222 // We need to have a catch all here and
223 // ignore generic exceptions.
224 // Also catches all IO errors generated by socket creation.
225 CommunicationException ce =
226 new CommunicationException(host + ":" + port);
227 ce.setRootCause(e);
228 throw ce;
229 }
230
231 worker = Obj.helper.createThread(this);
232 worker.setDaemon(true);
233 worker.start();
234 }
235
236 /*
237 * Create an InetSocketAddress using the specified hostname and port number.
238 */
239 private InetSocketAddress createInetSocketAddress(String host, int port) {
240 return new InetSocketAddress(host, port);
241 }
242
243 /*
244 * Create a Socket object using the specified socket factory and time limit.
245 *
246 * If a timeout is supplied and unconnected sockets are supported then
247 * an unconnected socket is created and the timeout is applied when
248 * connecting the socket. If a timeout is supplied but unconnected sockets
249 * are not supported then the timeout is ignored and a connected socket
250 * is created.
251 */
252 private Socket createSocket(String host, int port, String socketFactory,
253 int connectTimeout) throws Exception {
254
255 Socket socket = null;
256
257 if (socketFactory != null) {
258
259 // create the factory
260
261 Class<? extends SocketFactory> socketFactoryClass =
262 (Class<? extends SocketFactory>) Obj.helper.loadClass
263 (socketFactory);
264 Method getDefault =
265 socketFactoryClass.getMethod("getDefault", new Class<?>[]{});
266 SocketFactory factory = (SocketFactory) getDefault.invoke(null, new Object[]{});
267
268 // create the socket
269
270 if (connectTimeout > 0) {
271
272 InetSocketAddress endpoint =
273 createInetSocketAddress(host, port);
274
275 // unconnected socket
276 socket = factory.createSocket();
277
278 if (debug) {
279 System.err.println("Connection: creating socket with " +
280 "a timeout using supplied socket factory");
281 }
282
283 // connected socket
284 socket.connect(endpoint, connectTimeout);
285 }
286
287 // continue (but ignore connectTimeout)
288 if (socket == null) {
289 if (debug) {
290 System.err.println("Connection: creating socket using " +
291 "supplied socket factory");
292 }
293 // connected socket
294 socket = factory.createSocket(host, port);
295 }
296 } else {
297
298 if (connectTimeout > 0) {
299
300 InetSocketAddress endpoint = createInetSocketAddress(host, port);
301
302 socket = new Socket();
303
304 if (debug) {
305 System.err.println("Connection: creating socket with " +
306 "a timeout");
307 }
308 socket.connect(endpoint, connectTimeout);
309 }
310
311 // continue (but ignore connectTimeout)
312
313 if (socket == null) {
314 if (debug) {
315 System.err.println("Connection: creating socket");
316 }
317 // connected socket
318 socket = new Socket(host, port);
319 }
320 }
321
322 // For LDAP connect timeouts on LDAP over SSL connections must treat
323 // the SSL handshake following socket connection as part of the timeout.
324 // So explicitly set a socket read timeout, trigger the SSL handshake,
325 // then reset the timeout.
326 if (connectTimeout > 0 && socket instanceof SSLSocket) {
327 SSLSocket sslSocket = (SSLSocket) socket;
328 int socketTimeout = sslSocket.getSoTimeout();
329
330 sslSocket.setSoTimeout(connectTimeout); // reuse full timeout value
331 sslSocket.startHandshake();
|