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