KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > net > PlainSocketImpl


1 /*
2  * @(#)PlainSocketImpl.java 1.67 07/03/08
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.net;
9
10 import java.io.IOException JavaDoc;
11 import java.io.InputStream JavaDoc;
12 import java.io.OutputStream JavaDoc;
13 import java.io.InterruptedIOException JavaDoc;
14 import java.io.FileDescriptor JavaDoc;
15 import java.io.ByteArrayOutputStream JavaDoc;
16
17 import sun.net.ConnectionResetException;
18
19 /**
20  * Default Socket Implementation. This implementation does
21  * not implement any security checks.
22  * Note this class should <b>NOT</b> be public.
23  *
24  * @author Steven B. Byrne
25  * @version 1.67, 03/08/07
26  */

27 class PlainSocketImpl extends SocketImpl JavaDoc
28 {
29     /* instance variable for SO_TIMEOUT */
30     int timeout; // timeout in millisec
31
// traffic class
32
private int trafficClass;
33
34     private boolean shut_rd = false;
35     private boolean shut_wr = false;
36     
37     private SocketInputStream JavaDoc socketInputStream = null;
38
39     /* number of threads using the FileDescriptor */
40     private int fdUseCount = 0;
41
42     /* lock when increment/decrementing fdUseCount */
43     private Object JavaDoc fdLock = new Object JavaDoc();
44
45     /* indicates a close is pending on the file descriptor */
46     private boolean closePending = false;
47
48     /* indicates connection reset state */
49     private int CONNECTION_NOT_RESET = 0;
50     private int CONNECTION_RESET_PENDING = 1;
51     private int CONNECTION_RESET = 2;
52     private int resetState;
53     private Object JavaDoc resetLock = new Object JavaDoc();
54
55     /* second fd, used for ipv6 on windows only.
56      * fd1 is used for listeners and for client sockets at initialization
57      * until the socket is connected. Up to this point fd always refers
58      * to the ipv4 socket and fd1 to the ipv6 socket. After the socket
59      * becomes connected, fd always refers to the connected socket
60      * (either v4 or v6) and fd1 is closed.
61      *
62      * For ServerSockets, fd always refers to the v4 listener and
63      * fd1 the v6 listener.
64      */

65     private FileDescriptor JavaDoc fd1;
66     /*
67      * Needed for ipv6 on windows because we need to know
68      * if the socket is bound to ::0 or 0.0.0.0, when a caller
69      * asks for it. Otherwise we don't know which socket to ask.
70      */

71     private InetAddress JavaDoc anyLocalBoundAddr=null;
72  
73     /* to prevent starvation when listening on two sockets, this is
74      * is used to hold the id of the last socket we accepted on.
75      */

76     private int lastfd = -1;
77
78     /**
79      * Load net library into runtime.
80      */

81     static {
82     java.security.AccessController.doPrivileged(
83           new sun.security.action.LoadLibraryAction("net"));
84     initProto();
85     }
86
87     /**
88      * Constructs an empty instance.
89      */

90     PlainSocketImpl() { }
91
92     /**
93      * Constructs an instance with the given file descriptor.
94      * Note, this will not work with IPv6, since two fds are used.
95      */

96     PlainSocketImpl(FileDescriptor JavaDoc fd) {
97     this.fd = fd;
98     }
99
100     /**
101      * Creates a socket with a boolean that specifies whether this
102      * is a stream socket (true) or an unconnected UDP socket (false).
103      */

104     protected synchronized void create(boolean stream) throws IOException JavaDoc {
105     fd = new FileDescriptor JavaDoc();
106     fd1 = new FileDescriptor JavaDoc();
107     socketCreate(stream);
108     if (socket != null)
109         socket.setCreated();
110     if (serverSocket != null)
111         serverSocket.setCreated();
112     }
113
114     /**
115      * Creates a socket and connects it to the specified port on
116      * the specified host.
117      * @param host the specified host
118      * @param port the specified port
119      */

120     protected void connect(String JavaDoc host, int port)
121         throws UnknownHostException JavaDoc, IOException JavaDoc
122     {
123     IOException JavaDoc pending = null;
124     try {
125         InetAddress JavaDoc address = InetAddress.getByName(host);
126
127         try {
128         connectToAddress(address, port, timeout);
129         return;
130         } catch (IOException JavaDoc e) {
131         pending = e;
132         }
133     } catch (UnknownHostException JavaDoc e) {
134         pending = e;
135     }
136
137     // everything failed
138
close();
139     throw pending;
140     }
141
142     /**
143      * Creates a socket and connects it to the specified address on
144      * the specified port.
145      * @param address the address
146      * @param port the specified port
147      */

148     protected void connect(InetAddress JavaDoc address, int port) throws IOException JavaDoc {
149     this.port = port;
150     this.address = address;
151
152     try {
153         connectToAddress(address, port, timeout);
154         return;
155     } catch (IOException JavaDoc e) {
156         // everything failed
157
close();
158         throw e;
159     }
160     }
161
162     /**
163      * Creates a socket and connects it to the specified address on
164      * the specified port.
165      * @param address the address
166      * @param timeout the timeout value in milliseconds, or zero for no timeout.
167      * @throws IOException if connection fails
168      * @throws IllegalArgumentException if address is null or is a
169      * SocketAddress subclass not supported by this socket
170      * @since 1.4
171      */

172     protected void connect(SocketAddress JavaDoc address, int timeout) throws IOException JavaDoc {
173     if (address == null || !(address instanceof InetSocketAddress JavaDoc))
174         throw new IllegalArgumentException JavaDoc("unsupported address type");
175     InetSocketAddress JavaDoc addr = (InetSocketAddress JavaDoc) address;
176     if (addr.isUnresolved())
177         throw new UnknownHostException JavaDoc(addr.getHostName());
178     this.port = addr.getPort();
179     this.address = addr.getAddress();
180
181     try {
182         connectToAddress(this.address, port, timeout);
183         return;
184     } catch (IOException JavaDoc e) {
185         // everything failed
186
close();
187         throw e;
188     }
189     }
190
191     private void connectToAddress(InetAddress JavaDoc address, int port, int timeout) throws IOException JavaDoc {
192     if (address.isAnyLocalAddress()) {
193         doConnect(InetAddress.getLocalHost(), port, timeout);
194     } else {
195         doConnect(address, port, timeout);
196     }
197     }
198
199     public void setOption(int opt, Object JavaDoc val) throws SocketException JavaDoc {
200     if (isClosedOrPending()) {
201         throw new SocketException JavaDoc("Socket Closed");
202     }
203     boolean on = true;
204     switch (opt) {
205         /* check type safety b4 going native. These should never
206          * fail, since only java.Socket* has access to
207          * PlainSocketImpl.setOption().
208          */

209     case SO_LINGER:
210         if (val == null || (!(val instanceof Integer JavaDoc) && !(val instanceof Boolean JavaDoc)))
211         throw new SocketException JavaDoc("Bad parameter for option");
212         if (val instanceof Boolean JavaDoc) {
213         /* true only if disabling - enabling should be Integer */
214         on = false;
215         }
216         break;
217     case SO_TIMEOUT:
218         if (val == null || (!(val instanceof Integer JavaDoc)))
219         throw new SocketException JavaDoc("Bad parameter for SO_TIMEOUT");
220         int tmp = ((Integer JavaDoc) val).intValue();
221         if (tmp < 0)
222         throw new IllegalArgumentException JavaDoc("timeout < 0");
223         timeout = tmp;
224         break;
225     case IP_TOS:
226          if (val == null || !(val instanceof Integer JavaDoc)) {
227          throw new SocketException JavaDoc("bad argument for IP_TOS");
228          }
229          trafficClass = ((Integer JavaDoc)val).intValue();
230          break;
231     case SO_BINDADDR:
232         throw new SocketException JavaDoc("Cannot re-bind socket");
233     case TCP_NODELAY:
234         if (val == null || !(val instanceof Boolean JavaDoc))
235         throw new SocketException JavaDoc("bad parameter for TCP_NODELAY");
236         on = ((Boolean JavaDoc)val).booleanValue();
237         break;
238     case SO_SNDBUF:
239     case SO_RCVBUF:
240         if (val == null || !(val instanceof Integer JavaDoc) ||
241         !(((Integer JavaDoc)val).intValue() > 0)) {
242         throw new SocketException JavaDoc("bad parameter for SO_SNDBUF " +
243                       "or SO_RCVBUF");
244         }
245         break;
246     case SO_KEEPALIVE:
247         if (val == null || !(val instanceof Boolean JavaDoc))
248         throw new SocketException JavaDoc("bad parameter for SO_KEEPALIVE");
249         on = ((Boolean JavaDoc)val).booleanValue();
250         break;
251     case SO_OOBINLINE:
252         if (val == null || !(val instanceof Boolean JavaDoc))
253         throw new SocketException JavaDoc("bad parameter for SO_OOBINLINE");
254         on = ((Boolean JavaDoc)val).booleanValue();
255         break;
256     case SO_REUSEADDR:
257         if (val == null || !(val instanceof Boolean JavaDoc))
258             throw new SocketException JavaDoc("bad parameter for SO_REUSEADDR");
259         on = ((Boolean JavaDoc)val).booleanValue();
260         break;
261     default:
262         throw new SocketException JavaDoc("unrecognized TCP option: " + opt);
263     }
264     socketSetOption(opt, on, val);
265     }
266     public Object JavaDoc getOption(int opt) throws SocketException JavaDoc {
267     if (isClosedOrPending()) {
268         throw new SocketException JavaDoc("Socket Closed");
269     }
270     if (opt == SO_TIMEOUT) {
271         return new Integer JavaDoc(timeout);
272     }
273     int ret = 0;
274     /*
275      * The native socketGetOption() knows about 3 options.
276      * The 32 bit value it returns will be interpreted according
277      * to what we're asking. A return of -1 means it understands
278      * the option but its turned off. It will raise a SocketException
279      * if "opt" isn't one it understands.
280      */

281
282     switch (opt) {
283     case TCP_NODELAY:
284         ret = socketGetOption(opt, null);
285         return Boolean.valueOf(ret != -1);
286     case SO_OOBINLINE:
287         ret = socketGetOption(opt, null);
288         return Boolean.valueOf(ret != -1);
289     case SO_LINGER:
290         ret = socketGetOption(opt, null);
291         return (ret == -1) ? Boolean.FALSE: (Object JavaDoc)(new Integer JavaDoc(ret));
292     case SO_REUSEADDR:
293         ret = socketGetOption(opt, null);
294         return Boolean.valueOf(ret != -1);
295     case SO_BINDADDR:
296         if (fd != null && fd1 != null ) {
297         /* must be unbound or else bound to anyLocal */
298         return anyLocalBoundAddr;
299         }
300         InetAddressContainer in = new InetAddressContainer();
301         ret = socketGetOption(opt, in);
302         return in.addr;
303     case SO_SNDBUF:
304         case SO_RCVBUF:
305         ret = socketGetOption(opt, null);
306         return new Integer JavaDoc(ret);
307     case IP_TOS:
308         ret = socketGetOption(opt, null);
309         if (ret == -1) { // ipv6 tos
310
return new Integer JavaDoc(trafficClass);
311         } else {
312         return new Integer JavaDoc(ret);
313         }
314     case SO_KEEPALIVE:
315         ret = socketGetOption(opt, null);
316         return Boolean.valueOf(ret != -1);
317     // should never get here
318
default:
319         return null;
320     }
321     }
322
323     /**
324      * The workhorse of the connection operation. Tries several times to
325      * establish a connection to the given <host, port>. If unsuccessful,
326      * throws an IOException indicating what went wrong.
327      */

328
329     private synchronized void doConnect(InetAddress JavaDoc address, int port, int timeout) throws IOException JavaDoc {
330         try {
331         FileDescriptor JavaDoc fd = acquireFD();
332         try {
333             socketConnect(address, port, timeout);
334         // If we have a ref. to the Socket, then sets the flags
335
// created, bound & connected to true.
336
// This is normally done in Socket.connect() but some
337
// subclasses of Socket may call impl.connect() directly!
338
if (socket != null) {
339             socket.setBound();
340             socket.setConnected();
341         }
342         } finally {
343         releaseFD();
344         }
345     } catch (IOException JavaDoc e) {
346         close();
347         throw e;
348     }
349     }
350
351     /**
352      * Binds the socket to the specified address of the specified local port.
353      * @param address the address
354      * @param port the port
355      */

356     protected synchronized void bind(InetAddress JavaDoc address, int lport)
357     throws IOException JavaDoc
358     {
359     socketBind(address, lport);
360     if (socket != null)
361         socket.setBound();
362     if (serverSocket != null)
363         serverSocket.setBound();
364     if (address.isAnyLocalAddress()) {
365         anyLocalBoundAddr = address;
366     }
367     }
368
369     /**
370      * Listens, for a specified amount of time, for connections.
371      * @param count the amount of time to listen for connections
372      */

373     protected synchronized void listen(int count) throws IOException JavaDoc {
374     socketListen(count);
375     }
376
377     /**
378      * Accepts connections.
379      * @param s the connection
380      */

381     protected synchronized void accept(SocketImpl JavaDoc s) throws IOException JavaDoc {
382     FileDescriptor JavaDoc fd = acquireFD();
383     try {
384         socketAccept(s);
385     } finally {
386         releaseFD();
387     }
388     }
389
390     /**
391      * Gets an InputStream for this socket.
392      */

393     protected synchronized InputStream JavaDoc getInputStream() throws IOException JavaDoc {
394     if (isClosedOrPending()) {
395         throw new IOException JavaDoc("Socket Closed");
396     }
397     if (shut_rd) {
398         throw new IOException JavaDoc("Socket input is shutdown");
399     }
400     if (socketInputStream == null) {
401         socketInputStream = new SocketInputStream JavaDoc(this);
402     }
403     return socketInputStream;
404     }
405
406     void setInputStream(SocketInputStream JavaDoc in) {
407     socketInputStream = in;
408     }
409
410     /**
411      * Gets an OutputStream for this socket.
412      */

413     protected synchronized OutputStream JavaDoc getOutputStream() throws IOException JavaDoc {
414     if (isClosedOrPending()) {
415         throw new IOException JavaDoc("Socket Closed");
416     }
417         if (shut_wr) {
418         throw new IOException JavaDoc("Socket output is shutdown");
419     }
420     return new SocketOutputStream JavaDoc(this);
421     }
422
423     /**
424      * Returns the number of bytes that can be read without blocking.
425      */

426     protected synchronized int available() throws IOException JavaDoc {
427     if (isClosedOrPending()) {
428             throw new IOException JavaDoc("Stream closed.");
429     }
430
431     /*
432      * If connection has been reset then return 0 to indicate
433      * there are no buffered bytes.
434      */

435     if (isConnectionReset()) {
436         return 0;
437     }
438
439     /*
440      * If no bytes available and we were previously notified
441      * of a connection reset then we move to the reset state.
442      *
443      * If are notified of a connection reset then check
444      * again if there are bytes buffered on the socket.
445      */

446     int n = 0;
447     try {
448         n = socketAvailable();
449         if (n == 0 && isConnectionResetPending()) {
450             setConnectionReset();
451         }
452     } catch (ConnectionResetException exc1) {
453         setConnectionResetPending();
454         try {
455             n = socketAvailable();
456         if (n == 0) {
457             setConnectionReset();
458         }
459         } catch (ConnectionResetException exc2) {
460         }
461     }
462     return n;
463     }
464
465     /**
466      * Closes the socket.
467      */

468     protected void close() throws IOException JavaDoc {
469     synchronized(fdLock) {
470         if (fd != null || fd1 != null) {
471         if (fdUseCount == 0) {
472             if (closePending) {
473             return;
474             }
475             closePending = true;
476             /*
477              * We close the FileDescriptor in two-steps - first the
478              * "pre-close" which closes the socket but doesn't
479              * release the underlying file descriptor. This operation
480              * may be lengthy due to untransmitted data and a long
481              * linger interval. Once the pre-close is done we do the
482              * actual socket to release the fd.
483              */

484             try {
485                 socketPreClose();
486             } finally {
487                 socketClose();
488             }
489             fd = null;
490             fd1 = null;
491             return;
492         } else {
493             /*
494              * If a thread has acquired the fd and a close
495              * isn't pending then use a deferred close.
496              * Also decrement fdUseCount to signal the last
497              * thread that releases the fd to close it.
498              */

499             if (!closePending) {
500             closePending = true;
501                 fdUseCount--;
502             socketPreClose();
503             }
504         }
505         }
506     }
507     }
508     
509     void reset() throws IOException JavaDoc {
510         if (fd != null || fd1 != null) {
511             socketClose();
512         }
513         fd = null;
514         fd1 = null;
515         super.reset();
516     }
517
518
519     /**
520      * Shutdown read-half of the socket connection;
521      */

522     protected void shutdownInput() throws IOException JavaDoc {
523       if (fd != null) {
524       socketShutdown(SHUT_RD);
525       if (socketInputStream != null) {
526           socketInputStream.setEOF(true);
527       }
528       shut_rd = true;
529       }
530     }
531
532     /**
533      * Shutdown write-half of the socket connection;
534      */

535     protected void shutdownOutput() throws IOException JavaDoc {
536       if (fd != null) {
537       socketShutdown(SHUT_WR);
538       shut_wr = true;
539       }
540     }
541
542     protected boolean supportsUrgentData () {
543         return true;
544     }
545
546     protected void sendUrgentData (int data) throws IOException JavaDoc {
547         if (fd == null) {
548             throw new IOException JavaDoc("Socket Closed");
549         }
550         socketSendUrgentData (data);
551     }
552
553     /**
554      * Cleans up if the user forgets to close it.
555      */

556     protected void finalize() throws IOException JavaDoc {
557     close();
558     }
559
560
561     /*
562      * "Acquires" and returns the FileDescriptor for this impl
563      *
564      * A corresponding releaseFD is required to "release" the
565      * FileDescriptor.
566      */

567     public final FileDescriptor JavaDoc acquireFD() {
568     synchronized (fdLock) {
569         fdUseCount++;
570         return fd;
571     }
572     }
573
574     /*
575      * "Release" the FileDescriptor for this impl.
576      *
577      * If the use count goes to -1 then the socket is closed.
578      */

579     public final void releaseFD() {
580     synchronized (fdLock) {
581         fdUseCount--;
582         if (fdUseCount == -1) {
583         if (fd != null) {
584                 try {
585             socketClose();
586                 } catch (IOException JavaDoc e) {
587             } finally {
588                 fd = null;
589             }
590         }
591         }
592     }
593     }
594
595     public boolean isConnectionReset() {
596     synchronized (resetLock) {
597         return (resetState == CONNECTION_RESET);
598     }
599     }
600
601     public boolean isConnectionResetPending() {
602     synchronized (resetLock) {
603             return (resetState == CONNECTION_RESET_PENDING);
604         }
605     }
606
607     public void setConnectionReset() {
608     synchronized (resetLock) {
609             resetState = CONNECTION_RESET;
610         }
611     }
612
613     public void setConnectionResetPending() {
614     synchronized (resetLock) {
615             if (resetState == CONNECTION_NOT_RESET) {
616                 resetState = CONNECTION_RESET_PENDING;
617             }
618         }
619
620     }
621
622     /*
623      * Return true if already closed or close is pending
624      */

625     public boolean isClosedOrPending() {
626     /*
627      * Lock on fdLock to ensure that we wait if a
628      * close is in progress.
629      */

630     synchronized (fdLock) {
631         if (closePending || (fd == null && fd1 == null)) {
632         return true;
633         } else {
634         return false;
635         }
636     }
637     }
638
639     /*
640      * Return the current value of SO_TIMEOUT
641      */

642     public int getTimeout() {
643     return timeout;
644     }
645
646     /*
647      * "Pre-close" a socket by dup'ing the file descriptor - this enables
648      * the socket to be closed without releasing the file descriptor.
649      */

650     private void socketPreClose() throws IOException JavaDoc {
651     socketClose0(true);
652     }
653
654     /*
655      * Close the socket (and release the file descriptor).
656      */

657     private void socketClose() throws IOException JavaDoc {
658     socketClose0(false);
659     }
660
661     private native void socketCreate(boolean isServer) throws IOException JavaDoc;
662     private native void socketConnect(InetAddress JavaDoc address, int port, int timeout)
663     throws IOException JavaDoc;
664     private native void socketBind(InetAddress JavaDoc address, int port)
665     throws IOException JavaDoc;
666     private native void socketListen(int count)
667     throws IOException JavaDoc;
668     private native void socketAccept(SocketImpl JavaDoc s)
669     throws IOException JavaDoc;
670     private native int socketAvailable()
671     throws IOException JavaDoc;
672     private native void socketClose0(boolean useDeferredClose)
673     throws IOException JavaDoc;
674     private native void socketShutdown(int howto)
675     throws IOException JavaDoc;
676     private static native void initProto();
677     private native void socketSetOption(int cmd, boolean on, Object JavaDoc value)
678     throws SocketException JavaDoc;
679     private native int socketGetOption(int opt, Object JavaDoc iaContainerObj) throws SocketException JavaDoc;
680     private native int socketGetOption1(int opt, Object JavaDoc iaContainerObj, FileDescriptor JavaDoc fd) throws SocketException JavaDoc;
681     private native void socketSendUrgentData(int data)
682         throws IOException JavaDoc;
683
684     public final static int SHUT_RD = 0;
685     public final static int SHUT_WR = 1;
686 }
687
688 class InetAddressContainer {
689     InetAddress JavaDoc addr;
690 }
691
Popular Tags