54 /* instance variable for SO_TIMEOUT */
55 int timeout; // timeout in millisec
56 // traffic class
57 private int trafficClass;
58
59 private boolean shut_rd = false;
60 private boolean shut_wr = false;
61
62 private SocketInputStream socketInputStream = null;
63 private SocketOutputStream socketOutputStream = null;
64
65 /* number of threads using the FileDescriptor */
66 protected int fdUseCount = 0;
67
68 /* lock when increment/decrementing fdUseCount */
69 protected final Object fdLock = new Object();
70
71 /* indicates a close is pending on the file descriptor */
72 protected boolean closePending = false;
73
74 /* indicates connection reset state */
75 private volatile boolean connectionReset;
76
77 /* whether this Socket is a stream (TCP) socket or not (UDP)
78 */
79 protected boolean stream;
80
81 /**
82 * Load net library into runtime.
83 */
84 static {
85 java.security.AccessController.doPrivileged(
86 new java.security.PrivilegedAction<>() {
87 public Void run() {
88 System.loadLibrary("net");
89 return null;
90 }
91 });
92 }
93
94 private static volatile boolean checkedReusePort;
95 private static volatile boolean isReusePortAvailable;
96
97 /**
98 * Tells whether SO_REUSEPORT is supported.
99 */
100 static boolean isReusePortAvailable() {
101 if (!checkedReusePort) {
102 isReusePortAvailable = isReusePortAvailable0();
103 checkedReusePort = true;
104 }
105 return isReusePortAvailable;
106 }
107
108 /**
109 * Returns a set of SocketOptions supported by this impl and by this impl's
110 * socket (Socket or ServerSocket)
111 *
112 * @return a Set of SocketOptions
113 */
114 @Override
115 protected Set<SocketOption<?>> supportedOptions() {
116 Set<SocketOption<?>> options;
117 if (isReusePortAvailable()) {
118 options = new HashSet<>();
119 options.addAll(super.supportedOptions());
120 options.add(StandardSocketOptions.SO_REUSEPORT);
121 options = Collections.unmodifiableSet(options);
122 } else {
123 options = super.supportedOptions();
124 }
125 return options;
126 }
127
128 /**
129 * Creates a socket with a boolean that specifies whether this
130 * is a stream socket (true) or an unconnected UDP socket (false).
131 */
132 protected synchronized void create(boolean stream) throws IOException {
133 this.stream = stream;
134 if (!stream) {
135 ResourceManager.beforeUdpCreate();
136 // only create the fd after we know we will be able to create the socket
137 fd = new FileDescriptor();
138 try {
139 socketCreate(false);
140 SocketCleanable.register(fd);
141 } catch (IOException ioe) {
142 ResourceManager.afterUdpClose();
143 fd = null;
144 throw ioe;
145 }
146 } else {
147 fd = new FileDescriptor();
148 socketCreate(true);
149 SocketCleanable.register(fd);
150 }
151 if (socket != null)
152 socket.setCreated();
153 if (serverSocket != null)
154 serverSocket.setCreated();
155 }
156
157 /**
158 * Creates a socket and connects it to the specified port on
159 * the specified host.
160 * @param host the specified host
161 * @param port the specified port
162 */
163 protected void connect(String host, int port)
164 throws UnknownHostException, IOException
165 {
166 boolean connected = false;
167 try {
168 InetAddress address = InetAddress.getByName(host);
169 this.port = port;
170 this.address = address;
171
172 connectToAddress(address, port, timeout);
173 connected = true;
174 } finally {
228 connectToAddress(this.address, port, timeout);
229 connected = true;
230 } finally {
231 if (!connected) {
232 try {
233 close();
234 } catch (IOException ioe) {
235 /* Do nothing. If connect threw an exception then
236 it will be passed up the call stack */
237 }
238 }
239 }
240 }
241
242 private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {
243 if (address.isAnyLocalAddress()) {
244 doConnect(InetAddress.getLocalHost(), port, timeout);
245 } else {
246 doConnect(address, port, timeout);
247 }
248 }
249
250 public void setOption(int opt, Object val) throws SocketException {
251 if (isClosedOrPending()) {
252 throw new SocketException("Socket Closed");
253 }
254 boolean on = true;
255 switch (opt) {
256 /* check type safety b4 going native. These should never
257 * fail, since only java.Socket* has access to
258 * PlainSocketImpl.setOption().
259 */
260 case SO_LINGER:
261 if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
262 throw new SocketException("Bad parameter for option");
263 if (val instanceof Boolean) {
264 /* true only if disabling - enabling should be Integer */
265 on = false;
266 }
267 break;
344 case SO_OOBINLINE:
345 ret = socketGetOption(opt, null);
346 return Boolean.valueOf(ret != -1);
347 case SO_LINGER:
348 ret = socketGetOption(opt, null);
349 return (ret == -1) ? Boolean.FALSE: (Object)(ret);
350 case SO_REUSEADDR:
351 ret = socketGetOption(opt, null);
352 return Boolean.valueOf(ret != -1);
353 case SO_BINDADDR:
354 InetAddressContainer in = new InetAddressContainer();
355 ret = socketGetOption(opt, in);
356 return in.addr;
357 case SO_SNDBUF:
358 case SO_RCVBUF:
359 ret = socketGetOption(opt, null);
360 return ret;
361 case IP_TOS:
362 try {
363 ret = socketGetOption(opt, null);
364 if (ret == -1) { // ipv6 tos
365 return trafficClass;
366 } else {
367 return ret;
368 }
369 } catch (SocketException se) {
370 // TODO - should make better effort to read TOS or TCLASS
371 return trafficClass; // ipv6 tos
372 }
373 case SO_KEEPALIVE:
374 ret = socketGetOption(opt, null);
375 return Boolean.valueOf(ret != -1);
376 case SO_REUSEPORT:
377 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
378 throw new UnsupportedOperationException("unsupported option");
379 }
380 ret = socketGetOption(opt, null);
381 return Boolean.valueOf(ret != -1);
382 // should never get here
383 default:
384 return null;
385 }
386 }
387
388 /**
389 * The workhorse of the connection operation. Tries several times to
390 * establish a connection to the given <host, port>. If unsuccessful,
391 * throws an IOException indicating what went wrong.
392 */
393
394 synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
395 synchronized (fdLock) {
396 if (!closePending && (socket == null || !socket.isBound())) {
397 NetHooks.beforeTcpConnect(fd, address, port);
398 }
399 }
400 try {
401 acquireFD();
402 try {
403 socketConnect(address, port, timeout);
404 /* socket may have been closed during poll/select */
405 synchronized (fdLock) {
406 if (closePending) {
407 throw new SocketException ("Socket closed");
408 }
409 }
410 // If we have a ref. to the Socket, then sets the flags
411 // created, bound & connected to true.
412 // This is normally done in Socket.connect() but some
413 // subclasses of Socket may call impl.connect() directly!
414 if (socket != null) {
415 socket.setBound();
416 socket.setConnected();
417 }
418 } finally {
419 releaseFD();
420 }
421 } catch (IOException e) {
422 close();
423 throw SocketExceptions.of(e, new InetSocketAddress(address, port));
424 }
425 }
426
427 /**
428 * Binds the socket to the specified address of the specified local port.
429 * @param address the address
430 * @param lport the port
431 */
432 protected synchronized void bind(InetAddress address, int lport)
433 throws IOException
434 {
435 synchronized (fdLock) {
436 if (!closePending && (socket == null || !socket.isBound())) {
437 NetHooks.beforeTcpBind(fd, address, lport);
438 }
439 }
440 socketBind(address, lport);
441 if (socket != null)
442 socket.setBound();
443 if (serverSocket != null)
444 serverSocket.setBound();
445 }
446
447 /**
448 * Listens, for a specified amount of time, for connections.
449 * @param count the amount of time to listen for connections
450 */
451 protected synchronized void listen(int count) throws IOException {
452 socketListen(count);
453 }
454
455 /**
456 * Accepts connections.
457 * @param si the socket impl
458 */
459 protected void accept(SocketImpl si) throws IOException {
460 si.fd = new FileDescriptor();
461 acquireFD();
462 try {
463 socketAccept(si);
464 } finally {
465 releaseFD();
466 }
467 SocketCleanable.register(si.fd);
468 }
469
470 /**
471 * Gets an InputStream for this socket.
472 */
473 protected synchronized InputStream getInputStream() throws IOException {
474 synchronized (fdLock) {
475 if (isClosedOrPending())
476 throw new IOException("Socket Closed");
477 if (shut_rd)
478 throw new IOException("Socket input is shutdown");
479 if (socketInputStream == null) {
480 PrivilegedExceptionAction<SocketInputStream> pa = () -> new SocketInputStream(this);
481 try {
482 socketInputStream = AccessController.doPrivileged(pa);
483 } catch (PrivilegedActionException e) {
710 public int getTimeout() {
711 return timeout;
712 }
713
714 /*
715 * "Pre-close" a socket by dup'ing the file descriptor - this enables
716 * the socket to be closed without releasing the file descriptor.
717 */
718 private void socketPreClose() throws IOException {
719 socketClose0(true);
720 }
721
722 /*
723 * Close the socket (and release the file descriptor).
724 */
725 protected void socketClose() throws IOException {
726 SocketCleanable.unregister(fd);
727 socketClose0(false);
728 }
729
730 abstract void socketCreate(boolean isServer) throws IOException;
731 abstract void socketConnect(InetAddress address, int port, int timeout)
732 throws IOException;
733 abstract void socketBind(InetAddress address, int port)
734 throws IOException;
735 abstract void socketListen(int count)
736 throws IOException;
737 abstract void socketAccept(SocketImpl s)
738 throws IOException;
739 abstract int socketAvailable()
740 throws IOException;
741 abstract void socketClose0(boolean useDeferredClose)
742 throws IOException;
743 abstract void socketShutdown(int howto)
744 throws IOException;
745 abstract void socketSetOption(int cmd, boolean on, Object value)
746 throws SocketException;
747 abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
748 abstract void socketSendUrgentData(int data)
749 throws IOException;
750
|
54 /* instance variable for SO_TIMEOUT */
55 int timeout; // timeout in millisec
56 // traffic class
57 private int trafficClass;
58
59 private boolean shut_rd = false;
60 private boolean shut_wr = false;
61
62 private SocketInputStream socketInputStream = null;
63 private SocketOutputStream socketOutputStream = null;
64
65 /* number of threads using the FileDescriptor */
66 protected int fdUseCount = 0;
67
68 /* lock when increment/decrementing fdUseCount */
69 protected final Object fdLock = new Object();
70
71 /* indicates a close is pending on the file descriptor */
72 protected boolean closePending = false;
73
74 /* true, if and only if, the socket is bound */
75 volatile boolean bound;
76
77 /* true, if and only if, the socket is connected */
78 volatile boolean connected;
79
80 /* indicates connection reset state */
81 private volatile boolean connectionReset;
82
83 /* whether this Socket is a stream (TCP) socket or not (UDP)
84 */
85 protected boolean stream;
86
87 /**
88 * Load net library into runtime.
89 */
90 static {
91 java.security.AccessController.doPrivileged(
92 new java.security.PrivilegedAction<>() {
93 public Void run() {
94 System.loadLibrary("net");
95 return null;
96 }
97 });
98 }
99
100 private static volatile boolean checkedReusePort;
101 private static volatile boolean isReusePortAvailable;
102
103 /**
104 * Tells whether SO_REUSEPORT is supported.
105 */
106 static boolean isReusePortAvailable() {
107 if (!checkedReusePort) {
108 isReusePortAvailable = isReusePortAvailable0();
109 checkedReusePort = true;
110 }
111 return isReusePortAvailable;
112 }
113
114 AbstractPlainSocketImpl(boolean server) {
115 super(server);
116 }
117
118 /**
119 * Returns a set of SocketOptions supported by this impl and by this impl's
120 * socket (Socket or ServerSocket)
121 *
122 * @return a Set of SocketOptions
123 */
124 @Override
125 protected Set<SocketOption<?>> supportedOptions() {
126 Set<SocketOption<?>> options;
127 if (isReusePortAvailable()) {
128 options = new HashSet<>();
129 options.addAll(super.supportedOptions());
130 options.add(StandardSocketOptions.SO_REUSEPORT);
131 options = Collections.unmodifiableSet(options);
132 } else {
133 options = super.supportedOptions();
134 }
135 return options;
136 }
137
138 /**
139 * Creates a socket with a boolean that specifies whether this
140 * is a stream socket (true) or an unconnected UDP socket (false).
141 */
142 protected synchronized void create(boolean stream) throws IOException {
143 this.stream = stream;
144 if (!stream) {
145 ResourceManager.beforeUdpCreate();
146 // only create the fd after we know we will be able to create the socket
147 fd = new FileDescriptor();
148 try {
149 socketCreate(false, server);
150 SocketCleanable.register(fd);
151 } catch (IOException ioe) {
152 ResourceManager.afterUdpClose();
153 fd = null;
154 throw ioe;
155 }
156 } else {
157 fd = new FileDescriptor();
158 socketCreate(true, server);
159 SocketCleanable.register(fd);
160 }
161 }
162
163 /**
164 * Creates a socket and connects it to the specified port on
165 * the specified host.
166 * @param host the specified host
167 * @param port the specified port
168 */
169 protected void connect(String host, int port)
170 throws UnknownHostException, IOException
171 {
172 boolean connected = false;
173 try {
174 InetAddress address = InetAddress.getByName(host);
175 this.port = port;
176 this.address = address;
177
178 connectToAddress(address, port, timeout);
179 connected = true;
180 } finally {
234 connectToAddress(this.address, port, timeout);
235 connected = true;
236 } finally {
237 if (!connected) {
238 try {
239 close();
240 } catch (IOException ioe) {
241 /* Do nothing. If connect threw an exception then
242 it will be passed up the call stack */
243 }
244 }
245 }
246 }
247
248 private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {
249 if (address.isAnyLocalAddress()) {
250 doConnect(InetAddress.getLocalHost(), port, timeout);
251 } else {
252 doConnect(address, port, timeout);
253 }
254 connected = true;
255 bound = true; // implicitly bound
256 }
257
258 public void setOption(int opt, Object val) throws SocketException {
259 if (isClosedOrPending()) {
260 throw new SocketException("Socket Closed");
261 }
262 boolean on = true;
263 switch (opt) {
264 /* check type safety b4 going native. These should never
265 * fail, since only java.Socket* has access to
266 * PlainSocketImpl.setOption().
267 */
268 case SO_LINGER:
269 if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
270 throw new SocketException("Bad parameter for option");
271 if (val instanceof Boolean) {
272 /* true only if disabling - enabling should be Integer */
273 on = false;
274 }
275 break;
352 case SO_OOBINLINE:
353 ret = socketGetOption(opt, null);
354 return Boolean.valueOf(ret != -1);
355 case SO_LINGER:
356 ret = socketGetOption(opt, null);
357 return (ret == -1) ? Boolean.FALSE: (Object)(ret);
358 case SO_REUSEADDR:
359 ret = socketGetOption(opt, null);
360 return Boolean.valueOf(ret != -1);
361 case SO_BINDADDR:
362 InetAddressContainer in = new InetAddressContainer();
363 ret = socketGetOption(opt, in);
364 return in.addr;
365 case SO_SNDBUF:
366 case SO_RCVBUF:
367 ret = socketGetOption(opt, null);
368 return ret;
369 case IP_TOS:
370 try {
371 ret = socketGetOption(opt, null);
372 System.out.println("CHEGAR : ret: " + ret );
373 if (ret == -1) { // ipv6 tos
374 return trafficClass;
375 } else {
376 return ret;
377 }
378 } catch (SocketException se) {
379 // TODO - should make better effort to read TOS or TCLASS
380 System.out.println("CHEGAR : swallowing: " + se );
381 return trafficClass; // ipv6 tos
382 }
383 case SO_KEEPALIVE:
384 ret = socketGetOption(opt, null);
385 return Boolean.valueOf(ret != -1);
386 case SO_REUSEPORT:
387 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
388 throw new UnsupportedOperationException("unsupported option");
389 }
390 ret = socketGetOption(opt, null);
391 return Boolean.valueOf(ret != -1);
392 // should never get here
393 default:
394 return null;
395 }
396 }
397
398 /**
399 * The workhorse of the connection operation. Tries several times to
400 * establish a connection to the given <host, port>. If unsuccessful,
401 * throws an IOException indicating what went wrong.
402 */
403
404 synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
405 synchronized (fdLock) {
406 if (!closePending && (server || !bound)) {
407 NetHooks.beforeTcpConnect(fd, address, port);
408 }
409 }
410 try {
411 acquireFD();
412 try {
413 socketConnect(address, port, timeout);
414 /* socket may have been closed during poll/select */
415 synchronized (fdLock) {
416 if (closePending) {
417 throw new SocketException ("Socket closed");
418 }
419 }
420 } finally {
421 releaseFD();
422 }
423 } catch (IOException e) {
424 close();
425 throw SocketExceptions.of(e, new InetSocketAddress(address, port));
426 }
427 }
428
429 /**
430 * Binds the socket to the specified address of the specified local port.
431 * @param address the address
432 * @param lport the port
433 */
434 protected synchronized void bind(InetAddress address, int lport)
435 throws IOException
436 {
437 synchronized (fdLock) {
438 if (!closePending && (server || !bound)) {
439 NetHooks.beforeTcpBind(fd, address, lport);
440 }
441 }
442 socketBind(address, lport);
443 bound = true;
444 }
445
446 /**
447 * Listens, for a specified amount of time, for connections.
448 * @param count the amount of time to listen for connections
449 */
450 protected synchronized void listen(int count) throws IOException {
451 socketListen(count);
452 }
453
454 /**
455 * Accepts connections.
456 * @param si the socket impl
457 */
458 protected void accept(SocketImpl si) throws IOException {
459 si.fd = new FileDescriptor();
460 acquireFD();
461 try {
462 socketAccept(si);
463 bound = true;
464 connected = true;
465 //TODO REMOVE: try removing these lines to see it something will fail (setting of bound & connected )
466 } finally {
467 releaseFD();
468 }
469 SocketCleanable.register(si.fd);
470 }
471
472 /**
473 * Gets an InputStream for this socket.
474 */
475 protected synchronized InputStream getInputStream() throws IOException {
476 synchronized (fdLock) {
477 if (isClosedOrPending())
478 throw new IOException("Socket Closed");
479 if (shut_rd)
480 throw new IOException("Socket input is shutdown");
481 if (socketInputStream == null) {
482 PrivilegedExceptionAction<SocketInputStream> pa = () -> new SocketInputStream(this);
483 try {
484 socketInputStream = AccessController.doPrivileged(pa);
485 } catch (PrivilegedActionException e) {
712 public int getTimeout() {
713 return timeout;
714 }
715
716 /*
717 * "Pre-close" a socket by dup'ing the file descriptor - this enables
718 * the socket to be closed without releasing the file descriptor.
719 */
720 private void socketPreClose() throws IOException {
721 socketClose0(true);
722 }
723
724 /*
725 * Close the socket (and release the file descriptor).
726 */
727 protected void socketClose() throws IOException {
728 SocketCleanable.unregister(fd);
729 socketClose0(false);
730 }
731
732 abstract void socketCreate(boolean stream, boolean isServer) throws IOException;
733 abstract void socketConnect(InetAddress address, int port, int timeout)
734 throws IOException;
735 abstract void socketBind(InetAddress address, int port)
736 throws IOException;
737 abstract void socketListen(int count)
738 throws IOException;
739 abstract void socketAccept(SocketImpl s)
740 throws IOException;
741 abstract int socketAvailable()
742 throws IOException;
743 abstract void socketClose0(boolean useDeferredClose)
744 throws IOException;
745 abstract void socketShutdown(int howto)
746 throws IOException;
747 abstract void socketSetOption(int cmd, boolean on, Object value)
748 throws SocketException;
749 abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
750 abstract void socketSendUrgentData(int data)
751 throws IOException;
752
|