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