1 /*
2  * Copyright (c) 1995, 2018, 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.FileDescriptor;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.OutputStream;
32
33 import java.util.Collections;
34 import java.util.HashSet;
35 import java.util.Set;
36
37 import sun.net.ConnectionResetException;
38 import sun.net.NetHooks;
39 import sun.net.ResourceManager;
40 import sun.net.util.SocketExceptions;
41
42 /**
43  * Default Socket Implementation. This implementation does
44  * not implement any security checks.
45  * Note this class should <b>NOT</b> be public.
46  *
47  * @author  Steven B. Byrne
48  */

49 abstract class AbstractPlainSocketImpl extends SocketImpl {
50     /* instance variable for SO_TIMEOUT */
51     int timeout;   // timeout in millisec
52     // traffic class
53     private int trafficClass;
54
55     private boolean shut_rd = false;
56     private boolean shut_wr = false;
57
58     private SocketInputStream socketInputStream = null;
59     private SocketOutputStream socketOutputStream = null;
60
61     /* number of threads using the FileDescriptor */
62     protected int fdUseCount = 0;
63
64     /* lock when increment/decrementing fdUseCount */
65     protected final Object fdLock = new Object();
66
67     /* indicates a close is pending on the file descriptor */
68     protected boolean closePending = false;
69
70     /* indicates connection reset state */
71     private volatile boolean connectionReset;
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<>() {
83                 public Void run() {
84                     System.loadLibrary("net");
85                     return null;
86                 }
87             });
88     }
89
90     private static volatile boolean checkedReusePort;
91     private static volatile boolean isReusePortAvailable;
92
93     /**
94      * Tells whether SO_REUSEPORT is supported.
95      */

96     static boolean isReusePortAvailable() {
97         if (!checkedReusePort) {
98             isReusePortAvailable = isReusePortAvailable0();
99             checkedReusePort = true;
100         }
101         return isReusePortAvailable;
102     }
103
104     /**
105      * Returns a set of SocketOptions supported by this impl and by this impl's
106      * socket (Socket or ServerSocket)
107      *
108      * @return a Set of SocketOptions
109      */

110     @Override
111     protected Set<SocketOption<?>> supportedOptions() {
112         Set<SocketOption<?>> options;
113         if (isReusePortAvailable()) {
114             options = new HashSet<>();
115             options.addAll(super.supportedOptions());
116             options.add(StandardSocketOptions.SO_REUSEPORT);
117             options = Collections.unmodifiableSet(options);
118         } else {
119             options = super.supportedOptions();
120         }
121         return options;
122     }
123
124     /**
125      * Creates a socket with a boolean that specifies whether this
126      * is a stream socket (true) or an unconnected UDP socket (false).
127      */

128     protected synchronized void create(boolean stream) throws IOException {
129         this.stream = stream;
130         if (!stream) {
131             ResourceManager.beforeUdpCreate();
132             // only create the fd after we know we will be able to create the socket
133             fd = new FileDescriptor();
134             try {
135                 socketCreate(false);
136                 SocketCleanable.register(fd);
137             } catch (IOException ioe) {
138                 ResourceManager.afterUdpClose();
139                 fd = null;
140                 throw ioe;
141             }
142         } else {
143             fd = new FileDescriptor();
144             socketCreate(true);
145             SocketCleanable.register(fd);
146         }
147         if (socket != null)
148             socket.setCreated();
149         if (serverSocket != null)
150             serverSocket.setCreated();
151     }
152
153     /**
154      * Creates a socket and connects it to the specified port on
155      * the specified host.
156      * @param host the specified host
157      * @param port the specified port
158      */

159     protected void connect(String host, int port)
160         throws UnknownHostException, IOException
161     {
162         boolean connected = false;
163         try {
164             InetAddress address = InetAddress.getByName(host);
165             this.port = port;
166             this.address = address;
167
168             connectToAddress(address, port, timeout);
169             connected = true;
170         } finally {
171             if (!connected) {
172                 try {
173                     close();
174                 } catch (IOException ioe) {
175                     /* Do nothing. If connect threw an exception then
176                        it will be passed up the call stack */

177                 }
178             }
179         }
180     }
181
182     /**
183      * Creates a socket and connects it to the specified address on
184      * the specified port.
185      * @param address the address
186      * @param port the specified port
187      */

