jdk

Форк
0
/
UnixDomainSockets.c 
257 строк · 7.9 Кб
1
/*
2
 * Copyright (c) 2020, 2023, 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 "jvm.h"
32
#include "jlong.h"
33
#include "nio.h"
34
#include "nio_util.h"
35
#include "net_util.h"
36

37
#include "java_net_InetAddress.h"
38
#include "sun_nio_ch_Net.h"
39
#include "sun_nio_ch_PollArrayWrapper.h"
40

41
/* The winsock provider ID of the Microsoft AF_UNIX implementation */
42
static GUID MS_PROVIDER_ID  = {0xA00943D9,0x9C2E,0x4633,{0x9B,0x59,0,0x57,0xA3,0x16,0x09,0x94}};
43

44
jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len)
45
{
46
    if (sa->sun_family == AF_UNIX) {
47
        int namelen = (int)strlen(sa->sun_path);
48
        jbyteArray name = (*env)->NewByteArray(env, namelen);
49
        if (name != NULL) {
50
            (*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path);
51
            if ((*env)->ExceptionOccurred(env)) {
52
                return NULL;
53
            }
54
        }
55
        return name;
56
    }
57
    return NULL;
58
}
59

60
jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray addr, struct sockaddr_un *sa, int *len)
61
{
62
    memset(sa, 0, sizeof(struct sockaddr_un));
63
    sa->sun_family = AF_UNIX;
64
    if (addr == 0L) {
65
        /* Do explicit bind on Windows */
66
        *len = (int)(offsetof(struct sockaddr_un, sun_path));
67
        return 0;
68
    }
69
    int ret;
70
    jboolean isCopy;
71
    char *pname = (*env)->GetByteArrayElements(env, addr, &isCopy);
72
    if (pname == NULL) {
73
        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path not present");
74
        return -1;
75
    }
76

77
    size_t name_len = (size_t)(*env)->GetArrayLength(env, addr);
78
    if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {
79
        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path too long");
80
        ret = -1;
81
    } else {
82
        strncpy(sa->sun_path, pname, name_len);
83
        *len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len);
84
        ret = 0;
85
    }
86
    (*env)->ReleaseByteArrayElements(env, addr, pname, JNI_ABORT);
87
    return ret;
88
}
89

90
static int cmpGuid(GUID *g1, GUID *g2) {
91
    if (g1->Data1 != g2->Data1)
92
        return JNI_FALSE;
93
    if (g1->Data2 != g2->Data2)
94
        return JNI_FALSE;
95
    if (g1->Data3 != g2->Data3)
96
        return JNI_FALSE;
97
    for (int i=0; i<8; i++) {
98
        if (g1->Data4[i] != g2->Data4[i])
99
            return JNI_FALSE;
100
    }
101
    return JNI_TRUE;
102
}
103

104
static WSAPROTOCOL_INFOW provider;
105

106
JNIEXPORT jboolean JNICALL
107
Java_sun_nio_ch_UnixDomainSockets_init(JNIEnv *env, jclass cl)
108
{
109
    WSAPROTOCOL_INFOW info[5]; // if not large enough, a buffer is malloc'd
110
    LPWSAPROTOCOL_INFOW infoPtr = &info[0];
111
    DWORD len = sizeof(info);
112
    jboolean found = JNI_FALSE;
113

114
    /*
115
     * First locate the Microsoft AF_UNIX Winsock provider
116
     */
117
    int result = WSAEnumProtocolsW(0, infoPtr, &len);
118
    if (result == SOCKET_ERROR) {
119
        if (GetLastError() == WSAENOBUFS) {
120
            infoPtr = (LPWSAPROTOCOL_INFOW)malloc(len);
121
            if (infoPtr == NULL) {
122
                return JNI_FALSE;
123
            }
124
            result = WSAEnumProtocolsW(0, infoPtr, &len);
125
            if (result == SOCKET_ERROR) {
126
                free(infoPtr);
127
                return JNI_FALSE;
128
            }
129
        } else {
130
            return JNI_FALSE;
131
        }
132
    }
133
    for (int i=0; i<result;  i++) {
134
        if (infoPtr[i].iAddressFamily == AF_UNIX) {
135
            GUID g = infoPtr[i].ProviderId;
136
            if (cmpGuid(&g, &MS_PROVIDER_ID)) {
137
                found = JNI_TRUE;
138
                provider = infoPtr[i];
139
                break;
140
            }
141
        }
142
    }
143
    if (infoPtr != &info[0]) {
144
        free(infoPtr);
145
    }
146
    /*
147
     * check we can create a socket
148
     */
149
    if (found) {
150
        SOCKET s = WSASocketW(PF_UNIX, SOCK_STREAM, 0, &provider, 0, WSA_FLAG_OVERLAPPED);
151
        if (s == INVALID_SOCKET) {
152
            return JNI_FALSE;
153
        }
154
        closesocket(s);
155
    }
156
    return found;
157
}
158

