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