188     protected void connect(InetAddress address, int port) throws IOException {
189         this.port = port;
190         this.address = address;
191
192         try {
193             connectToAddress(address, port, timeout);
194             return;
195         } catch (IOException e) {
196             // everything failed
197             close();
198             throw e;
199         }
200     }
201
202     /**
203      * Creates a socket and connects it to the specified address on
204      * the specified port.
205      * @param address the address
206      * @param timeout the timeout value in milliseconds, or zero for no timeout.
207      * @throws IOException if connection fails
208      * @throws  IllegalArgumentException if address is null or is a
209      *          SocketAddress subclass not supported by this socket
210      * @since 1.4
211      */

212     protected void connect(SocketAddress address, int timeout)
213             throws IOException {
214         boolean connected = false;
215         try {
216             if (address == null || !(address instanceof InetSocketAddress))
217                 throw new IllegalArgumentException("unsupported address type");
218             InetSocketAddress addr = (InetSocketAddress) address;
219             if (addr.isUnresolved())
220                 throw new UnknownHostException(addr.getHostName());
221             this.port = addr.getPort();
222             this.address = addr.getAddress();
223
224             connectToAddress(this.address, port, timeout);
225             connected = true;
226         } finally {
227             if (!connected) {
228                 try {
229                     close();
230                 } catch (IOException ioe) {
231                     /* Do nothing. If connect threw an exception then
232                        it will be passed up the call stack */

233                 }
234             }
235         }
236     }
237
238     private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {
239         if (address.isAnyLocalAddress()) {
240             doConnect(InetAddress.getLocalHost(), port, timeout);
241         } else {
242             doConnect(address, port, timeout);
243         }
244     }
245
246     public void setOption(int opt, Object val) throws SocketException {
247         if (isClosedOrPending()) {
248             throw new SocketException("Socket Closed");
249         }
250         boolean on = true;
251         switch (opt) {
252             /* check type safety b4 going native.  These should never
253              * fail, since only java.Socket* has access to
254              * PlainSocketImpl.setOption().
255              */

256         case SO_LINGER:
257             if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
258                 throw new SocketException("Bad parameter for option");
259             if (val instanceof Boolean) {
260                 /* true only if disabling - enabling should be Integer */
261                 on = false;
262             }
263             break;
264         case SO_TIMEOUT:
265             if (val == null || (!(val instanceof Integer)))
266                 throw new SocketException("Bad parameter for SO_TIMEOUT");
267             int tmp = ((Integer) val).intValue();
268             if (tmp < 0)
269                 throw new IllegalArgumentException("timeout < 0");
270             timeout = tmp;
271             break;
272         case IP_TOS:
273              if (val == null || !(val instanceof Integer)) {
274                  throw new SocketException("bad argument for IP_TOS");
275              }
276              trafficClass = ((Integer)val).intValue();
277              break;
278         case SO_BINDADDR:
279             throw new SocketException("Cannot re-bind socket");
280         case TCP_NODELAY:
281             if (val == null || !(val instanceof Boolean))
282                 throw new SocketException("bad parameter for TCP_NODELAY");
283             on = ((Boolean)val).booleanValue();
284             break;
285         case SO_SNDBUF:
286         case SO_RCVBUF:
287             if (val == null || !(val instanceof Integer) ||
288                 !(((Integer)val).intValue() > 0)) {
289                 throw new SocketException("bad parameter for SO_SNDBUF " +
290                                           "or SO_RCVBUF");
291             }
292             break;
293         case SO_KEEPALIVE:
294             if (val == null || !(val instanceof Boolean))
295                 throw new SocketException("bad parameter for SO_KEEPALIVE");
296             on = ((Boolean)val).booleanValue();
297             break;
298         case SO_OOBINLINE:
299             if (val == null || !(val instanceof Boolean))
300                 throw new SocketException("bad parameter for SO_OOBINLINE");
301             on = ((Boolean)val).booleanValue();
302             break;
303         case SO_REUSEADDR:
304             if (val == null || !(val instanceof Boolean))
305                 throw new SocketException("bad parameter for SO_REUSEADDR");
306             on = ((Boolean)val).booleanValue();
307             break;
308         case SO_REUSEPORT:
309             if (val == null || !(val instanceof Boolean))
310                 throw new SocketException("bad parameter for SO_REUSEPORT");
311             if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT))
312                 throw new UnsupportedOperationException("unsupported option");
313             on = ((Boolean)val).booleanValue();
314             break;
315         default:
316             throw new SocketException("unrecognized TCP option: " + opt);
317         }
318         socketSetOption(opt, on, val);
319     }
320     public Object getOption(int opt) throws SocketException {
321         if (isClosedOrPending()) {
322             throw new SocketException("Socket Closed");
323         }
324         if (opt == SO_TIMEOUT) {
325             return timeout;
326         }
327         int ret = 0;
328         /*
329          * The native socketGetOption() knows about 3 options.
330          * The 32 bit value it returns will be interpreted according
331          * to what we're asking.  A return of -1 means it understands
332          * the option but its turned off.  It will raise a SocketException
333          * if "opt" isn't one it understands.
334          */

335
336         switch (opt) {
337         case TCP_NODELAY:
338             ret = socketGetOption(opt, null);
339             return Boolean.valueOf(ret != -1);
340         case SO_OOBINLINE:
341             ret = socketGetOption(opt, null);
342             return Boolean.valueOf(ret != -1);
343         case SO_LINGER:
344             ret = socketGetOption(opt, null);
345             return (ret == -1) ? Boolean.FALSE: (Object)(ret);
346         case SO_REUSEADDR:
347             ret = socketGetOption(opt, null);
348             return Boolean.valueOf(ret != -1);
349         case SO_BINDADDR:
350             InetAddressContainer in = new InetAddressContainer();
351             ret = socketGetOption(opt, in);
352             return in.addr;
353         case SO_SNDBUF:
354         case SO_RCVBUF:
355             ret = socketGetOption(opt, null);
356             return ret;
357         case IP_TOS:
358             try {
359                 ret = socketGetOption(opt, null);
360                 if (ret == -1) { // ipv6 tos
361                     return trafficClass;
362                 } else {
363                     return ret;
364                 }
365             } catch (SocketException se) {
366                     // TODO - should make better effort to read TOS or TCLASS
367                     return trafficClass; // ipv6 tos
368             }
369         case SO_KEEPALIVE:
370             ret = socketGetOption(opt, null);
371             return Boolean.valueOf(ret != -1);
372         case SO_REUSEPORT:
373             if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
374                 throw new UnsupportedOperationException("unsupported option");
375             }
376             ret = socketGetOption(opt, null);
377             return Boolean.valueOf(ret != -1);
378         // should never get here
379         default:
380             return null;
381         }
382     }
383
384     /**
385      * The workhorse of the connection operation.  Tries several times to
386      * establish a connection to the given <host, port>.  If unsuccessful,
387      * throws an IOException indicating what went wrong.
388      */

