1/*
2 * Copyright (c) 2008, 2009, 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
29#include "jni.h"
30#include "jni_util.h"
31#include "jlong.h"
32#include "nio.h"
33#include "nio_util.h"
34#include "net_util.h"
35
36#include "sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl.h"
37
38
39#ifndef WSAID_ACCEPTEX
40#define WSAID_ACCEPTEX {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
41#endif
42
43#ifndef SO_UPDATE_ACCEPT_CONTEXT
44#define SO_UPDATE_ACCEPT_CONTEXT 0x700B
45#endif
46
47
48typedef BOOL (*AcceptEx_t)
49(
50    SOCKET sListenSocket,
51    SOCKET sAcceptSocket,
52    PVOID lpOutputBuffer,
53    DWORD dwReceiveDataLength,
54    DWORD dwLocalAddressLength,
55    DWORD dwRemoteAddressLength,
56    LPDWORD lpdwBytesReceived,
57    LPOVERLAPPED lpOverlapped
58);
59
60
61static AcceptEx_t AcceptEx_func;
62
63
64JNIEXPORT void JNICALL
65Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_initIDs(JNIEnv* env, jclass this) {
66    GUID GuidAcceptEx = WSAID_ACCEPTEX;
67    SOCKET s;
68    int rv;
69    DWORD dwBytes;
70
71    s = socket(AF_INET, SOCK_STREAM, 0);
72    if (s == INVALID_SOCKET) {
73        JNU_ThrowIOExceptionWithLastError(env, "socket failed");
74        return;
75    }
76    rv = WSAIoctl(s,
77                  SIO_GET_EXTENSION_FUNCTION_POINTER,
78                  (LPVOID)&GuidAcceptEx,
79                  sizeof(GuidAcceptEx),
80                  &AcceptEx_func,
81                  sizeof(AcceptEx_func),
82                  &dwBytes,
83                  NULL,
84                  NULL);
85    if (rv != 0)
86        JNU_ThrowIOExceptionWithLastError(env, "WSAIoctl failed");
87    closesocket(s);
88}
89
90JNIEXPORT jint JNICALL
91Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_accept0(JNIEnv* env, jclass this,
92    jlong listenSocket, jlong acceptSocket, jlong ov, jlong buf)
93{
94    BOOL res;
95    SOCKET s1 = (SOCKET)jlong_to_ptr(listenSocket);
96    SOCKET s2 = (SOCKET)jlong_to_ptr(acceptSocket);
97    PVOID outputBuffer = (PVOID)jlong_to_ptr(buf);
98
99    DWORD nread = 0;
100    OVERLAPPED* lpOverlapped = (OVERLAPPED*)jlong_to_ptr(ov);
101    ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED));
102
103    res = (*AcceptEx_func)(s1,
104                           s2,
105                           outputBuffer,
106                           0,
107                           sizeof(SOCKETADDRESS)+16,
108                           sizeof(SOCKETADDRESS)+16,
109                           &nread,
110                           lpOverlapped);
111    if (res == 0) {
112        int error = WSAGetLastError();
113        if (error == ERROR_IO_PENDING) {
114            return IOS_UNAVAILABLE;
115        }
116        JNU_ThrowIOExceptionWithLastError(env, "AcceptEx failed");
117        return IOS_THROWN;
118    }
119
120    return 0;
121}
122
123JNIEXPORT void JNICALL
124Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_updateAcceptContext(JNIEnv* env, jclass this,
125    jlong listenSocket, jlong acceptSocket)
126{
127    SOCKET s1 = (SOCKET)jlong_to_ptr(listenSocket);
128    SOCKET s2 = (SOCKET)jlong_to_ptr(acceptSocket);
129
130    setsockopt(s2, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&s1, sizeof(s1));
131}
132
133
134JNIEXPORT void JNICALL
135Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_closesocket0(JNIEnv* env, jclass this,
136    jlong socket)
137{
138    SOCKET s = (SOCKET)jlong_to_ptr(socket);
139
140    if (closesocket(s) == SOCKET_ERROR)
141        JNU_ThrowIOExceptionWithLastError(env, "closesocket failed");
142}
143