1 /*
2 * Copyright (c) 2002, 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
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 "nio.h"
43 #include "sun_nio_ch_WindowsSelectorImpl.h"
44 #include "sun_nio_ch_PollArrayWrapper.h"
45
46 #include "nio_util.h" /* Needed for POLL* constants (includes "winsock2.h") */
47
48 typedef struct {
49 jint fd;
50 jshort events;
51 } pollfd;
52
53 #define WAKEUP_SOCKET_BUF_SIZE 16
54
55
56 JNIEXPORT jint JNICALL
Java_sun_nio_ch_WindowsSelectorImpl_00024SubSelector_poll0(JNIEnv * env,jobject this,jlong pollAddress,jint numfds,jintArray returnReadFds,jintArray returnWriteFds,jintArray returnExceptFds,jlong timeout,jlong fdsBuffer)57 Java_sun_nio_ch_WindowsSelectorImpl_00024SubSelector_poll0(JNIEnv *env, jobject this,
58 jlong pollAddress, jint numfds,
59 jintArray returnReadFds, jintArray returnWriteFds,
60 jintArray returnExceptFds, jlong timeout, jlong fdsBuffer)
61 {
62 DWORD result = 0;
63 pollfd *fds = (pollfd *) pollAddress;
64 int i;
65 FD_SET *readfds = (FD_SET *) jlong_to_ptr(fdsBuffer);
66 FD_SET *writefds = (FD_SET *) jlong_to_ptr(fdsBuffer + sizeof(FD_SET));
67 FD_SET *exceptfds = (FD_SET *) jlong_to_ptr(fdsBuffer + sizeof(FD_SET) * 2);
68 struct timeval timevalue, *tv;
69 static struct timeval zerotime = {0, 0};
70 int read_count = 0, write_count = 0, except_count = 0;
71
72 #ifdef _WIN64
73 int resultbuf[FD_SETSIZE + 1];
74 #endif
75
76 if (timeout == 0) {
77 tv = &zerotime;
78 } else if (timeout < 0) {
79 tv = NULL;
80 } else {
81 jlong sec = timeout / 1000;
82 tv = &timevalue;
83 //
84 // struct timeval members are signed 32-bit integers so the
85 // signed 64-bit jlong needs to be clamped
86 //
87 if (sec > INT_MAX) {
88 tv->tv_sec = INT_MAX;
89 tv->tv_usec = 0;
90 } else {
91 tv->tv_sec = (long)sec;
92 tv->tv_usec = (long)((timeout % 1000) * 1000);
93 }
94 }
95
96 /* Set FD_SET structures required for select */
97 for (i = 0; i < numfds; i++) {
98 if (fds[i].events & POLLIN) {
99 readfds->fd_array[read_count] = fds[i].fd;
100 read_count++;
101 }
102 if (fds[i].events & (POLLOUT | POLLCONN))
103 {
104 writefds->fd_array[write_count] = fds[i].fd;
105 write_count++;
106 }
107 exceptfds->fd_array[except_count] = fds[i].fd;
108 except_count++;
109 }
110
111 readfds->fd_count = read_count;
112 writefds->fd_count = write_count;
113 exceptfds->fd_count = except_count;
114
115 /* Call select */
116 if ((result = select(0 , readfds, writefds, exceptfds, tv))
117 == SOCKET_ERROR) {
118 JNU_ThrowIOExceptionWithLastError(env, "Select failed");
119 return IOS_THROWN;
120 }
121
122 /* Return selected sockets. */
123 /* Each Java array consists of sockets count followed by sockets list */
124
125 #ifdef _WIN64
126 resultbuf[0] = readfds->fd_count;
127 for (i = 0; i < (int)readfds->fd_count; i++) {
128 resultbuf[i + 1] = (int)readfds->fd_array[i];
129 }
130 (*env)->SetIntArrayRegion(env, returnReadFds, 0,
131 readfds->fd_count + 1, resultbuf);
132
133 resultbuf[0] = writefds->fd_count;
134 for (i = 0; i < (int)writefds->fd_count; i++) {
135 resultbuf[i + 1] = (int)writefds->fd_array[i];
136 }
137 (*env)->SetIntArrayRegion(env, returnWriteFds, 0,
138 writefds->fd_count + 1, resultbuf);
139
140 resultbuf[0] = exceptfds->fd_count;
141 for (i = 0; i < (int)exceptfds->fd_count; i++) {
142 resultbuf[i + 1] = (int)exceptfds->fd_array[i];
143 }
144 (*env)->SetIntArrayRegion(env, returnExceptFds, 0,
145 exceptfds->fd_count + 1, resultbuf);
146 #else
147 (*env)->SetIntArrayRegion(env, returnReadFds, 0,
148 readfds->fd_count + 1, (jint *)readfds);
149
150 (*env)->SetIntArrayRegion(env, returnWriteFds, 0,
151 writefds->fd_count + 1, (jint *)writefds);
152 (*env)->SetIntArrayRegion(env, returnExceptFds, 0,
153 exceptfds->fd_count + 1, (jint *)exceptfds);
154 #endif
155 return 0;
156 }
157
158 JNIEXPORT void JNICALL
Java_sun_nio_ch_WindowsSelectorImpl_setWakeupSocket0(JNIEnv * env,jclass this,jint scoutFd)159 Java_sun_nio_ch_WindowsSelectorImpl_setWakeupSocket0(JNIEnv *env, jclass this,
160 jint scoutFd)
161 {
162 /* Write one byte into the pipe */
163 const char byte = 1;
164 send(scoutFd, &byte, 1, 0);
165 }
166
167 JNIEXPORT void JNICALL
Java_sun_nio_ch_WindowsSelectorImpl_resetWakeupSocket0(JNIEnv * env,jclass this,jint scinFd)168 Java_sun_nio_ch_WindowsSelectorImpl_resetWakeupSocket0(JNIEnv *env, jclass this,
169 jint scinFd)
170 {
171 char bytes[WAKEUP_SOCKET_BUF_SIZE];
172 long bytesToRead;
173
174 /* Drain socket */
175 /* Find out how many bytes available for read */
176 ioctlsocket (scinFd, FIONREAD, &bytesToRead);
177 if (bytesToRead == 0) {
178 return;
179 }
180 /* Prepare corresponding buffer if needed, and then read */
181 if (bytesToRead > WAKEUP_SOCKET_BUF_SIZE) {
182 char* buf = (char*)malloc(bytesToRead);
183 if (buf == NULL) {
184 JNU_ThrowOutOfMemoryError(env, NULL);
185 return;
186 }
187 recv(scinFd, buf, bytesToRead, 0);
188 free(buf);
189 } else {
190 recv(scinFd, bytes, WAKEUP_SOCKET_BUF_SIZE, 0);
191 }
192 }
193
194 JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_WindowsSelectorImpl_discardUrgentData(JNIEnv * env,jobject this,jint s)195 Java_sun_nio_ch_WindowsSelectorImpl_discardUrgentData(JNIEnv* env, jobject this,
196 jint s)
197 {
198 char data[8];
199 jboolean discarded = JNI_FALSE;
200 int n;
201 do {
202 n = recv(s, (char*)&data, sizeof(data), MSG_OOB);
203 if (n > 0) {
204 discarded = JNI_TRUE;
205 }
206 } while (n > 0);
207 return discarded;
208 }
209