389
390     synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
391         synchronized (fdLock) {
392             if (!closePending && (socket == null || !socket.isBound())) {
393                 NetHooks.beforeTcpConnect(fd, address, port);
394             }
395         }
396         try {
397             acquireFD();
398             try {
399                 socketConnect(address, port, timeout);
400                 /* socket may have been closed during poll/select */
401                 synchronized (fdLock) {
402                     if (closePending) {
403                         throw new SocketException ("Socket closed");
404                     }
405                 }
406                 // If we have a ref. to the Socket, then sets the flags
407                 // created, bound & connected to true.
408                 // This is normally done in Socket.connect() but some
409                 // subclasses of Socket may call impl.connect() directly!
410                 if (socket != null) {
411                     socket.setBound();
412                     socket.setConnected();
413                 }
414             } finally {
415                 releaseFD();
416             }
417         } catch (IOException e) {
418             close();
419             throw SocketExceptions.of(e, new InetSocketAddress(address, port));
420         }
421     }
422
423     /**
424      * Binds the socket to the specified address of the specified local port.
425      * @param address the address
426      * @param lport the port
427      */

428     protected synchronized void bind(InetAddress address, int lport)
429         throws IOException
430     {
431        synchronized (fdLock) {
432             if (!closePending && (socket == null || !socket.isBound())) {
433                 NetHooks.beforeTcpBind(fd, address, lport);
434             }
435         }
436         socketBind(address, lport);
437         if (socket != null)
438             socket.setBound();
439         if (serverSocket != null)
440             serverSocket.setBound();
441     }
442
443     /**
444      * Listens, for a specified amount of time, for connections.
445      * @param count the amount of time to listen for connections
446      */

