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