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