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 }