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