1 /*
2 * Copyright (c) 1997, 2018, 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 #include <errno.h>
26
27 #include "jvm.h"
28 #include "net_util.h"
29
30 #include "java_net_SocketOptions.h"
31 #include "java_net_PlainSocketImpl.h"
32
33 /************************************************************************
34 * PlainSocketImpl
35 */
36
37 static jfieldID IO_fd_fdID;
38
39 jfieldID psi_fdID;
40 jfieldID psi_addressID;
41 jfieldID psi_ipaddressID;
42 jfieldID psi_portID;
43 jfieldID psi_localportID;
44 jfieldID psi_timeoutID;
45 jfieldID psi_trafficClassID;
46 jfieldID psi_serverSocketID;
47 jfieldID psi_fdLockID;
48 jfieldID psi_closePendingID;
49
50 extern void setDefaultScopeID(JNIEnv *env, struct sockaddr *him);
51
52 /*
53 * file descriptor used for dup2
54 */
55 static int marker_fd = -1;
56
57
58 #define SET_NONBLOCKING(fd) { \
59 int flags = fcntl(fd, F_GETFL); \
60 flags |= O_NONBLOCK; \
61 fcntl(fd, F_SETFL, flags); \
62 }
63
64 #define SET_BLOCKING(fd) { \
65 int flags = fcntl(fd, F_GETFL); \
66 flags &= ~O_NONBLOCK; \
67 fcntl(fd, F_SETFL, flags); \
68 }
69
70 /*
71 * Create the marker file descriptor by establishing a loopback connection
72 * which we shutdown but do not close the fd. The result is an fd that
73 * can be used for read/write.
74 */
getMarkerFD()75 static int getMarkerFD()
76 {
77 int sv[2];
78
79 #ifdef AF_UNIX
80 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
81 return -1;
82 }
83 #else
84 return -1;
85 #endif
86
87 /*
88 * Finally shutdown sv[0] (any reads to this fd will get
89 * EOF; any writes will get an error).
90 */
91 shutdown(sv[0], 2);
92 close(sv[1]);
93
94 return sv[0];
95 }
96
97 /*
98 * Return the file descriptor given a PlainSocketImpl
99 */
getFD(JNIEnv * env,jobject this)100 static int getFD(JNIEnv *env, jobject this) {
101 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
102 CHECK_NULL_RETURN(fdObj, -1);
103 return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
104 }
105
106 /*
107 * The initroto function is called whenever PlainSocketImpl is
108 * loaded, to cache field IDs for efficiency. This is called every time
109 * the Java class is loaded.
110 *
111 * Class: java_net_PlainSocketImpl
112 * Method: initProto
113 * Signature: ()V
114 */
115 JNIEXPORT void JNICALL
Java_java_net_PlainSocketImpl_initProto(JNIEnv * env,jclass cls)116 Java_java_net_PlainSocketImpl_initProto(JNIEnv *env, jclass cls) {
117 psi_fdID = (*env)->GetFieldID(env, cls , "fd",
118 "Ljava/io/FileDescriptor;");
119 CHECK_NULL(psi_fdID);
120 psi_addressID = (*env)->GetFieldID(env, cls, "address",
121 "Ljava/net/InetAddress;");
122 CHECK_NULL(psi_addressID);
123 psi_portID = (*env)->GetFieldID(env, cls, "port", "I");
124 CHECK_NULL(psi_portID);
125 psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");
126 CHECK_NULL(psi_localportID);
127 psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
128 CHECK_NULL(psi_timeoutID);
129 psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
130 CHECK_NULL(psi_trafficClassID);
131 psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket",
132 "Ljava/net/ServerSocket;");
133 CHECK_NULL(psi_serverSocketID);
134 psi_fdLockID = (*env)->GetFieldID(env, cls, "fdLock",
135 "Ljava/lang/Object;");
136 CHECK_NULL(psi_fdLockID);
137 psi_closePendingID = (*env)->GetFieldID(env, cls, "closePending", "Z");
138 CHECK_NULL(psi_closePendingID);
139 IO_fd_fdID = NET_GetFileDescriptorID(env);
140 CHECK_NULL(IO_fd_fdID);
141
142 initInetAddressIDs(env);
143 JNU_CHECK_EXCEPTION(env);
144
145 /* Create the marker fd used for dup2 */
146 marker_fd = getMarkerFD();
147 }
148
149 /* a global reference to the java.net.SocketException class. In
150 * socketCreate, we ensure that this is initialized. This is to
151 * prevent the problem where socketCreate runs out of file
152 * descriptors, and is then unable to load the exception class.
153 */
154 static jclass socketExceptionCls;
155
156 /*
157 * Class: java_net_PlainSocketImpl
158 * Method: socketCreate
159 * Signature: (Z)V */
160 JNIEXPORT void JNICALL
Java_java_net_PlainSocketImpl_socketCreate(JNIEnv * env,jobject this,jboolean stream)161 Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
162 jboolean stream) {
163 jobject fdObj, ssObj;
164 int fd;
165 int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
166 int domain = ipv6_available() ? AF_INET6 : AF_INET;
167
168 if (socketExceptionCls == NULL) {
169 jclass c = (*env)->FindClass(env, "java/net/SocketException");
170 CHECK_NULL(c);
171 socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c);
172 CHECK_NULL(socketExceptionCls);
173 }
174 fdObj = (*env)->GetObjectField(env, this, psi_fdID);
175
176 if (fdObj == NULL) {
177 (*env)->ThrowNew(env, socketExceptionCls, "null fd object");
178 return;
179 }
180
181 if ((fd = socket(domain, type, 0)) == -1) {
182 /* note: if you run out of fds, you may not be able to load
183 * the exception class, and get a NoClassDefFoundError
184 * instead.
185 */
186 NET_ThrowNew(env, errno, "can't create socket");
187 return;
188 }
189
190 #ifndef _BSDONLY_SOURCE
191 /* Disable IPV6_V6ONLY to ensure dual-socket support */
192 if (domain == AF_INET6) {
193 int arg = 0;
194 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
195 sizeof(int)) < 0) {
196 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
197 close(fd);
198 return;
199 }
200 }
201 #endif
202
203 /*
204 * If this is a server socket then enable SO_REUSEADDR
205 * automatically and set to non blocking.
206 */
207 ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID);
208 if (ssObj != NULL) {
209 int arg = 1;
210 SET_NONBLOCKING(fd);
211 if (NET_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
212 sizeof(arg)) < 0) {
213 NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");
214 close(fd);
215 return;
216 }
217 }
218
219 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
220 }
221
222 /*
223 * inetAddress is the address object passed to the socket connect
224 * call.
225 *
226 * Class: java_net_PlainSocketImpl
227 * Method: socketConnect
228 * Signature: (Ljava/net/InetAddress;I)V
229 */
230 JNIEXPORT void JNICALL
Java_java_net_PlainSocketImpl_socketConnect(JNIEnv * env,jobject this,jobject iaObj,jint port,jint timeout)231 Java_java_net_PlainSocketImpl_socketConnect(JNIEnv *env, jobject this,
232 jobject iaObj, jint port,
233 jint timeout)
234 {
235 jint localport = (*env)->GetIntField(env, this, psi_localportID);
236 int len = 0;
237 /* fdObj is the FileDescriptor field on this */
238 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
239
240 jclass clazz = (*env)->GetObjectClass(env, this);
241
242 jobject fdLock;
243
244 jint trafficClass = (*env)->GetIntField(env, this, psi_trafficClassID);
245
246 /* fd is an int field on iaObj */
247 jint fd;
248
249 SOCKETADDRESS sa;
250 /* The result of the connection */
251 int connect_rv = -1;
252
253 if (IS_NULL(fdObj)) {
254 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
255 return;
256 } else {
257 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
258 }
259 if (IS_NULL(iaObj)) {
260 JNU_ThrowNullPointerException(env, "inet address argument null.");
261 return;
262 }
263
264 /* connect */
265 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len,
266 JNI_TRUE) != 0) {
267 return;
268 }
269 setDefaultScopeID(env, &sa.sa);
270
271 if (trafficClass != 0 && ipv6_available()) {
272 NET_SetTrafficClass(&sa, trafficClass);
273 }
274
275 if (timeout <= 0) {
276 connect_rv = NET_Connect(fd, &sa.sa, len);
277 #ifdef __solaris__
278 if (connect_rv == -1 && errno == EINPROGRESS ) {
279
280 /* This can happen if a blocking connect is interrupted by a signal.
281 * See 6343810.
282 */
283 while (1) {
284 struct pollfd pfd;
285 pfd.fd = fd;
286 pfd.events = POLLOUT;
287
288 connect_rv = NET_Poll(&pfd, 1, -1);
289
290 if (connect_rv == -1) {
291 if (errno == EINTR) {
292 continue;
293 } else {
294 break;
295 }
296 }
297 if (connect_rv > 0) {
298 socklen_t optlen;
299 /* has connection been established */
300 optlen = sizeof(connect_rv);
301 if (getsockopt(fd, SOL_SOCKET, SO_ERROR,
302 (void*)&connect_rv, &optlen) <0) {
303 connect_rv = errno;
304 }
305
306 if (connect_rv != 0) {
307 /* restore errno */
308 errno = connect_rv;
309 connect_rv = -1;
310 }
311 break;
312 }
313 }
314 }
315 #endif
316 } else {
317 /*
318 * A timeout was specified. We put the socket into non-blocking
319 * mode, connect, and then wait for the connection to be
320 * established, fail, or timeout.
321 */
322 SET_NONBLOCKING(fd);
323
324 /* no need to use NET_Connect as non-blocking */
325 connect_rv = connect(fd, &sa.sa, len);
326
327 /* connection not established immediately */
328 if (connect_rv != 0) {
329 socklen_t optlen;
330 jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
331 jlong prevNanoTime = JVM_NanoTime(env, 0);
332
333 if (errno != EINPROGRESS) {
334 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
335 "connect failed");
336 SET_BLOCKING(fd);
337 return;
338 }
339
340 /*
341 * Wait for the connection to be established or a
342 * timeout occurs. poll needs to handle EINTR in
343 * case lwp sig handler redirects any process signals to
344 * this thread.
345 */
346 while (1) {
347 jlong newNanoTime;
348 struct pollfd pfd;
349 pfd.fd = fd;
350 pfd.events = POLLOUT;
351
352 errno = 0;
353 connect_rv = NET_Poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC);
354
355 if (connect_rv >= 0) {
356 break;
357 }
358 if (errno != EINTR) {
359 break;
360 }
361
362 /*
363 * The poll was interrupted so adjust timeout and
364 * restart
365 */
366 newNanoTime = JVM_NanoTime(env, 0);
367 nanoTimeout -= (newNanoTime - prevNanoTime);
368 if (nanoTimeout < NET_NSEC_PER_MSEC) {
369 connect_rv = 0;
370 break;
371 }
372 prevNanoTime = newNanoTime;
373
374 } /* while */
375
376 if (connect_rv == 0) {
377 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
378 "connect timed out");
379
380 /*
381 * Timeout out but connection may still be established.
382 * At the high level it should be closed immediately but
383 * just in case we make the socket blocking again and
384 * shutdown input & output.
385 */
386 SET_BLOCKING(fd);
387 shutdown(fd, 2);
388 return;
389 }
390
391 /* has connection been established */
392 optlen = sizeof(connect_rv);
393 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
394 &optlen) <0) {
395 connect_rv = errno;
396 }
397 }
398
399 /* make socket blocking again */
400 SET_BLOCKING(fd);
401
402 /* restore errno */
403 if (connect_rv != 0) {
404 errno = connect_rv;
405 connect_rv = -1;
406 }
407 }
408
409 /* report the appropriate exception */
410 if (connect_rv < 0) {
411
412 #ifdef __linux__
413 /*
414 * Linux/GNU distribution setup /etc/hosts so that
415 * InetAddress.getLocalHost gets back the loopback address
416 * rather than the host address. Thus a socket can be
417 * bound to the loopback address and the connect will
418 * fail with EADDRNOTAVAIL. In addition the Linux kernel
419 * returns the wrong error in this case - it returns EINVAL
420 * instead of EADDRNOTAVAIL. We handle this here so that
421 * a more descriptive exception text is used.
422 */
423 if (connect_rv == -1 && errno == EINVAL) {
424 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
425 "Invalid argument or cannot assign requested address");
426 return;
427 }
428 #endif
429 #if defined(EPROTO)
430 if (errno == EPROTO) {
431 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ProtocolException",
432 "Protocol error");
433 return;
434 }
435 #endif
436 if (errno == ECONNREFUSED) {
437 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
438 "Connection refused");
439 } else if (errno == ETIMEDOUT) {
440 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
441 "Connection timed out");
442 } else if (errno == EHOSTUNREACH) {
443 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",
444 "Host unreachable");
445 } else if (errno == EADDRNOTAVAIL) {
446 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",
447 "Address not available");
448 } else if ((errno == EISCONN) || (errno == EBADF)) {
449 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
450 "Socket closed");
451 } else {
452 JNU_ThrowByNameWithMessageAndLastError
453 (env, JNU_JAVANETPKG "SocketException", "connect failed");
454 }
455 return;
456 }
457
458 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
459
460 /* set the remote peer address and port */
461 (*env)->SetObjectField(env, this, psi_addressID, iaObj);
462 (*env)->SetIntField(env, this, psi_portID, port);
463
464 /*
465 * we need to initialize the local port field if bind was called
466 * previously to the connect (by the client) then localport field
467 * will already be initialized
468 */
469 if (localport == 0) {
470 /* Now that we're a connected socket, let's extract the port number
471 * that the system chose for us and store it in the Socket object.
472 */
473 socklen_t slen = sizeof(SOCKETADDRESS);
474 if (getsockname(fd, &sa.sa, &slen) == -1) {
475 JNU_ThrowByNameWithMessageAndLastError
476 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
477 } else {
478 localport = NET_GetPortFromSockaddr(&sa);
479 (*env)->SetIntField(env, this, psi_localportID, localport);
480 }
481 }
482 }
483
484 /*
485 * Class: java_net_PlainSocketImpl
486 * Method: socketBind
487 * Signature: (Ljava/net/InetAddress;I)V
488 */
489 JNIEXPORT void JNICALL
Java_java_net_PlainSocketImpl_socketBind(JNIEnv * env,jobject this,jobject iaObj,jint localport)490 Java_java_net_PlainSocketImpl_socketBind(JNIEnv *env, jobject this,
491 jobject iaObj, jint localport) {
492
493 /* fdObj is the FileDescriptor field on this */
494 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
495 /* fd is an int field on fdObj */
496 int fd;
497 int len = 0;
498 SOCKETADDRESS sa;
499
500 if (IS_NULL(fdObj)) {
501 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
502 "Socket closed");
503 return;
504 } else {
505 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
506 }
507 if (IS_NULL(iaObj)) {
508 JNU_ThrowNullPointerException(env, "iaObj is null.");
509 return;
510 }
511
512 /* bind */
513 if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa,
514 &len, JNI_TRUE) != 0) {
515 return;
516 }
517 setDefaultScopeID(env, &sa.sa);
518
519 if (NET_Bind(fd, &sa, len) < 0) {
520 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
521 errno == EPERM || errno == EACCES) {
522 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
523 "Bind failed");
524 } else {
525 JNU_ThrowByNameWithMessageAndLastError
526 (env, JNU_JAVANETPKG "SocketException", "Bind failed");
527 }
528 return;
529 }
530
531 /* set the address */
532 (*env)->SetObjectField(env, this, psi_addressID, iaObj);
533
534 /* initialize the local port */
535 if (localport == 0) {
536 socklen_t slen = sizeof(SOCKETADDRESS);
537 /* Now that we're a connected socket, let's extract the port number
538 * that the system chose for us and store it in the Socket object.
539 */
540 if (getsockname(fd, &sa.sa, &slen) == -1) {
541 JNU_ThrowByNameWithMessageAndLastError
542 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
543 return;
544 }
545 localport = NET_GetPortFromSockaddr(&sa);
546 (*env)->SetIntField(env, this, psi_localportID, localport);
547 } else {
548 (*env)->SetIntField(env, this, psi_localportID, localport);
549 }
550 }
551
552 /*
553 * Class: java_net_PlainSocketImpl
554 * Method: socketListen
555 * Signature: (I)V
556 */
557 JNIEXPORT void JNICALL
Java_java_net_PlainSocketImpl_socketListen(JNIEnv * env,jobject this,jint count)558 Java_java_net_PlainSocketImpl_socketListen(JNIEnv *env, jobject this,
559 jint count)
560 {
561 /* this FileDescriptor fd field */
562 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
563 /* fdObj's int fd field */
564 int fd;
565
566 if (IS_NULL(fdObj)) {
567 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
568 "Socket closed");
569 return;
570 } else {
571 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
572 }
573
574 /*
575 * Workaround for bugid 4101691 in Solaris 2.6. See 4106600.
576 * If listen backlog is Integer.MAX_VALUE then subtract 1.
577 */
578 if (count == 0x7fffffff)
579 count -= 1;
580
581 if (listen(fd, count) == -1) {
582 JNU_ThrowByNameWithMessageAndLastError
583 (env, JNU_JAVANETPKG "SocketException", "Listen failed");
584 }
585 }
586
587 /*
588 * Class: java_net_PlainSocketImpl
589 * Method: socketAccept
590 * Signature: (Ljava/net/SocketImpl;)V
591 */
592 JNIEXPORT void JNICALL
Java_java_net_PlainSocketImpl_socketAccept(JNIEnv * env,jobject this,jobject socket)593 Java_java_net_PlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
594 jobject socket)
595 {
596 /* fields on this */
597 int port;
598 jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
599 jlong prevNanoTime = 0;
600 jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
601 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
602
603 /* the FileDescriptor field on socket */
604 jobject socketFdObj;
605 /* the InetAddress field on socket */
606 jobject socketAddressObj;
607
608 /* the ServerSocket fd int field on fdObj */
609 jint fd;
610
611 /* accepted fd */
612 jint newfd;
613
614 SOCKETADDRESS sa;
615 socklen_t slen = sizeof(SOCKETADDRESS);
616
617 if (IS_NULL(fdObj)) {
618 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
619 "Socket closed");
620 return;
621 } else {
622 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
623 }
624 if (IS_NULL(socket)) {
625 JNU_ThrowNullPointerException(env, "socket is null");
626 return;
627 }
628
629 /*
630 * accept connection but ignore ECONNABORTED indicating that
631 * connection was eagerly accepted by the OS but was reset
632 * before accept() was called.
633 *
634 * If accept timeout in place and timeout is adjusted with
635 * each ECONNABORTED or EWOULDBLOCK or EAGAIN to ensure that
636 * semantics of timeout are preserved.
637 */
638 for (;;) {
639 int ret;
640 jlong currNanoTime;
641
642 /* first usage pick up current time */
643 if (prevNanoTime == 0 && nanoTimeout > 0) {
644 prevNanoTime = JVM_NanoTime(env, 0);
645 }
646
647 /* passing a timeout of 0 to poll will return immediately,
648 but in the case of ServerSocket 0 means infinite. */
649 if (timeout <= 0) {
650 ret = NET_Timeout(env, fd, -1, 0);
651 } else {
652 ret = NET_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC, prevNanoTime);
653 }
654 if (ret == 0) {
655 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
656 "Accept timed out");
657 return;
658 } else if (ret == -1) {
659 if (errno == EBADF) {
660 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
661 } else if (errno == ENOMEM) {
662 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
663 } else {
664 JNU_ThrowByNameWithMessageAndLastError
665 (env, JNU_JAVANETPKG "SocketException", "Accept failed");
666 }
667 return;
668 }
669
670 newfd = NET_Accept(fd, &sa.sa, &slen);
671
672 /* connection accepted */
673 if (newfd >= 0) {
674 SET_BLOCKING(newfd);
675 break;
676 }
677
678 /* non (ECONNABORTED or EWOULDBLOCK or EAGAIN) error */
679 if (!(errno == ECONNABORTED || errno == EWOULDBLOCK || errno == EAGAIN)) {
680 break;
681 }
682
683 /* ECONNABORTED or EWOULDBLOCK or EAGAIN error so adjust timeout if there is one. */
684 if (nanoTimeout >= NET_NSEC_PER_MSEC) {
685 currNanoTime = JVM_NanoTime(env, 0);
686 nanoTimeout -= (currNanoTime - prevNanoTime);
687 if (nanoTimeout < NET_NSEC_PER_MSEC) {
688 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
689 "Accept timed out");
690 return;
691 }
692 prevNanoTime = currNanoTime;
693 }
694 }
695
696 if (newfd < 0) {
697 if (newfd == -2) {
698 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
699 "operation interrupted");
700 } else {
701 if (errno == EINVAL) {
702 errno = EBADF;
703 }
704 if (errno == EBADF) {
705 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
706 } else {
707 JNU_ThrowByNameWithMessageAndLastError
708 (env, JNU_JAVANETPKG "SocketException", "Accept failed");
709 }
710 }
711 return;
712 }
713
714 /*
715 * fill up the remote peer port and address in the new socket structure.
716 */
717 socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port);
718 if (socketAddressObj == NULL) {
719 /* should be pending exception */
720 close(newfd);
721 return;
722 }
723
724 /*
725 * Populate SocketImpl.fd.fd
726 */
727 socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
728 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd);
729
730 (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
731 (*env)->SetIntField(env, socket, psi_portID, port);
732 /* also fill up the local port information */
733 port = (*env)->GetIntField(env, this, psi_localportID);
734 (*env)->SetIntField(env, socket, psi_localportID, port);
735 }
736
737
738 /*
739 * Class: java_net_PlainSocketImpl
740 * Method: socketAvailable
741 * Signature: ()I
742 */
743 JNIEXPORT jint JNICALL
Java_java_net_PlainSocketImpl_socketAvailable(JNIEnv * env,jobject this)744 Java_java_net_PlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {
745
746 jint ret = -1;
747 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
748 jint fd;
749
750 if (IS_NULL(fdObj)) {
751 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
752 "Socket closed");
753 return -1;
754 } else {
755 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
756 }
757 /* NET_SocketAvailable returns 0 for failure, 1 for success */
758 if (NET_SocketAvailable(fd, &ret) == 0){
759 if (errno == ECONNRESET) {
760 JNU_ThrowByName(env, "sun/net/ConnectionResetException", "");
761 } else {
762 JNU_ThrowByNameWithMessageAndLastError
763 (env, JNU_JAVANETPKG "SocketException", "ioctl FIONREAD failed");
764 }
765 }
766 return ret;
767 }
768
769 /*
770 * Class: java_net_PlainSocketImpl
771 * Method: socketClose0
772 * Signature: (Z)V
773 */
774 JNIEXPORT void JNICALL
Java_java_net_PlainSocketImpl_socketClose0(JNIEnv * env,jobject this,jboolean useDeferredClose)775 Java_java_net_PlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
776 jboolean useDeferredClose) {
777
778 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
779 jint fd;
780
781 if (IS_NULL(fdObj)) {
782 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
783 "socket already closed");
784 return;
785 } else {
786 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
787 }
788 if (fd != -1) {
789 if (useDeferredClose && marker_fd >= 0) {
790 NET_Dup2(marker_fd, fd);
791 } else {
792 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
793 NET_SocketClose(fd);
794 }
795 }
796 }
797
798 /*
799 * Class: java_net_PlainSocketImpl
800 * Method: socketShutdown
801 * Signature: (I)V
802 */
803 JNIEXPORT void JNICALL
Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv * env,jobject this,jint howto)804 Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
805 jint howto)
806 {
807
808 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
809 jint fd;
810
811 /*
812 * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
813 * -1 already?
814 */
815 if (IS_NULL(fdObj)) {
816 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
817 "socket already closed");
818 return;
819 } else {
820 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
821 }
822 shutdown(fd, howto);
823 }
824
825
826 /*
827 * Class: java_net_PlainSocketImpl
828 * Method: socketSetOption0
829 * Signature: (IZLjava/lang/Object;)V
830 */
831 JNIEXPORT void JNICALL
Java_java_net_PlainSocketImpl_socketSetOption0(JNIEnv * env,jobject this,jint cmd,jboolean on,jobject value)832 Java_java_net_PlainSocketImpl_socketSetOption0
833 (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value)
834 {
835 int fd;
836 int level, optname, optlen;
837 union {
838 int i;
839 struct linger ling;
840 } optval;
841
842 /*
843 * Check that socket hasn't been closed
844 */
845 fd = getFD(env, this);
846 if (fd < 0) {
847 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
848 "Socket closed");
849 return;
850 }
851
852 /*
853 * SO_TIMEOUT is a NOOP on Solaris/Linux
854 */
855 if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
856 return;
857 }
858
859 /*
860 * Map the Java level socket option to the platform specific
861 * level and option name.
862 */
863 if (NET_MapSocketOption(cmd, &level, &optname)) {
864 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
865 return;
866 }
867
868 switch (cmd) {
869 case java_net_SocketOptions_SO_SNDBUF :
870 case java_net_SocketOptions_SO_RCVBUF :
871 case java_net_SocketOptions_SO_LINGER :
872 case java_net_SocketOptions_IP_TOS :
873 {
874 jclass cls;
875 jfieldID fid;
876
877 cls = (*env)->FindClass(env, "java/lang/Integer");
878 CHECK_NULL(cls);
879 fid = (*env)->GetFieldID(env, cls, "value", "I");
880 CHECK_NULL(fid);
881
882 if (cmd == java_net_SocketOptions_SO_LINGER) {
883 if (on) {
884 optval.ling.l_onoff = 1;
885 optval.ling.l_linger = (*env)->GetIntField(env, value, fid);
886 } else {
887 optval.ling.l_onoff = 0;
888 optval.ling.l_linger = 0;
889 }
890 optlen = sizeof(optval.ling);
891 } else {
892 optval.i = (*env)->GetIntField(env, value, fid);
893 optlen = sizeof(optval.i);
894 }
895
896 break;
897 }
898
899 /* Boolean -> int */
900 default :
901 optval.i = (on ? 1 : 0);
902 optlen = sizeof(optval.i);
903
904 }
905
906 if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
907 #if defined(__solaris__) || defined(_AIX)
908 if (errno == EINVAL) {
909 // On Solaris setsockopt will set errno to EINVAL if the socket
910 // is closed. The default error message is then confusing
911 char fullMsg[128];
912 jio_snprintf(fullMsg, sizeof(fullMsg), "Invalid option or socket reset by remote peer");
913 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);
914 return;
915 }
916 #endif /* __solaris__ */
917 JNU_ThrowByNameWithMessageAndLastError
918 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
919 }
920 }
921
922 /*
923 * Class: java_net_PlainSocketImpl
924 * Method: socketGetOption
925 * Signature: (ILjava/lang/Object;)I
926 */
927 JNIEXPORT jint JNICALL
Java_java_net_PlainSocketImpl_socketGetOption(JNIEnv * env,jobject this,jint cmd,jobject iaContainerObj)928 Java_java_net_PlainSocketImpl_socketGetOption
929 (JNIEnv *env, jobject this, jint cmd, jobject iaContainerObj)
930 {
931 int fd;
932 int level, optname, optlen;
933 union {
934 int i;
935 struct linger ling;
936 } optval;
937
938 /*
939 * Check that socket hasn't been closed
940 */
941 fd = getFD(env, this);
942 if (fd < 0) {
943 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
944 "Socket closed");
945 return -1;
946 }
947
948 /*
949 * SO_BINDADDR isn't a socket option
950 */
951 if (cmd == java_net_SocketOptions_SO_BINDADDR) {
952 SOCKETADDRESS sa;
953 socklen_t len = sizeof(SOCKETADDRESS);
954 int port;
955 jobject iaObj;
956 jclass iaCntrClass;
957 jfieldID iaFieldID;
958
959 if (getsockname(fd, &sa.sa, &len) < 0) {
960 JNU_ThrowByNameWithMessageAndLastError
961 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
962 return -1;
963 }
964 iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
965 CHECK_NULL_RETURN(iaObj, -1);
966
967 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
968 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");
969 CHECK_NULL_RETURN(iaFieldID, -1);
970 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
971 return 0; /* notice change from before */
972 }
973
974 /*
975 * Map the Java level socket option to the platform specific
976 * level and option name.
977 */
978 if (NET_MapSocketOption(cmd, &level, &optname)) {
979 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
980 return -1;
981 }
982
983 /*
984 * Args are int except for SO_LINGER
985 */
986 if (cmd == java_net_SocketOptions_SO_LINGER) {
987 optlen = sizeof(optval.ling);
988 } else {
989 optlen = sizeof(optval.i);
990 }
991
992 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
993 JNU_ThrowByNameWithMessageAndLastError
994 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
995 return -1;
996 }
997
998 switch (cmd) {
999 case java_net_SocketOptions_SO_LINGER:
1000 return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
1001
1002 case java_net_SocketOptions_SO_SNDBUF:
1003 case java_net_SocketOptions_SO_RCVBUF:
1004 case java_net_SocketOptions_IP_TOS:
1005 return optval.i;
1006
1007 default :
1008 return (optval.i == 0) ? -1 : 1;
1009 }
1010 }
1011
1012
1013 /*
1014 * Class: java_net_PlainSocketImpl
1015 * Method: socketSendUrgentData
1016 * Signature: (B)V
1017 */
1018 JNIEXPORT void JNICALL
Java_java_net_PlainSocketImpl_socketSendUrgentData(JNIEnv * env,jobject this,jint data)1019 Java_java_net_PlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
1020 jint data) {
1021 /* The fd field */
1022 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1023 int n, fd;
1024 unsigned char d = data & 0xFF;
1025
1026 if (IS_NULL(fdObj)) {
1027 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1028 return;
1029 } else {
1030 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1031 /* Bug 4086704 - If the Socket associated with this file descriptor
1032 * was closed (sysCloseFD), the file descriptor is set to -1.
1033 */
1034 if (fd == -1) {
1035 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1036 return;
1037 }
1038
1039 }
1040 n = NET_Send(fd, (char *)&d, 1, MSG_OOB);
1041 if (n == -1) {
1042 JNU_ThrowIOExceptionWithLastError(env, "Write failed");
1043 }
1044 }
1045