1 /*
   2  * Copyright (c) 2002, 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 
  26 /*
  27  */
  28 
  29 /* Maximum number of sockets per select() */
  30 /* This number should be equal to WindowsSelectorImpl.MAX_SELECTABLE_FDS */
  31 /* This definition MUST precede the inclusion of winsock2.h */
  32 
  33 #define FD_SETSIZE 1024
  34 
  35 #include <limits.h>
  36 #include <stdlib.h>
  37 #include <winsock2.h>
  38 
  39 #include "jvm.h"
  40 #include "jni.h"
  41 #include "jni_util.h"
  42 #include "sun_nio_ch_WindowsSelectorImpl.h"
  43 #include "sun_nio_ch_PollArrayWrapper.h"
  44 
  45 #include "nio_util.h" /* Needed for POLL* constants (includes "winsock2.h") */
  46 
  47 typedef struct {
  48     jint fd;
  49     jshort events;
  50 } pollfd;
  51 
  52 #define WAKEUP_SOCKET_BUF_SIZE 16
  53 
  54 
  55 JNIEXPORT jint JNICALL
  56 Java_sun_nio_ch_WindowsSelectorImpl_00024SubSelector_poll0(JNIEnv *env, jobject this,
  57                                    jlong pollAddress, jint numfds,
  58                                    jintArray returnReadFds, jintArray returnWriteFds,
  59                                    jintArray returnExceptFds, jlong timeout)
  60 {
  61     DWORD result = 0;
  62     pollfd *fds = (pollfd *) pollAddress;
  63     int i;
  64     FD_SET readfds, writefds, exceptfds;
  65     struct timeval timevalue, *tv;
  66     static struct timeval zerotime = {0, 0};
  67     int read_count = 0, write_count = 0, except_count = 0;
  68 
  69 #ifdef _WIN64
  70     int resultbuf[FD_SETSIZE + 1];
  71 #endif
  72 
  73     if (timeout == 0) {
  74         tv = &zerotime;
  75     } else if (timeout < 0) {
  76         tv = NULL;
  77     } else {
  78         jlong sec = timeout / 1000;
  79         tv = &timevalue;
  80         //
  81         // struct timeval members are signed 32-bit integers so the
  82         // signed 64-bit jlong needs to be clamped
  83         //
  84         if (sec > INT_MAX) {
  85             tv->tv_sec  = INT_MAX;
  86             tv->tv_usec = 0;
  87         } else {
  88             tv->tv_sec  = (long)sec;
  89             tv->tv_usec = (long)((timeout % 1000) * 1000);
  90         }
  91     }
  92 
  93     /* Set FD_SET structures required for select */
  94     for (i = 0; i < numfds; i++) {
  95         if (fds[i].events & POLLIN) {
  96            readfds.fd_array[read_count] = fds[i].fd;
  97            read_count++;
  98         }
  99         if (fds[i].events & (POLLOUT | POLLCONN))
 100         {
 101            writefds.fd_array[write_count] = fds[i].fd;
 102            write_count++;
 103         }
 104         exceptfds.fd_array[except_count] = fds[i].fd;
 105         except_count++;
 106     }
 107 
 108     readfds.fd_count = read_count;
 109     writefds.fd_count = write_count;
 110     exceptfds.fd_count = except_count;
 111 
 112     /* Call select */
 113     if ((result = select(0 , &readfds, &writefds, &exceptfds, tv))
 114                                                              == SOCKET_ERROR) {
 115         /* Bad error - this should not happen frequently */
 116         /* Iterate over sockets and call select() on each separately */
 117         FD_SET errreadfds, errwritefds, errexceptfds;
 118         readfds.fd_count = 0;
 119         writefds.fd_count = 0;
 120         exceptfds.fd_count = 0;
 121         for (i = 0; i < numfds; i++) {
 122             /* prepare select structures for the i-th socket */
 123             errreadfds.fd_count = 0;
 124             errwritefds.fd_count = 0;
 125             if (fds[i].events & POLLIN) {
 126                errreadfds.fd_array[0] = fds[i].fd;
 127                errreadfds.fd_count = 1;
 128             }
 129             if (fds[i].events & (POLLOUT | POLLCONN))
 130             {
 131                 errwritefds.fd_array[0] = fds[i].fd;
 132                 errwritefds.fd_count = 1;
 133             }
 134             errexceptfds.fd_array[0] = fds[i].fd;
 135             errexceptfds.fd_count = 1;
 136 
 137             /* call select on the i-th socket */
 138             if (select(0, &errreadfds, &errwritefds, &errexceptfds, &zerotime)
 139                                                              == SOCKET_ERROR) {
 140                 /* This socket causes an error. Add it to exceptfds set */
 141                 exceptfds.fd_array[exceptfds.fd_count] = fds[i].fd;
 142                 exceptfds.fd_count++;
 143             } else {
 144                 /* This socket does not cause an error. Process result */
 145                 if (errreadfds.fd_count == 1) {
 146                     readfds.fd_array[readfds.fd_count] = fds[i].fd;
 147                     readfds.fd_count++;
 148                 }
 149                 if (errwritefds.fd_count == 1) {
 150                     writefds.fd_array[writefds.fd_count] = fds[i].fd;
 151                     writefds.fd_count++;
 152                 }
 153                 if (errexceptfds.fd_count == 1) {
 154                     exceptfds.fd_array[exceptfds.fd_count] = fds[i].fd;
 155                     exceptfds.fd_count++;
 156                 }
 157             }
 158         }
 159     }
 160 
 161     /* Return selected sockets. */
 162     /* Each Java array consists of sockets count followed by sockets list */
 163 
 164 #ifdef _WIN64
 165     resultbuf[0] = readfds.fd_count;
 166     for (i = 0; i < (int)readfds.fd_count; i++) {
 167         resultbuf[i + 1] = (int)readfds.fd_array[i];
 168     }
 169     (*env)->SetIntArrayRegion(env, returnReadFds, 0,
 170                               readfds.fd_count + 1, resultbuf);
 171 
 172     resultbuf[0] = writefds.fd_count;
 173     for (i = 0; i < (int)writefds.fd_count; i++) {
 174         resultbuf[i + 1] = (int)writefds.fd_array[i];
 175     }
 176     (*env)->SetIntArrayRegion(env, returnWriteFds, 0,
 177                               writefds.fd_count + 1, resultbuf);
 178 
 179     resultbuf[0] = exceptfds.fd_count;
 180     for (i = 0; i < (int)exceptfds.fd_count; i++) {
 181         resultbuf[i + 1] = (int)exceptfds.fd_array[i];
 182     }
 183     (*env)->SetIntArrayRegion(env, returnExceptFds, 0,
 184                               exceptfds.fd_count + 1, resultbuf);
 185 #else
 186     (*env)->SetIntArrayRegion(env, returnReadFds, 0,
 187                               readfds.fd_count + 1, (jint *)&readfds);
 188 
 189     (*env)->SetIntArrayRegion(env, returnWriteFds, 0,
 190                               writefds.fd_count + 1, (jint *)&writefds);
 191     (*env)->SetIntArrayRegion(env, returnExceptFds, 0,
 192                               exceptfds.fd_count + 1, (jint *)&exceptfds);
 193 #endif
 194     return 0;
 195 }
 196 
 197 JNIEXPORT void JNICALL
 198 Java_sun_nio_ch_WindowsSelectorImpl_setWakeupSocket0(JNIEnv *env, jclass this,
 199                                                 jint scoutFd)
 200 {
 201     int written;
 202     /* Write one byte into the pipe */
 203     const char byte = 1;
 204     written = send(scoutFd, &byte, 1, 0);
 205 
 206     if (written > 0) {
 207         JVM_callFileWriteBytes(env, written);
 208     }
 209 }
 210 
 211 JNIEXPORT void JNICALL
 212 Java_sun_nio_ch_WindowsSelectorImpl_resetWakeupSocket0(JNIEnv *env, jclass this,
 213                                                 jint scinFd)
 214 {
 215     char bytes[WAKEUP_SOCKET_BUF_SIZE];
 216     long bytesToRead;
 217     int read;
 218 
 219     /* Drain socket */
 220     /* Find out how many bytes available for read */
 221     ioctlsocket (scinFd, FIONREAD, &bytesToRead);
 222     if (bytesToRead == 0) {
 223         return;
 224     }
 225     /* Prepare corresponding buffer if needed, and then read */
 226     if (bytesToRead > WAKEUP_SOCKET_BUF_SIZE) {
 227         char* buf = (char*)malloc(bytesToRead);
 228         read = recv(scinFd, buf, bytesToRead, 0);
 229         free(buf);
 230     } else {
 231         read = recv(scinFd, bytes, WAKEUP_SOCKET_BUF_SIZE, 0);
 232     }
 233     if (read > 0) {
 234         JVM_callNetworkReadBytes(env, read);
 235     }
 236 }
 237 
 238 JNIEXPORT jboolean JNICALL
 239 Java_sun_nio_ch_WindowsSelectorImpl_discardUrgentData(JNIEnv* env, jobject this,
 240                                                       jint s)
 241 {
 242     char data[8];
 243     jboolean discarded = JNI_FALSE;
 244     int n;
 245     do {
 246         n = recv(s, (char*)&data, sizeof(data), MSG_OOB);
 247         if (n > 0) {
 248             discarded = JNI_TRUE;
 249         }
 250     } while (n > 0);
 251     return discarded;
 252 }