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