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