1 /*
   2  * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 #include <windows.h>
  27 #include <winsock2.h>
  28 #include <stddef.h>
  29 
  30 #include "jni.h"
  31 #include "jni_util.h"
  32 #include "jlong.h"
  33 #include "nio.h"
  34 #include "nio_util.h"
  35 #include "net_util.h"
  36 
  37 #include "sun_nio_ch_WindowsAsynchronousSocketChannelImpl.h"
  38 
  39 #ifndef WSAID_CONNECTEX
  40 #define WSAID_CONNECTEX {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}
  41 #endif
  42 
  43 #ifndef SO_UPDATE_CONNECT_CONTEXT
  44 #define SO_UPDATE_CONNECT_CONTEXT 0x7010
  45 #endif
  46 
  47 typedef BOOL (*ConnectEx_t)
  48 (
  49     SOCKET s,
  50     const struct sockaddr* name,
  51     int namelen,
  52     PVOID lpSendBuffer,
  53     DWORD dwSendDataLength,
  54     LPDWORD lpdwBytesSent,
  55     LPOVERLAPPED lpOverlapped
  56 );
  57 
  58 static ConnectEx_t ConnectEx_func;
  59 
  60 
  61 JNIEXPORT void JNICALL
  62 Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_initIDs(JNIEnv* env, jclass this) {
  63     GUID GuidConnectEx = WSAID_CONNECTEX;
  64     SOCKET s;
  65     int rv;
  66     DWORD dwBytes;
  67 
  68     s = socket(AF_INET, SOCK_STREAM, 0);
  69     if (s == INVALID_SOCKET) {
  70         JNU_ThrowIOExceptionWithLastError(env, "socket failed");
  71         return;
  72     }
  73     rv = WSAIoctl(s,
  74                   SIO_GET_EXTENSION_FUNCTION_POINTER,
  75                   (LPVOID)&GuidConnectEx,
  76                   sizeof(GuidConnectEx),
  77                   &ConnectEx_func,
  78                   sizeof(ConnectEx_func),
  79                   &dwBytes,
  80                   NULL,
  81                   NULL);
  82     if (rv != 0)
  83         JNU_ThrowIOExceptionWithLastError(env, "WSAIoctl failed");
  84     closesocket(s);
  85 }
  86 
  87 JNIEXPORT jint JNICALL
  88 Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_connect0(JNIEnv* env, jclass this,
  89     jlong socket, jboolean preferIPv6, jobject iao, jint port, jlong ov)
  90 {
  91     SOCKET s = (SOCKET) jlong_to_ptr(socket);
  92     OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov);
  93 
  94     SOCKETADDRESS sa;
  95     int sa_len;
  96     BOOL res;
  97 
  98     if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
  99         return IOS_THROWN;
 100     }
 101 
 102     ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED));
 103 
 104     res = (*ConnectEx_func)(s,
 105                             (struct sockaddr *)&sa,
 106                             sa_len,
 107                             NULL,
 108                             0,
 109                             NULL,
 110                             lpOverlapped);
 111     if (res == 0) {
 112         int error = GetLastError();
 113         if (error == ERROR_IO_PENDING) {
 114             return IOS_UNAVAILABLE;
 115         }
 116         JNU_ThrowIOExceptionWithLastError(env, "ConnectEx failed");
 117         return IOS_THROWN;
 118     }
 119     return 0;
 120 }
 121 
 122 JNIEXPORT void JNICALL
 123 Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_updateConnectContext(JNIEnv* env, jclass this,
 124     jlong socket)
 125 {
 126     SOCKET s = (SOCKET)jlong_to_ptr(socket);
 127     setsockopt(s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
 128 }
 129 
 130 
 131 JNIEXPORT void JNICALL
 132 Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_shutdown0(JNIEnv *env, jclass cl,
 133     jlong socket, jint how)
 134 {
 135     SOCKET s =(SOCKET) jlong_to_ptr(socket);
 136     if (shutdown(s, how) == SOCKET_ERROR) {
 137         JNU_ThrowIOExceptionWithLastError(env, "shutdown failed");
 138     }
 139 }
 140 
 141 
 142 JNIEXPORT void JNICALL
 143 Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_closesocket0(JNIEnv* env, jclass this,
 144     jlong socket)
 145 {
 146     SOCKET s = (SOCKET)jlong_to_ptr(socket);
 147     if (closesocket(s) == SOCKET_ERROR)
 148         JNU_ThrowIOExceptionWithLastError(env, "closesocket failed");
 149 }
 150 
 151 
 152 JNIEXPORT jint JNICALL
 153 Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_read0(JNIEnv* env, jclass this,
 154     jlong socket, jint count, jlong address, jlong ov)
 155 {
 156     SOCKET s = (SOCKET) jlong_to_ptr(socket);
 157     WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address);
 158     OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov);
 159     BOOL res;
 160     DWORD nread = 0;
 161     DWORD flags = 0;
 162 
 163     ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED));
 164     res = WSARecv(s,
 165                   lpWsaBuf,
 166                   (DWORD)count,
 167                   &nread,
 168                   &flags,
 169                   lpOverlapped,
 170                   NULL);
 171 
 172     if (res == SOCKET_ERROR) {
 173         int error = WSAGetLastError();
 174         if (error == WSA_IO_PENDING) {
 175             return IOS_UNAVAILABLE;
 176         }
 177         if (error == WSAESHUTDOWN) {
 178             return 0;       // input shutdown
 179         }
 180         JNU_ThrowIOExceptionWithLastError(env, "WSARecv failed");
 181         return IOS_THROWN;
 182     }
 183     if (nread == 0) {
 184         // Handle graceful close or bytes not yet available cases
 185         // via completion port notification.
 186         return IOS_UNAVAILABLE;
 187     }
 188     return (jint)nread;
 189 }
 190 
 191 JNIEXPORT jint JNICALL
 192 Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_write0(JNIEnv* env, jclass this,
 193     jlong socket, jint count, jlong address, jlong ov)
 194 {
 195     SOCKET s = (SOCKET) jlong_to_ptr(socket);
 196     WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address);
 197     OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov);
 198     BOOL res;
 199     DWORD nwritten;
 200 
 201     ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED));
 202     res = WSASend(s,
 203                   lpWsaBuf,
 204                   (DWORD)count,
 205                   &nwritten,
 206                   0,
 207                   lpOverlapped,
 208                   NULL);
 209 
 210     if (res == SOCKET_ERROR) {
 211         int error = WSAGetLastError();
 212         if (error == WSA_IO_PENDING) {
 213             return IOS_UNAVAILABLE;
 214         }
 215         if (error == WSAESHUTDOWN) {
 216             return IOS_EOF;     // output shutdown
 217         }
 218         JNU_ThrowIOExceptionWithLastError(env, "WSASend failed");
 219         return IOS_THROWN;
 220     }
 221     return (jint)nwritten;
 222 }