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 flags = 0; 161 162 ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED)); 163 res = WSARecv(s, 164 lpWsaBuf, 165 (DWORD)count, 166 NULL, 167 &flags, 168 lpOverlapped, 169 NULL); 170 171 if (res == SOCKET_ERROR) { 172 int error = WSAGetLastError(); 173 if (error == WSA_IO_PENDING) { 174 return IOS_UNAVAILABLE; 175 } 176 if (error == WSAESHUTDOWN) { 177 return IOS_EOF; // input shutdown 178 } 179 JNU_ThrowIOExceptionWithLastError(env, "WSARecv failed"); 180 return IOS_THROWN; 181 } 182 return IOS_UNAVAILABLE; 183 } 184 185 JNIEXPORT jint JNICALL 186 Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_write0(JNIEnv* env, jclass this, 187 jlong socket, jint count, jlong address, jlong ov) 188 { 189 SOCKET s = (SOCKET) jlong_to_ptr(socket); 190 WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address); 191 OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov); 192 BOOL res; 193 194 ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED)); 195 res = WSASend(s, 196 lpWsaBuf, 197 (DWORD)count, 198 NULL, 199 0, 200 lpOverlapped, 201 NULL); 202 203 if (res == SOCKET_ERROR) { 204 int error = WSAGetLastError(); 205 if (error == WSA_IO_PENDING) { 206 return IOS_UNAVAILABLE; 207 } 208 if (error == WSAESHUTDOWN) { 209 return IOS_EOF; // output shutdown 210 } 211 JNU_ThrowIOExceptionWithLastError(env, "WSASend failed"); 212 return IOS_THROWN; 213 } 214 return IOS_UNAVAILABLE; 215 }