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