1 /*
   2  * Copyright (c) 2000, 2008, 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 <windows.h>
  27 #include <winsock2.h>
  28 #include <ctype.h>
  29 #include "jni.h"
  30 #include "jni_util.h"
  31 #include "jvm.h"
  32 #include "jlong.h"
  33 #include "sun_nio_ch_SocketChannelImpl.h"
  34 
  35 #include "nio.h"
  36 #include "nio_util.h"
  37 #include "net_util.h"
  38 
  39 
  40 static jfieldID ia_addrID;      /* java.net.InetAddress.address */
  41 
  42 JNIEXPORT void JNICALL
  43 Java_sun_nio_ch_SocketChannelImpl_initIDs(JNIEnv *env, jclass cls)
  44 {
  45     cls = (*env)->FindClass(env, "java/net/InetAddress");
  46     ia_addrID = (*env)->GetFieldID(env, cls, "address", "I");
  47 }
  48 
  49 jint
  50 handleSocketError(JNIEnv *env, int errorValue)
  51 {
  52     NET_ThrowNew(env, errorValue, NULL);
  53     return IOS_THROWN;
  54 }
  55 
  56 JNIEXPORT jint JNICALL
  57 Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv *env, jobject this,
  58                                                jobject fdo, jboolean block,
  59                                                jboolean ready)
  60 {
  61     int optError = 0;
  62     int lastError = 0;
  63     int result = 0;
  64     int retry = 0;
  65     int n = sizeof(int);
  66     jint fd = fdval(env, fdo);
  67     fd_set wr, ex;
  68     struct timeval t = { 0, 0 };
  69 
  70     FD_ZERO(&wr);
  71     FD_ZERO(&ex);
  72     FD_SET((u_int)fd, &wr);
  73     FD_SET((u_int)fd, &ex);
  74 
  75     result = select(fd+1, 0, &wr, &ex, block ? NULL : &t);
  76 
  77     /* save last winsock error */
  78     if (result == SOCKET_ERROR) {
  79         lastError = WSAGetLastError();
  80     }
  81 
  82     if (block) { /* must configure socket back to blocking state */
  83         u_long argp = 0;
  84         int r = ioctlsocket(fd, FIONBIO, &argp);
  85         if (r == SOCKET_ERROR) {
  86             handleSocketError(env, WSAGetLastError());
  87         }
  88     }
  89 
  90     if (result == 0) {  /* timeout */
  91         return block ? 0 : IOS_UNAVAILABLE;
  92     } else {
  93         if (result == SOCKET_ERROR)     { /* select failed */
  94             handleSocketError(env, lastError);
  95             return IOS_THROWN;
  96         }
  97     }
  98 
  99     /*
 100      * Socket is writable or error occured. On some Windows editions
 101      * the socket will appear writable when the connect fails so we
 102      * check for error rather than writable.
 103      */
 104     if (!FD_ISSET(fd, &ex)) {
 105         return 1;               /* connection established */
 106     }
 107 
 108     /*
 109      * A getsockopt( SO_ERROR ) may indicate success on NT4 even
 110      * though the connection has failed. The workaround is to allow
 111      * winsock to be scheduled and this is done via by yielding.
 112      * As the yield approach is problematic in heavy load situations
 113      * we attempt up to 3 times to get the failure reason.
 114      */
 115     for (retry=0; retry<3; retry++) {
 116         result = getsockopt((SOCKET)fd,
 117                             SOL_SOCKET,
 118                             SO_ERROR,
 119                             (char *)&optError,
 120                             &n);
 121         if (result == SOCKET_ERROR) {
 122             int lastError = WSAGetLastError();
 123             if (lastError == WSAEINPROGRESS) {
 124                 return IOS_UNAVAILABLE;
 125             }
 126             NET_ThrowNew(env, lastError, "getsockopt");
 127             return IOS_THROWN;
 128         }
 129         if (optError) {
 130             break;
 131         }
 132         Sleep(0);
 133     }
 134 
 135     if (optError != NO_ERROR) {
 136         handleSocketError(env, optError);
 137         return IOS_THROWN;
 138     }
 139 
 140     return 0;
 141 }
 142 
 143 JNIEXPORT jint JNICALL
 144 Java_sun_nio_ch_SocketChannelImpl_sendOutOfBandData(JNIEnv* env, jclass this,
 145                                                     jobject fdo, jbyte b)
 146 {
 147     int n = send(fdval(env, fdo), (const char*)&b, 1, MSG_OOB);
 148     if (n == SOCKET_ERROR) {
 149         handleSocketError(env, WSAGetLastError());
 150         return IOS_THROWN;
 151     } else {
 152         return n;
 153     }
 154 }