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