159
JNIEXPORT jint JNICALL
160
Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv *env, jclass cl)
161
{
162
    SOCKET s = WSASocketW(PF_UNIX, SOCK_STREAM, 0, &provider, 0, WSA_FLAG_OVERLAPPED);
163
    if (s == INVALID_SOCKET) {
164
        NET_ThrowNew(env, WSAGetLastError(), "WSASocketW");
165
        return IOS_THROWN;
166
    }
167
    SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0);
168
    return (int)s;
169
}
170

171
/**
172
 * Windows does not support auto bind. So, the windows version of unixSocketAddressToSockaddr
173
 * looks out for a null 'uaddr' and handles it specially
174
 */
175
JNIEXPORT void JNICALL
176
Java_sun_nio_ch_UnixDomainSockets_bind0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray addr)
177
{
178
    struct sockaddr_un sa;
179
    int sa_len = 0;
180
    int rv = 0;
181

182
    if (unixSocketAddressToSockaddr(env, addr, &sa, &sa_len) != 0)
183
        return;
184

185
    rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
186
    if (rv == SOCKET_ERROR) {
187
        int err = WSAGetLastError();
188
        NET_ThrowNew(env, err, "bind");
189
    }
190
}
191

192
JNIEXPORT jint JNICALL
193
Java_sun_nio_ch_UnixDomainSockets_connect0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray addr)
194
{
195
    struct sockaddr_un sa;
196
    int sa_len = 0;
197
    int rv;
198

199
    if (unixSocketAddressToSockaddr(env, addr, &sa, &sa_len) != 0) {
200
        return IOS_THROWN;
201
    }
202

203
    rv = connect(fdval(env, fdo), (const struct sockaddr *)&sa, sa_len);
204
    if (rv != 0) {
205
        int err = WSAGetLastError();
206
        if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) {
207
            return IOS_UNAVAILABLE;
208
        }
209
        NET_ThrowNew(env, err, "connect");
210
        return IOS_THROWN;
211
    }
212
    return 1;
213
}
214

215
JNIEXPORT jint JNICALL
216
Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
217
                                          jobjectArray array)
218
{
219
    jint fd = fdval(env, fdo);
220
    jint newfd;
221
    struct sockaddr_un sa;
222
    socklen_t sa_len = sizeof(sa);
223
    jbyteArray address;
224

225
    memset((char *)&sa, 0, sizeof(sa));
226
    newfd = (jint) accept(fd, (struct sockaddr *)&sa, &sa_len);
227
    if (newfd == INVALID_SOCKET) {
228
        int theErr = (jint)WSAGetLastError();
229
        if (theErr == WSAEWOULDBLOCK) {
230
            return IOS_UNAVAILABLE;
231
        }
232
        JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
233
        return IOS_THROWN;
234
    }
235

236
    SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
237
    setfdval(env, newfdo, newfd);
238

239
    address = sockaddrToUnixAddressBytes(env, &sa, sa_len);
240
    CHECK_NULL_RETURN(address, IOS_THROWN);
241
    (*env)->SetObjectArrayElement(env, array, 0, address);
242

243
    return 1;
244
}
245

246
JNIEXPORT jbyteArray JNICALL
247
Java_sun_nio_ch_UnixDomainSockets_localAddress0(JNIEnv *env, jclass clazz, jobject fdo)
248
{
249
    struct sockaddr_un sa;
250
    int sa_len = sizeof(sa);
251

252
    if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) == SOCKET_ERROR) {
253
        JNU_ThrowIOExceptionWithLastError(env, "getsockname");
254
        return NULL;
255
    }
256
    return sockaddrToUnixAddressBytes(env, &sa, sa_len);
257
}
258

259

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.