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