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