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