1 /*
2 * Copyright (c) 2000, 2019, 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_SocketDispatcher.h"
34 #include "nio.h"
35 #include "nio_util.h"
36
37
38 /**************************************************************
39 * SocketDispatcher.c
40 */
41
42 JNIEXPORT jint JNICALL
Java_sun_nio_ch_SocketDispatcher_read0(JNIEnv * env,jclass clazz,jobject fdo,jlong address,jint len)43 Java_sun_nio_ch_SocketDispatcher_read0(JNIEnv *env, jclass clazz, jobject fdo,
44 jlong address, jint len)
45 {
46 /* set up */
47 int i = 0;
48 DWORD read = 0;
49 DWORD flags = 0;
50 jint fd = fdval(env, fdo);
51 WSABUF buf;
52
53 /* limit size */
54 if (len > MAX_BUFFER_SIZE)
55 len = MAX_BUFFER_SIZE;
56
57 /* destination buffer and size */
58 buf.buf = (char *)address;
59 buf.len = (u_long)len;
60
61 /* read into the buffers */
62 i = WSARecv((SOCKET)fd, /* Socket */
63 &buf, /* pointers to the buffers */
64 (DWORD)1, /* number of buffers to process */
65 &read, /* receives number of bytes read */
66 &flags, /* no flags */
67 0, /* no overlapped sockets */
68 0); /* no completion routine */
69
70 if (i == SOCKET_ERROR) {
71 int theErr = (jint)WSAGetLastError();
72 if (theErr == WSAEWOULDBLOCK) {
73 return IOS_UNAVAILABLE;
74 }
75 if (theErr == WSAECONNRESET) {
76 JNU_ThrowByName(env, "sun/net/ConnectionResetException", "Connection reset");
77 } else {
78 JNU_ThrowIOExceptionWithLastError(env, "Read failed");
79 }
80 return IOS_THROWN;
81 }
82
83 return convertReturnVal(env, (jint)read, JNI_TRUE);
84 }
85
86 JNIEXPORT jlong JNICALL
Java_sun_nio_ch_SocketDispatcher_readv0(JNIEnv * env,jclass clazz,jobject fdo,jlong address,jint len)87 Java_sun_nio_ch_SocketDispatcher_readv0(JNIEnv *env, jclass clazz, jobject fdo,
88 jlong address, jint len)
89 {
90 /* set up */
91 int i = 0;
92 DWORD read = 0;
93 DWORD flags = 0;
94 jint fd = fdval(env, fdo);
95 struct iovec *iovp = (struct iovec *)address;
96 WSABUF *bufs = malloc(len * sizeof(WSABUF));
97 jint rem = MAX_BUFFER_SIZE;
98
99 if (bufs == 0) {
100 JNU_ThrowOutOfMemoryError(env, 0);
101 return IOS_THROWN;
102 }
103
104 /* copy iovec into WSABUF */
105 for(i=0; i<len; i++) {
106 jint iov_len = iovp[i].iov_len;
107 if (iov_len > rem)
108 iov_len = rem;
109 bufs[i].buf = (char *)iovp[i].iov_base;
110 bufs[i].len = (u_long)iov_len;
111 rem -= iov_len;
112 if (rem == 0) {
113 len = i+1;
114 break;
115 }
116 }
117
118 /* read into the buffers */
119 i = WSARecv((SOCKET)fd, /* Socket */
120 bufs, /* pointers to the buffers */
121 (DWORD)len, /* number of buffers to process */
122 &read, /* receives number of bytes read */
123 &flags, /* no flags */
124 0, /* no overlapped sockets */
125 0); /* no completion routine */
126
127 /* clean up */
128 free(bufs);
129
130 if (i != 0) {
131 int theErr = (jint)WSAGetLastError();
132 if (theErr == WSAEWOULDBLOCK) {
133 return IOS_UNAVAILABLE;
134 }
135 if (theErr == WSAECONNRESET) {
136 JNU_ThrowByName(env, "sun/net/ConnectionResetException", "Connection reset");
137 } else {
138 JNU_ThrowIOExceptionWithLastError(env, "Vector read failed");
139 }
140 return IOS_THROWN;
141 }
142
143 return convertLongReturnVal(env, (jlong)read, JNI_TRUE);
144 }
145
146 JNIEXPORT jint JNICALL
Java_sun_nio_ch_SocketDispatcher_write0(JNIEnv * env,jclass clazz,jobject fdo,jlong address,jint total)147 Java_sun_nio_ch_SocketDispatcher_write0(JNIEnv *env, jclass clazz, jobject fdo,
148 jlong address, jint total)
149 {
150 /* set up */
151 int i = 0;
152 DWORD written = 0;
153 jint count = 0;
154 jint fd = fdval(env, fdo);
155 WSABUF buf;
156
157 do {
158 /* limit size */
159 jint len = total - count;
160 if (len > MAX_BUFFER_SIZE)
161 len = MAX_BUFFER_SIZE;
162
163 /* copy iovec into WSABUF */
164 buf.buf = (char *)address;
165 buf.len = (u_long)len;
166
167 /* write from the buffer */
168 i = WSASend((SOCKET)fd, /* Socket */
169 &buf, /* pointers to the buffers */
170 (DWORD)1, /* number of buffers to process */
171 &written, /* receives number of bytes written */
172 0, /* no flags */
173 0, /* no overlapped sockets */
174 0); /* no completion routine */
175
176 if (i == SOCKET_ERROR) {
177 if (count > 0) {
178 /* can't throw exception when some bytes have been written */
179 break;
180 } else {
181 int theErr = (jint)WSAGetLastError();
182 if (theErr == WSAEWOULDBLOCK) {
183 return IOS_UNAVAILABLE;
184 }
185 if (theErr == WSAECONNRESET) {
186 JNU_ThrowIOException(env, "Connection reset by peer");
187 } else {
188 JNU_ThrowIOExceptionWithLastError(env, "Write failed");
189 }
190 return IOS_THROWN;
191 }
192 }
193
194 count += (jint)written;
195 address += written;
196
197 } while ((count < total) && (written == MAX_BUFFER_SIZE));
198
199 return count;
200 }
201
202 JNIEXPORT jlong JNICALL
Java_sun_nio_ch_SocketDispatcher_writev0(JNIEnv * env,jclass clazz,jobject fdo,jlong address,jint len)203 Java_sun_nio_ch_SocketDispatcher_writev0(JNIEnv *env, jclass clazz,
204 jobject fdo, jlong address, jint len)
205 {
206 /* set up */
207 int next_index, next_offset, ret=0;
208 DWORD written = 0;
209 jint fd = fdval(env, fdo);
210 struct iovec *iovp = (struct iovec *)address;
211 WSABUF *bufs = malloc(len * sizeof(WSABUF));
212 jlong count = 0;
213
214 if (bufs == 0) {
215 JNU_ThrowOutOfMemoryError(env, 0);
216 return IOS_THROWN;
217 }
218
219 // next buffer and offset to consume
220 next_index = 0;
221 next_offset = 0;
222
223 while (next_index < len) {
224 DWORD buf_count = 0;
225
226 /* Prepare the WSABUF array to a maximum total size of MAX_BUFFER_SIZE */
227 jint rem = MAX_BUFFER_SIZE;
228 while (next_index < len && rem > 0) {
229 jint iov_len = iovp[next_index].iov_len - next_offset;
230 char* ptr = (char *)iovp[next_index].iov_base;
231 ptr += next_offset;
232 if (iov_len > rem) {
233 iov_len = rem;
234 next_offset += rem;
235 } else {
236 next_index ++;
237 next_offset = 0;
238 }
239
240 bufs[buf_count].buf = ptr;
241 bufs[buf_count].len = (u_long)iov_len;
242 buf_count++;
243
244 rem -= iov_len;
245 }
246
247 /* write the buffers */
248 ret = WSASend((SOCKET)fd, /* Socket */
249 bufs, /* pointers to the buffers */
250 buf_count, /* number of buffers to process */
251 &written, /* receives number of bytes written */
252 0, /* no flags */
253 0, /* no overlapped sockets */
254 0); /* no completion routine */
255
256 if (ret == SOCKET_ERROR) {
257 break;
258 }
259
260 count += written;
261 }
262
263 /* clean up */
264 free(bufs);
265
266 if (ret == SOCKET_ERROR && count == 0) {
267 int theErr = (jint)WSAGetLastError();
268 if (theErr == WSAEWOULDBLOCK) {
269 return IOS_UNAVAILABLE;
270 }
271 if (theErr == WSAECONNRESET) {
272 JNU_ThrowIOException(env, "Connection reset by peer");
273 } else {
274 JNU_ThrowIOExceptionWithLastError(env, "Vector write failed");
275 }
276 return IOS_THROWN;
277 }
278
279 return convertLongReturnVal(env, count, JNI_FALSE);
280 }
281
282 JNIEXPORT void JNICALL
Java_sun_nio_ch_SocketDispatcher_close0(JNIEnv * env,jclass clazz,jint fd)283 Java_sun_nio_ch_SocketDispatcher_close0(JNIEnv *env, jclass clazz, jint fd)
284 {
285 if (closesocket(fd) == SOCKET_ERROR) {
286 JNU_ThrowIOExceptionWithLastError(env, "Socket close failed");
287 }
288 }
289