447     protected synchronized void listen(int count) throws IOException {
448         socketListen(count);
449     }
450
451     /**
452      * Accepts connections.
453      * @param s the connection
454      */

455     protected void accept(SocketImpl s) throws IOException {
456         acquireFD();
457         try {
458             socketAccept(s);
459         } finally {
460             releaseFD();
461         }
462     }
463
464     /**
465      * Gets an InputStream for this socket.
466      */

467     protected synchronized InputStream getInputStream() throws IOException {
468         synchronized (fdLock) {
469             if (isClosedOrPending())
470                 throw new IOException("Socket Closed");
471             if (shut_rd)
472                 throw new IOException("Socket input is shutdown");
473             if (socketInputStream == null)
474                 socketInputStream = new SocketInputStream(this);
475         }
476         return socketInputStream;
477     }
478
479     void setInputStream(SocketInputStream in) {
480         socketInputStream = in;
481     }
482
483     /**
484      * Gets an OutputStream for this socket.
485      */

486     protected synchronized OutputStream getOutputStream() throws IOException {
487         synchronized (fdLock) {
488             if (isClosedOrPending())
489                 throw new IOException("Socket Closed");
490             if (shut_wr)
491                 throw new IOException("Socket output is shutdown");
492             if (socketOutputStream == null)
493                 socketOutputStream = new SocketOutputStream(this);
494         }
495         return socketOutputStream;
496     }
497
498     void setFileDescriptor(FileDescriptor fd) {
499         this.fd = fd;
500     }
501
502     void setAddress(InetAddress address) {
503         this.address = address;
504     }
505
506     void setPort(int port) {
507         this.port = port;
508     }
509
510     void setLocalPort(int localport) {
511         this.localport = localport;
512     }
513
514     /**
515      * Returns the number of bytes that can be read without blocking.
516      */

517     protected synchronized int available() throws IOException {
518         if (isClosedOrPending()) {
519             throw new IOException("Stream closed.");
520         }
521
522         /*
523          * If connection has been reset or shut down for input, then return 0
524          * to indicate there are no buffered bytes.
525          */

526         if (isConnectionReset() || shut_rd) {
527             return 0;
528         }
529
530         /*
531          * If no bytes available and we were previously notified
532          * of a connection reset then we move to the reset state.
533          *
534          * If are notified of a connection reset then check
535          * again if there are bytes buffered on the socket.
536          */

537         int n = 0;
538         try {
539             n = socketAvailable();
540         } catch (ConnectionResetException exc1) {
541             setConnectionReset();
542         }
543         return n;
544     }
545
546     /**
547      * Closes the socket.
548      */

549     protected void close() throws IOException {
550         synchronized(fdLock) {
551             if (fd != null) {
552                 if (!stream) {
553                     ResourceManager.afterUdpClose();
554                 }
555                 if (fdUseCount == 0) {
556                     if (closePending) {
557                         return;
558                     }
559                     closePending = true;
560                     /*
561                      * We close the FileDescriptor in two-steps - first the
562                      * "pre-close" which closes the socket but doesn't
563                      * release the underlying file descriptor. This operation
564                      * may be lengthy due to untransmitted data and a long
565                      * linger interval. Once the pre-close is done we do the
566                      * actual socket to release the fd.
567                      */

568                     try {
569                         socketPreClose();
570                     } finally {
571                         socketClose();
572                     }
573                     fd = null;
574                     return;
575                 } else {
576                     /*
577                      * If a thread has acquired the fd and a close
578                      * isn't pending then use a deferred close.
579                      * Also decrement fdUseCount to signal the last
580                      * thread that releases the fd to close it.
581                      */

582                     if (!closePending) {
583                         closePending = true;
584                         fdUseCount--;
585                         socketPreClose();
586                     }
587                 }
588             }
589         }
590     }
591
592     void reset() throws IOException {
593         if (fd != null) {
594             socketClose();
595         }
596         fd = null;
597         super.reset();
598     }
599
600
601     /**
602      * Shutdown read-half of the socket connection;
603      */

