View Javadoc
1   /*
2    * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
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 java.net;
27  
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.io.OutputStream;
31  import java.io.FileDescriptor;
32  
33  import sun.net.ConnectionResetException;
34  import sun.net.NetHooks;
35  import sun.net.ResourceManager;
36  
37  /**
38   * Default Socket Implementation. This implementation does
39   * not implement any security checks.
40   * Note this class should <b>NOT</b> be public.
41   *
42   * @author  Steven B. Byrne
43   */
44  abstract class AbstractPlainSocketImpl extends SocketImpl
45  {
46      /* instance variable for SO_TIMEOUT */
47      int timeout;   // timeout in millisec
48      // traffic class
49      private int trafficClass;
50  
51      private boolean shut_rd = false;
52      private boolean shut_wr = false;
53  
54      private SocketInputStream socketInputStream = null;
55      private SocketOutputStream socketOutputStream = null;
56  
57      /* number of threads using the FileDescriptor */
58      protected int fdUseCount = 0;
59  
60      /* lock when increment/decrementing fdUseCount */
61      protected final Object fdLock = new Object();
62  
63      /* indicates a close is pending on the file descriptor */
64      protected boolean closePending = false;
65  
66      /* indicates connection reset state */
67      private int CONNECTION_NOT_RESET = 0;
68      private int CONNECTION_RESET_PENDING = 1;
69      private int CONNECTION_RESET = 2;
70      private int resetState;
71      private final Object resetLock = new Object();
72  
73     /* whether this Socket is a stream (TCP) socket or not (UDP)
74      */
75      protected boolean stream;
76  
77      /**
78       * Load net library into runtime.
79       */
80      static {
81          java.security.AccessController.doPrivileged(
82              new java.security.PrivilegedAction<Void>() {
83                  public Void run() {
84                      System.loadLibrary("net");
85                      return null;
86                  }
87              });
88      }
89  
90      /**
91       * Creates a socket with a boolean that specifies whether this
92       * is a stream socket (true) or an unconnected UDP socket (false).
93       */
94      protected synchronized void create(boolean stream) throws IOException {
95          this.stream = stream;
96          if (!stream) {
97              ResourceManager.beforeUdpCreate();
98              // only create the fd after we know we will be able to create the socket
99              fd = new FileDescriptor();
100             try {
101                 socketCreate(false);
102             } catch (IOException ioe) {
103                 ResourceManager.afterUdpClose();
104                 fd = null;
105                 throw ioe;
106             }
107         } else {
108             fd = new FileDescriptor();
109             socketCreate(true);
110         }
111         if (socket != null)
112             socket.setCreated();
113         if (serverSocket != null)
114             serverSocket.setCreated();
115     }
116 
117     /**
118      * Creates a socket and connects it to the specified port on
119      * the specified host.
120      * @param host the specified host
121      * @param port the specified port
122      */
123     protected void connect(String host, int port)
124         throws UnknownHostException, IOException
125     {
126         boolean connected = false;
127         try {
128             InetAddress address = InetAddress.getByName(host);
129             this.port = port;
130             this.address = address;
131 
132             connectToAddress(address, port, timeout);
133             connected = true;
134         } finally {
135             if (!connected) {
136                 try {
137                     close();
138                 } catch (IOException ioe) {
139                     /* Do nothing. If connect threw an exception then
140                        it will be passed up the call stack */
141                 }
142             }
143         }
144     }
145 
146     /**
147      * Creates a socket and connects it to the specified address on
148      * the specified port.
149      * @param address the address
150      * @param port the specified port
151      */
152     protected void connect(InetAddress address, int port) throws IOException {
153         this.port = port;
154         this.address = address;
155 
156         try {
157             connectToAddress(address, port, timeout);
158             return;
159         } catch (IOException e) {
160             // everything failed
161             close();
162             throw e;
163         }
164     }
165 
166     /**
167      * Creates a socket and connects it to the specified address on
168      * the specified port.
169      * @param address the address
170      * @param timeout the timeout value in milliseconds, or zero for no timeout.
171      * @throws IOException if connection fails
172      * @throws  IllegalArgumentException if address is null or is a
173      *          SocketAddress subclass not supported by this socket
174      * @since 1.4
175      */
176     protected void connect(SocketAddress address, int timeout)
177             throws IOException {
178         boolean connected = false;
179         try {
180             if (address == null || !(address instanceof InetSocketAddress))
181                 throw new IllegalArgumentException("unsupported address type");
182             InetSocketAddress addr = (InetSocketAddress) address;
183             if (addr.isUnresolved())
184                 throw new UnknownHostException(addr.getHostName());
185             this.port = addr.getPort();
186             this.address = addr.getAddress();
187 
188             connectToAddress(this.address, port, timeout);
189             connected = true;
190         } finally {
191             if (!connected) {
192                 try {
193                     close();
194                 } catch (IOException ioe) {
195                     /* Do nothing. If connect threw an exception then
196                        it will be passed up the call stack */
197                 }
198             }
199         }
200     }
201 
202     private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {
203         if (address.isAnyLocalAddress()) {
204             doConnect(InetAddress.getLocalHost(), port, timeout);
205         } else {
206             doConnect(address, port, timeout);
207         }
208     }
209 
210     public void setOption(int opt, Object val) throws SocketException {
211         if (isClosedOrPending()) {
212             throw new SocketException("Socket Closed");
213         }
214         boolean on = true;
215         switch (opt) {
216             /* check type safety b4 going native.  These should never
217              * fail, since only java.Socket* has access to
218              * PlainSocketImpl.setOption().
219              */
220         case SO_LINGER:
221             if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
222                 throw new SocketException("Bad parameter for option");
223             if (val instanceof Boolean) {
224                 /* true only if disabling - enabling should be Integer */
225                 on = false;
226             }
227             break;
228         case SO_TIMEOUT:
229             if (val == null || (!(val instanceof Integer)))
230                 throw new SocketException("Bad parameter for SO_TIMEOUT");
231             int tmp = ((Integer) val).intValue();
232             if (tmp < 0)
233                 throw new IllegalArgumentException("timeout < 0");
234             timeout = tmp;
235             break;
236         case IP_TOS:
237              if (val == null || !(val instanceof Integer)) {
238                  throw new SocketException("bad argument for IP_TOS");
239              }
240              trafficClass = ((Integer)val).intValue();
241              break;
242         case SO_BINDADDR:
243             throw new SocketException("Cannot re-bind socket");
244         case TCP_NODELAY:
245             if (val == null || !(val instanceof Boolean))
246                 throw new SocketException("bad parameter for TCP_NODELAY");
247             on = ((Boolean)val).booleanValue();
248             break;
249         case SO_SNDBUF:
250         case SO_RCVBUF:
251             if (val == null || !(val instanceof Integer) ||
252                 !(((Integer)val).intValue() > 0)) {
253                 throw new SocketException("bad parameter for SO_SNDBUF " +
254                                           "or SO_RCVBUF");
255             }
256             break;
257         case SO_KEEPALIVE:
258             if (val == null || !(val instanceof Boolean))
259                 throw new SocketException("bad parameter for SO_KEEPALIVE");
260             on = ((Boolean)val).booleanValue();
261             break;
262         case SO_OOBINLINE:
263             if (val == null || !(val instanceof Boolean))
264                 throw new SocketException("bad parameter for SO_OOBINLINE");
265             on = ((Boolean)val).booleanValue();
266             break;
267         case SO_REUSEADDR:
268             if (val == null || !(val instanceof Boolean))
269                 throw new SocketException("bad parameter for SO_REUSEADDR");
270             on = ((Boolean)val).booleanValue();
271             break;
272         default:
273             throw new SocketException("unrecognized TCP option: " + opt);
274         }
275         socketSetOption(opt, on, val);
276     }
277     public Object getOption(int opt) throws SocketException {
278         if (isClosedOrPending()) {
279             throw new SocketException("Socket Closed");
280         }
281         if (opt == SO_TIMEOUT) {
282             return new Integer(timeout);
283         }
284         int ret = 0;
285         /*
286          * The native socketGetOption() knows about 3 options.
287          * The 32 bit value it returns will be interpreted according
288          * to what we're asking.  A return of -1 means it understands
289          * the option but its turned off.  It will raise a SocketException
290          * if "opt" isn't one it understands.
291          */
292 
293         switch (opt) {
294         case TCP_NODELAY:
295             ret = socketGetOption(opt, null);
296             return Boolean.valueOf(ret != -1);
297         case SO_OOBINLINE:
298             ret = socketGetOption(opt, null);
299             return Boolean.valueOf(ret != -1);
300         case SO_LINGER:
301             ret = socketGetOption(opt, null);
302             return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret));
303         case SO_REUSEADDR:
304             ret = socketGetOption(opt, null);
305             return Boolean.valueOf(ret != -1);
306         case SO_BINDADDR:
307             InetAddressContainer in = new InetAddressContainer();
308             ret = socketGetOption(opt, in);
309             return in.addr;
310         case SO_SNDBUF:
311         case SO_RCVBUF:
312             ret = socketGetOption(opt, null);
313             return new Integer(ret);
314         case IP_TOS:
315             ret = socketGetOption(opt, null);
316             if (ret == -1) { // ipv6 tos
317                 return new Integer(trafficClass);
318             } else {
319                 return new Integer(ret);
320             }
321         case SO_KEEPALIVE:
322             ret = socketGetOption(opt, null);
323             return Boolean.valueOf(ret != -1);
324         // should never get here
325         default:
326             return null;
327         }
328     }
329 
330     /**
331      * The workhorse of the connection operation.  Tries several times to
332      * establish a connection to the given <host, port>.  If unsuccessful,
333      * throws an IOException indicating what went wrong.
334      */
335 
336     synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
337         synchronized (fdLock) {
338             if (!closePending && (socket == null || !socket.isBound())) {
339                 NetHooks.beforeTcpConnect(fd, address, port);
340             }
341         }
342         try {
343             acquireFD();
344             try {
345                 socketConnect(address, port, timeout);
346                 /* socket may have been closed during poll/select */
347                 synchronized (fdLock) {
348                     if (closePending) {
349                         throw new SocketException ("Socket closed");
350                     }
351                 }
352                 // If we have a ref. to the Socket, then sets the flags
353                 // created, bound & connected to true.
354                 // This is normally done in Socket.connect() but some
355                 // subclasses of Socket may call impl.connect() directly!
356                 if (socket != null) {
357                     socket.setBound();
358                     socket.setConnected();
359                 }
360             } finally {
361                 releaseFD();
362             }
363         } catch (IOException e) {
364             close();
365             throw e;
366         }
367     }
368 
369     /**
370      * Binds the socket to the specified address of the specified local port.
371      * @param address the address
372      * @param lport the port
373      */
374     protected synchronized void bind(InetAddress address, int lport)
375         throws IOException
376     {
377        synchronized (fdLock) {
378             if (!closePending && (socket == null || !socket.isBound())) {
379                 NetHooks.beforeTcpBind(fd, address, lport);
380             }
381         }
382         socketBind(address, lport);
383         if (socket != null)
384             socket.setBound();
385         if (serverSocket != null)
386             serverSocket.setBound();
387     }
388 
389     /**
390      * Listens, for a specified amount of time, for connections.
391      * @param count the amount of time to listen for connections
392      */
393     protected synchronized void listen(int count) throws IOException {
394         socketListen(count);
395     }
396 
397     /**
398      * Accepts connections.
399      * @param s the connection
400      */
401     protected void accept(SocketImpl s) throws IOException {
402         acquireFD();
403         try {
404             socketAccept(s);
405         } finally {
406             releaseFD();
407         }
408     }
409 
410     /**
411      * Gets an InputStream for this socket.
412      */
413     protected synchronized InputStream getInputStream() throws IOException {
414         synchronized (fdLock) {
415             if (isClosedOrPending())
416                 throw new IOException("Socket Closed");
417             if (shut_rd)
418                 throw new IOException("Socket input is shutdown");
419             if (socketInputStream == null)
420                 socketInputStream = new SocketInputStream(this);
421         }
422         return socketInputStream;
423     }
424 
425     void setInputStream(SocketInputStream in) {
426         socketInputStream = in;
427     }
428 
429     /**
430      * Gets an OutputStream for this socket.
431      */
432     protected synchronized OutputStream getOutputStream() throws IOException {
433         synchronized (fdLock) {
434             if (isClosedOrPending())
435                 throw new IOException("Socket Closed");
436             if (shut_wr)
437                 throw new IOException("Socket output is shutdown");
438             if (socketOutputStream == null)
439                 socketOutputStream = new SocketOutputStream(this);
440         }
441         return socketOutputStream;
442     }
443 
444     void setFileDescriptor(FileDescriptor fd) {
445         this.fd = fd;
446     }
447 
448     void setAddress(InetAddress address) {
449         this.address = address;
450     }
451 
452     void setPort(int port) {
453         this.port = port;
454     }
455 
456     void setLocalPort(int localport) {
457         this.localport = localport;
458     }
459 
460     /**
461      * Returns the number of bytes that can be read without blocking.
462      */
463     protected synchronized int available() throws IOException {
464         if (isClosedOrPending()) {
465             throw new IOException("Stream closed.");
466         }
467 
468         /*
469          * If connection has been reset or shut down for input, then return 0
470          * to indicate there are no buffered bytes.
471          */
472         if (isConnectionReset() || shut_rd) {
473             return 0;
474         }
475 
476         /*
477          * If no bytes available and we were previously notified
478          * of a connection reset then we move to the reset state.
479          *
480          * If are notified of a connection reset then check
481          * again if there are bytes buffered on the socket.
482          */
483         int n = 0;
484         try {
485             n = socketAvailable();
486             if (n == 0 && isConnectionResetPending()) {
487                 setConnectionReset();
488             }
489         } catch (ConnectionResetException exc1) {
490             setConnectionResetPending();
491             try {
492                 n = socketAvailable();
493                 if (n == 0) {
494                     setConnectionReset();
495                 }
496             } catch (ConnectionResetException exc2) {
497             }
498         }
499         return n;
500     }
501 
502     /**
503      * Closes the socket.
504      */
505     protected void close() throws IOException {
506         synchronized(fdLock) {
507             if (fd != null) {
508                 if (!stream) {
509                     ResourceManager.afterUdpClose();
510                 }
511                 if (fdUseCount == 0) {
512                     if (closePending) {
513                         return;
514                     }
515                     closePending = true;
516                     /*
517                      * We close the FileDescriptor in two-steps - first the
518                      * "pre-close" which closes the socket but doesn't
519                      * release the underlying file descriptor. This operation
520                      * may be lengthy due to untransmitted data and a long
521                      * linger interval. Once the pre-close is done we do the
522                      * actual socket to release the fd.
523                      */
524                     try {
525                         socketPreClose();
526                     } finally {
527                         socketClose();
528                     }
529                     fd = null;
530                     return;
531                 } else {
532                     /*
533                      * If a thread has acquired the fd and a close
534                      * isn't pending then use a deferred close.
535                      * Also decrement fdUseCount to signal the last
536                      * thread that releases the fd to close it.
537                      */
538                     if (!closePending) {
539                         closePending = true;
540                         fdUseCount--;
541                         socketPreClose();
542                     }
543                 }
544             }
545         }
546     }
547 
548     void reset() throws IOException {
549         if (fd != null) {
550             socketClose();
551         }
552         fd = null;
553         super.reset();
554     }
555 
556 
557     /**
558      * Shutdown read-half of the socket connection;
559      */
560     protected void shutdownInput() throws IOException {
561       if (fd != null) {
562           socketShutdown(SHUT_RD);
563           if (socketInputStream != null) {
564               socketInputStream.setEOF(true);
565           }
566           shut_rd = true;
567       }
568     }
569 
570     /**
571      * Shutdown write-half of the socket connection;
572      */
573     protected void shutdownOutput() throws IOException {
574       if (fd != null) {
575           socketShutdown(SHUT_WR);
576           shut_wr = true;
577       }
578     }
579 
580     protected boolean supportsUrgentData () {
581         return true;
582     }
583 
584     protected void sendUrgentData (int data) throws IOException {
585         if (fd == null) {
586             throw new IOException("Socket Closed");
587         }
588         socketSendUrgentData (data);
589     }
590 
591     /**
592      * Cleans up if the user forgets to close it.
593      */
594     protected void finalize() throws IOException {
595         close();
596     }
597 
598     /*
599      * "Acquires" and returns the FileDescriptor for this impl
600      *
601      * A corresponding releaseFD is required to "release" the
602      * FileDescriptor.
603      */
604     FileDescriptor acquireFD() {
605         synchronized (fdLock) {
606             fdUseCount++;
607             return fd;
608         }
609     }
610 
611     /*
612      * "Release" the FileDescriptor for this impl.
613      *
614      * If the use count goes to -1 then the socket is closed.
615      */
616     void releaseFD() {
617         synchronized (fdLock) {
618             fdUseCount--;
619             if (fdUseCount == -1) {
620                 if (fd != null) {
621                     try {
622                         socketClose();
623                     } catch (IOException e) {
624                     } finally {
625                         fd = null;
626                     }
627                 }
628             }
629         }
630     }
631 
632     public boolean isConnectionReset() {
633         synchronized (resetLock) {
634             return (resetState == CONNECTION_RESET);
635         }
636     }
637 
638     public boolean isConnectionResetPending() {
639         synchronized (resetLock) {
640             return (resetState == CONNECTION_RESET_PENDING);
641         }
642     }
643 
644     public void setConnectionReset() {
645         synchronized (resetLock) {
646             resetState = CONNECTION_RESET;
647         }
648     }
649 
650     public void setConnectionResetPending() {
651         synchronized (resetLock) {
652             if (resetState == CONNECTION_NOT_RESET) {
653                 resetState = CONNECTION_RESET_PENDING;
654             }
655         }
656 
657     }
658 
659     /*
660      * Return true if already closed or close is pending
661      */
662     public boolean isClosedOrPending() {
663         /*
664          * Lock on fdLock to ensure that we wait if a
665          * close is in progress.
666          */
667         synchronized (fdLock) {
668             if (closePending || (fd == null)) {
669                 return true;
670             } else {
671                 return false;
672             }
673         }
674     }
675 
676     /*
677      * Return the current value of SO_TIMEOUT
678      */
679     public int getTimeout() {
680         return timeout;
681     }
682 
683     /*
684      * "Pre-close" a socket by dup'ing the file descriptor - this enables
685      * the socket to be closed without releasing the file descriptor.
686      */
687     private void socketPreClose() throws IOException {
688         socketClose0(true);
689     }
690 
691     /*
692      * Close the socket (and release the file descriptor).
693      */
694     protected void socketClose() throws IOException {
695         socketClose0(false);
696     }
697 
698     abstract void socketCreate(boolean isServer) throws IOException;
699     abstract void socketConnect(InetAddress address, int port, int timeout)
700         throws IOException;
701     abstract void socketBind(InetAddress address, int port)
702         throws IOException;
703     abstract void socketListen(int count)
704         throws IOException;
705     abstract void socketAccept(SocketImpl s)
706         throws IOException;
707     abstract int socketAvailable()
708         throws IOException;
709     abstract void socketClose0(boolean useDeferredClose)
710         throws IOException;
711     abstract void socketShutdown(int howto)
712         throws IOException;
713     abstract void socketSetOption(int cmd, boolean on, Object value)
714         throws SocketException;
715     abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
716     abstract void socketSendUrgentData(int data)
717         throws IOException;
718 
719     public final static int SHUT_RD = 0;
720     public final static int SHUT_WR = 1;
721 }