1 /*
   2  * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 #include "net_util.h"
  26 
  27 #include "java_net_PlainSocketImpl.h"
  28 #include "java_net_SocketOptions.h"
  29 
  30 #define SET_BLOCKING     0
  31 #define SET_NONBLOCKING  1
  32 
  33 static jclass isa_class;        /* java.net.InetSocketAddress */
  34 static jmethodID isa_ctorID;    /* InetSocketAddress(InetAddress, int) */
  35 
  36 /*
  37  * Class:     java_net_PlainSocketImpl
  38  * Method:    initIDs
  39  * Signature: ()V
  40  */
  41 JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_initIDs
  42   (JNIEnv *env, jclass clazz) {
  43 
  44     jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
  45     CHECK_NULL(cls);
  46     isa_class = (*env)->NewGlobalRef(env, cls);
  47     CHECK_NULL(isa_class);
  48     isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
  49                                      "(Ljava/net/InetAddress;I)V");
  50     CHECK_NULL(isa_ctorID);
  51     initInetAddressIDs(env);
  52 
  53     // implement read timeout with select.
  54     isRcvTimeoutSupported = JNI_FALSE;
  55 }
  56 
  57 /*
  58  * Class:     java_net_PlainSocketImpl
  59  * Method:    socket0
  60  * Signature: (ZZ)I
  61  */
  62 JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_socket0
  63   (JNIEnv *env, jclass clazz, jboolean stream) {
  64     int fd, rv, opt = 0;
  65     int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
  66     int domain = ipv6_available() ? AF_INET6 : AF_INET;
  67 
  68     fd = NET_Socket(domain, type, 0);
  69 
  70     if (fd == INVALID_SOCKET) {
  71         NET_ThrowNew(env, WSAGetLastError(), "create");
  72         return -1;
  73     }
  74 
  75     if (domain == AF_INET6) {
  76         rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt,
  77                         sizeof(opt));
  78         if (rv == SOCKET_ERROR) {
  79             NET_ThrowNew(env, WSAGetLastError(), "create");
  80             closesocket(fd);
  81             return -1;
  82         }
  83     }
  84 
  85     return fd;
  86 }
  87 
  88 /*
  89  * Class:     java_net_PlainSocketImpl
  90  * Method:    bind0
  91  * Signature: (ILjava/net/InetAddress;I)V
  92  */
  93 JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_bind0
  94   (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
  95    jboolean exclBind)
  96 {
  97     SOCKETADDRESS sa;
  98     int rv, sa_len = 0;
  99     jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
 100 
 101     if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
 102                                   &sa_len, v4MappedAddress) != 0) {
 103         return;
 104     }
 105 
 106     rv = NET_WinBind(fd, &sa, sa_len, exclBind);
 107 
 108     if (rv == SOCKET_ERROR)
 109         NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
 110 }
 111 
 112 /*
 113  * Class:     java_net_PlainSocketImpl
 114  * Method:    connect0
 115  * Signature: (ILjava/net/InetAddress;I)I
 116  */
 117 JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_connect0
 118   (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
 119     SOCKETADDRESS sa;
 120     int rv, sa_len = 0;
 121     jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
 122 
 123     if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
 124                                   &sa_len, v4MappedAddress) != 0) {
 125         return -1;
 126     }
 127 
 128     rv = connect(fd, &sa.sa, sa_len);
 129     if (rv == SOCKET_ERROR) {
 130         int err = WSAGetLastError();
 131         if (err == WSAEWOULDBLOCK) {
 132             return java_net_PlainSocketImpl_WOULDBLOCK;
 133         } else if (err == WSAEADDRNOTAVAIL) {
 134             JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
 135                 "connect: Address is invalid on local machine,"
 136                 " or port is not valid on remote machine");
 137         } else {
 138             NET_ThrowNew(env, err, "connect");
 139         }
 140         // return value not important.
 141     }
 142     return rv;
 143 }
 144 
 145 /*
 146  * Class:     java_net_PlainSocketImpl
 147  * Method:    waitForConnect
 148  * Signature: (II)V
 149  */
 150 JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_waitForConnect
 151   (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
 152     int rv, retry;
 153     int optlen = sizeof(rv);
 154     fd_set wr, ex;
 155     struct timeval t;
 156 
 157     FD_ZERO(&wr);
 158     FD_ZERO(&ex);
 159     FD_SET(fd, &wr);
 160     FD_SET(fd, &ex);
 161     t.tv_sec = timeout / 1000;
 162     t.tv_usec = (timeout % 1000) * 1000;
 163 
 164     /*
 165      * Wait for timeout, connection established or
 166      * connection failed.
 167      */
 168     rv = select(fd+1, 0, &wr, &ex, &t);
 169 
 170     /*
 171      * Timeout before connection is established/failed so
 172      * we throw exception and shutdown input/output to prevent
 173      * socket from being used.
 174      * The socket should be closed immediately by the caller.
 175      */
 176     if (rv == 0) {
 177         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 178                         "connect timed out");
 179         shutdown(fd, SD_BOTH);
 180         return;
 181     }
 182 
 183     /*
 184      * Socket is writable or error occurred. On some Windows editions
 185      * the socket will appear writable when the connect fails so we
 186      * check for error rather than writable.
 187      */
 188     if (!FD_ISSET(fd, &ex)) {
 189         return;         /* connection established */
 190     }
 191 
 192     /*
 193      * Connection failed. The logic here is designed to work around
 194      * bug on Windows NT whereby using getsockopt to obtain the
 195      * last error (SO_ERROR) indicates there is no error. The workaround
 196      * on NT is to allow winsock to be scheduled and this is done by
 197      * yielding and retrying. As yielding is problematic in heavy
 198      * load conditions we attempt up to 3 times to get the error reason.
 199      */
 200     for (retry = 0; retry < 3; retry++) {
 201         NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
 202                        (char*)&rv, &optlen);
 203         if (rv) {
 204             break;
 205         }
 206         Sleep(0);
 207     }
 208 
 209     if (rv == 0) {
 210         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 211                         "Unable to establish connection");
 212     } else if (!ipv6_available() && rv == WSAEADDRNOTAVAIL) {
 213         JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
 214                         "connect: Address is invalid on local machine,"
 215                         " or port is not valid on remote machine");
 216     } else {
 217         NET_ThrowNew(env, rv, "connect");
 218     }
 219 }
 220 
 221 /*
 222  * Class:     java_net_PlainSocketImpl
 223  * Method:    localPort0
 224  * Signature: (I)I
 225  */
 226 JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_localPort0
 227   (JNIEnv *env, jclass clazz, jint fd) {
 228     SOCKETADDRESS sa;
 229     int len = sizeof(sa);
 230 
 231     if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
 232         if (WSAGetLastError() == WSAENOTSOCK) {
 233             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 234                     "Socket closed");
 235         } else {
 236             NET_ThrowNew(env, WSAGetLastError(), "getsockname failed");
 237         }
 238         return -1;
 239     }
 240     return (int) ntohs((u_short)GET_PORT(&sa));
 241 }
 242 
 243 /*
 244  * Class:     java_net_PlainSocketImpl
 245  * Method:    localAddress
 246  * Signature: (ILjava/net/InetAddressContainer;)V
 247  */
 248 JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_localAddress
 249   (JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) {
 250     int port;
 251     SOCKETADDRESS sa;
 252     int len = sizeof(sa);
 253     jobject iaObj;
 254     jclass iaContainerClass;
 255     jfieldID iaFieldID;
 256 
 257     if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
 258         NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
 259         return;
 260     }
 261     iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
 262     CHECK_NULL(iaObj);
 263 
 264     iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);
 265     iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;");
 266     CHECK_NULL(iaFieldID);
 267     (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
 268 }
 269 
 270 /*
 271  * Class:     java_net_PlainSocketImpl
 272  * Method:    listen0
 273  * Signature: (II)V
 274  */
 275 JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_listen0
 276   (JNIEnv *env, jclass clazz, jint fd, jint backlog) {
 277     if (listen(fd, backlog) == SOCKET_ERROR) {
 278         NET_ThrowNew(env, WSAGetLastError(), "listen failed");
 279     }
 280 }
 281 
 282 /*
 283  * Class:     java_net_PlainSocketImpl
 284  * Method:    accept0
 285  * Signature: (I[Ljava/net/InetSocketAddress;)I
 286  */
 287 JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_accept0
 288   (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
 289     int newfd, port = 0;
 290     jobject isa;
 291     jobject ia;
 292     SOCKETADDRESS sa;
 293     int len = sizeof(sa);
 294 
 295     memset((char *)&sa, 0, len);
 296     newfd = accept(fd, &sa.sa, &len);
 297 
 298     if (newfd == INVALID_SOCKET) {
 299         NET_ThrowNew(env, WSAGetLastError(), "accept failed");
 300         return -1;
 301     }
 302 
 303     SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
 304 
 305     ia = NET_SockaddrToInetAddress(env, &sa, &port);
 306     if (ia == NULL){
 307         closesocket(newfd);
 308         return -1;
 309     }
 310     isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
 311     if (isa == NULL) {
 312         closesocket(newfd);
 313         return -1;
 314     }
 315     (*env)->SetObjectArrayElement(env, isaa, 0, isa);
 316 
 317     return newfd;
 318 }
 319 
 320 /*
 321  * Class:     java_net_PlainSocketImpl
 322  * Method:    waitForNewConnection
 323  * Signature: (II)V
 324  */
 325 JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_waitForNewConnection
 326   (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
 327     int rv;
 328 
 329     rv = NET_Timeout(fd, timeout);
 330     if (rv == 0) {
 331         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 332                         "Accept timed out");
 333     } else if (rv == -1) {
 334         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
 335     } else if (rv == -2) {
 336         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 337                         "operation interrupted");
 338     }
 339 }
 340 
 341 /*
 342  * Class:     java_net_PlainSocketImpl
 343  * Method:    available0
 344  * Signature: (I)I
 345  */
 346 JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_available0
 347   (JNIEnv *env, jclass clazz, jint fd) {
 348     jint available = -1;
 349 
 350     if ((ioctlsocket(fd, FIONREAD, &available)) == SOCKET_ERROR) {
 351         NET_ThrowNew(env, WSAGetLastError(), "socket available");
 352     }
 353 
 354     return available;
 355 }
 356 
 357 /*
 358  * Class:     java_net_PlainSocketImpl
 359  * Method:    close0
 360  * Signature: (I)V
 361  */
 362 JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_close0
 363   (JNIEnv *env, jclass clazz, jint fd) {
 364      NET_SocketClose(fd);
 365 }
 366 
 367 /*
 368  * Class:     java_net_PlainSocketImpl
 369  * Method:    shutdown0
 370  * Signature: (II)V
 371  */
 372 JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_shutdown0
 373   (JNIEnv *env, jclass clazz, jint fd, jint howto) {
 374     shutdown(fd, howto);
 375 }
 376 
 377 /*
 378  * Class:     java_net_PlainSocketImpl
 379  * Method:    setIntOption
 380  * Signature: (III)V
 381  */
 382 JNIEXPORT void JNICALL
 383 Java_java_net_PlainSocketImpl_setIntOption
 384   (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value)
 385 {
 386     int level = 0, opt = 0;
 387     struct linger linger = {0, 0};
 388     char *parg;
 389     int arglen;
 390 
 391     if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
 392         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
 393         return;
 394     }
 395 
 396     if (opt == java_net_SocketOptions_SO_LINGER) {
 397         parg = (char *)&linger;
 398         arglen = sizeof(linger);
 399         if (value >= 0) {
 400             linger.l_onoff = 1;
 401             linger.l_linger = (unsigned short)value;
 402         } else {
 403             linger.l_onoff = 0;
 404             linger.l_linger = 0;
 405         }
 406     } else {
 407         parg = (char *)&value;
 408         arglen = sizeof(value);
 409     }
 410 
 411     if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {
 412         NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
 413     }
 414 }
 415 
 416 /*
 417  * Class:     java_net_PlainSocketImpl
 418  * Method:    setSoTimeout0
 419  * Signature: (II)V
 420  */
 421 JNIEXPORT void JNICALL
 422 Java_java_net_PlainSocketImpl_setSoTimeout0
 423   (JNIEnv *env, jclass clazz, jint fd, jint timeout)
 424 {
 425     /*
 426      * SO_TIMEOUT is the socket option used to specify the timeout
 427      * for ServerSocket.accept and Socket.getInputStream().read.
 428      * It does not typically map to a native level socket option.
 429      * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
 430      * socket option to specify a receive timeout on the socket. This
 431      * receive timeout is applicable to Socket only and the socket
 432      * option should not be set on ServerSocket.
 433      */
 434 
 435     /*
 436      * SO_RCVTIMEO is only supported on Microsoft's implementation
 437      * of Windows Sockets so if WSAENOPROTOOPT returned then
 438      * reset flag and timeout will be implemented using
 439      * select() -- see SocketInputStream.socketRead.
 440      */
 441     if (isRcvTimeoutSupported) {
 442         /*
 443          * Disable SO_RCVTIMEO if timeout is <= 5 second.
 444          */
 445         if (timeout <= 5000) {
 446             timeout = 0;
 447         }
 448 
 449         if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
 450             sizeof(timeout)) < 0) {
 451             int err = WSAGetLastError();
 452             if (err == WSAENOPROTOOPT) {
 453                 isRcvTimeoutSupported = JNI_FALSE;
 454             } else {
 455                 NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO");
 456             }
 457         }
 458     }
 459 }
 460 
 461 /*
 462  * Class:     java_net_PlainSocketImpl
 463  * Method:    getIntOption
 464  * Signature: (II)I
 465  */
 466 JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_getIntOption
 467   (JNIEnv *env, jclass clazz, jint fd, jint cmd)
 468 {
 469     int level = 0, opt = 0;
 470     int result = 0;
 471     struct linger linger = {0, 0};
 472     char *arg;
 473     int arglen;
 474 
 475     if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
 476         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
 477         return -1;
 478     }
 479 
 480     if (opt == java_net_SocketOptions_SO_LINGER) {
 481         arg = (char *)&linger;
 482         arglen = sizeof(linger);
 483     } else {
 484         arg = (char *)&result;
 485         arglen = sizeof(result);
 486     }
 487 
 488     if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) {
 489         NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
 490         return -1;
 491     }
 492 
 493     if (opt == java_net_SocketOptions_SO_LINGER)
 494         return linger.l_onoff ? linger.l_linger : -1;
 495     else
 496         return result;
 497 }
 498 
 499 /*
 500  * Class:     java_net_PlainSocketImpl
 501  * Method:    sendOOB
 502  * Signature: (II)V
 503  */
 504 JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_sendOOB
 505   (JNIEnv *env, jclass clazz, jint fd, jint data) {
 506     jint n;
 507     unsigned char d = (unsigned char) data & 0xff;
 508 
 509     n = send(fd, (char *)&data, 1, MSG_OOB);
 510     if (n == SOCKET_ERROR) {
 511         NET_ThrowNew(env, WSAGetLastError(), "send");
 512     }
 513 }
 514 
 515 /*
 516  * Class:     java_net_PlainSocketImpl
 517  * Method:    configureBlocking
 518  * Signature: (IZ)V
 519  */
 520 JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_configureBlocking
 521   (JNIEnv *env, jclass clazz, jint fd, jboolean blocking) {
 522     u_long arg;
 523     int result;
 524 
 525     if (blocking == JNI_TRUE) {
 526         arg = SET_BLOCKING;      // 0
 527     } else {
 528         arg = SET_NONBLOCKING;   // 1
 529     }
 530 
 531     result = ioctlsocket(fd, FIONBIO, &arg);
 532     if (result == SOCKET_ERROR) {
 533         NET_ThrowNew(env, WSAGetLastError(), "configureBlocking");
 534     }
 535 }