1
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
49 abstract class AbstractPlainSocketImpl extends SocketImpl {
50
51 int timeout;
52
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
62 protected int fdUseCount = 0;
63
64
65 protected final Object fdLock = new Object();
66
67
68 protected boolean closePending = false;
69
70
71 private volatile boolean connectionReset;
72
73
75 protected boolean stream;
76
77
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
96 static boolean isReusePortAvailable() {
97 if (!checkedReusePort) {
98 isReusePortAvailable = isReusePortAvailable0();
99 checkedReusePort = true;
100 }
101 return isReusePortAvailable;
102 }
103
104
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
128 protected synchronized void create(boolean stream) throws IOException {
129 this.stream = stream;
130 if (!stream) {
131 ResourceManager.beforeUdpCreate();
132
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
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
177 }
178 }
179 }
180 }
181
182
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
197 close();
198 throw e;
199 }
200 }
201
202
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
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
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
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
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) {
361 return trafficClass;
362 } else {
363 return ret;
364 }
365 } catch (SocketException se) {
366
367 return trafficClass;
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
379 default:
380 return null;
381 }
382 }
383
384
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
401 synchronized (fdLock) {
402 if (closePending) {
403 throw new SocketException ("Socket closed");
404 }
405 }
406
407
408
409
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
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
447 protected synchronized void listen(int count) throws IOException {
448 socketListen(count);
449 }
450
451
455 protected void accept(SocketImpl s) throws IOException {
456 acquireFD();
457 try {
458 socketAccept(s);
459 } finally {
460 releaseFD();
461 }
462 }
463
464
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
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
517 protected synchronized int available() throws IOException {
518 if (isClosedOrPending()) {
519 throw new IOException("Stream closed.");
520 }
521
522
526 if (isConnectionReset() || shut_rd) {
527 return 0;
528 }
529
530
537 int n = 0;
538 try {
539 n = socketAvailable();
540 } catch (ConnectionResetException exc1) {
541 setConnectionReset();
542 }
543 return n;
544 }
545
546
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
568 try {
569 socketPreClose();
570 } finally {
571 socketClose();
572 }
573 fd = null;
574 return;
575 } else {
576
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
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
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
641 FileDescriptor acquireFD() {
642 synchronized (fdLock) {
643 fdUseCount++;
644 return fd;
645 }
646 }
647
648
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
680 public boolean isClosedOrPending() {
681
685 synchronized (fdLock) {
686 if (closePending || (fd == null)) {
687 return true;
688 } else {
689 return false;
690 }
691 }
692 }
693
694
697 public int getTimeout() {
698 return timeout;
699 }
700
701
705 private void socketPreClose() throws IOException {
706 socketClose0(true);
707 }
708
709
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