1 /*
2  * Copyright (c) 2008, 2011, 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 <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 (PASCAL *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
Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_initIDs(JNIEnv * env,jclass this)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
Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_connect0(JNIEnv * env,jclass this,jlong socket,jboolean preferIPv6,jobject iao,jint port,jlong ov)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
Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_updateConnectContext(JNIEnv * env,jclass this,jlong socket)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
Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_shutdown0(JNIEnv * env,jclass cl,jlong socket,jint how)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
Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_closesocket0(JNIEnv * env,jclass this,jlong socket)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
Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_read0(JNIEnv * env,jclass this,jlong socket,jint count,jlong address,jlong ov)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
Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_write0(JNIEnv * env,jclass this,jlong socket,jint count,jlong address,jlong ov)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 }
216