604     protected void shutdownInput() throws IOException {
605       if (fd != null) {
606           socketShutdown(SHUT_RD);
607           if (socketInputStream != null) {
608               socketInputStream.setEOF(true);
609           }
610           shut_rd = true;
611       }
612     }
613
614     /**
615      * Shutdown write-half of the socket connection;
616      */

617     protected void shutdownOutput() throws IOException {
618       if (fd != null) {
619           socketShutdown(SHUT_WR);
620           shut_wr = true;
621       }
622     }
623
624     protected boolean supportsUrgentData () {
625         return true;
626     }
627
628     protected void sendUrgentData (int data) throws IOException {
629         if (fd == null) {
630             throw new IOException("Socket Closed");
631         }
632         socketSendUrgentData (data);
633     }
634
635     /*
636      * "Acquires" and returns the FileDescriptor for this impl
637      *
638      * A corresponding releaseFD is required to "release" the
639      * FileDescriptor.
640      */

641     FileDescriptor acquireFD() {
642         synchronized (fdLock) {
643             fdUseCount++;
644             return fd;
645         }
646     }
647
648     /*
649      * "Release" the FileDescriptor for this impl.
650      *
651      * If the use count goes to -1 then the socket is closed.
652      */

653     void releaseFD() {
654         synchronized (fdLock) {
655             fdUseCount--;
656             if (fdUseCount == -1) {
657                 if (fd != null) {
658                     try {
659                         socketClose();
660                     } catch (IOException e) {
661                     } finally {
662                         fd = null;
663                     }
664                 }
665             }
666         }
667     }
668
669     boolean isConnectionReset() {
670         return connectionReset;
671     }
672
673     void setConnectionReset() {
674         connectionReset = true;
675     }
676
677     /*
678      * Return true if already closed or close is pending
679      */

680     public boolean isClosedOrPending() {
681         /*
682          * Lock on fdLock to ensure that we wait if a
683          * close is in progress.
684          */

685         synchronized (fdLock) {
686             if (closePending || (fd == null)) {
687                 return true;
688             } else {
689                 return false;
690             }
691         }
692     }
693
694     /*
695      * Return the current value of SO_TIMEOUT
696      */

697     public int getTimeout() {
698         return timeout;
699     }
700
701     /*
702      * "Pre-close" a socket by dup'ing the file descriptor - this enables
703      * the socket to be closed without releasing the file descriptor.
704      */

705     private void socketPreClose() throws IOException {
706         socketClose0(true);
707     }
708
709     /*
710      * Close the socket (and release the file descriptor).
711      */

712     protected void socketClose() throws IOException {
713         SocketCleanable.unregister(fd);
714         socketClose0(false);
715     }
716
717     abstract void socketCreate(boolean isServer) throws IOException;
718     abstract void socketConnect(InetAddress address, int port, int timeout)
719         throws IOException;
720     abstract void socketBind(InetAddress address, int port)
721         throws IOException;
722     abstract void socketListen(int count)
723         throws IOException;
724     abstract void socketAccept(SocketImpl s)
725         throws IOException;
726     abstract int socketAvailable()
727         throws IOException;
728     abstract void socketClose0(boolean useDeferredClose)
729         throws IOException;
730     abstract void socketShutdown(int howto)
731         throws IOException;
732     abstract void socketSetOption(int cmd, boolean on, Object value)
733         throws SocketException;
734     abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
735     abstract void socketSendUrgentData(int data)
736         throws IOException;
737
738     public static final int SHUT_RD = 0;
739     public static final int SHUT_WR = 1;
740
741     private static native boolean isReusePortAvailable0();
742 }
743