Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/windows/native/libnet/PlainSocketImpl.c
41119 views
1
/*
2
* Copyright (c) 2007, 2018, 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
#include "net_util.h"
26
27
#include "java_net_PlainSocketImpl.h"
28
#include "java_net_SocketOptions.h"
29
30
#define SET_BLOCKING 0
31
#define SET_NONBLOCKING 1
32
33
static jclass isa_class; /* java.net.InetSocketAddress */
34
static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
35
36
/*
37
* Class: java_net_PlainSocketImpl
38
* Method: initIDs
39
* Signature: ()V
40
*/
41
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_initIDs
42
(JNIEnv *env, jclass clazz) {
43
44
jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
45
CHECK_NULL(cls);
46
isa_class = (*env)->NewGlobalRef(env, cls);
47
CHECK_NULL(isa_class);
48
isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
49
"(Ljava/net/InetAddress;I)V");
50
CHECK_NULL(isa_ctorID);
51
initInetAddressIDs(env);
52
53
// implement read timeout with select.
54
isRcvTimeoutSupported = JNI_FALSE;
55
}
56
57
/*
58
* Class: java_net_PlainSocketImpl
59
* Method: socket0
60
* Signature: (ZZ)I
61
*/
62
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_socket0
63
(JNIEnv *env, jclass clazz, jboolean stream) {
64
int fd, rv, opt = 0;
65
int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
66
int domain = ipv6_available() ? AF_INET6 : AF_INET;
67
68
fd = NET_Socket(domain, type, 0);
69
70
if (fd == INVALID_SOCKET) {
71
NET_ThrowNew(env, WSAGetLastError(), "create");
72
return -1;
73
}
74
75
if (domain == AF_INET6) {
76
rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt,
77
sizeof(opt));
78
if (rv == SOCKET_ERROR) {
79
NET_ThrowNew(env, WSAGetLastError(), "create");
80
closesocket(fd);
81
return -1;
82
}
83
}
84
85
return fd;
86
}
87
88
/*
89
* Class: java_net_PlainSocketImpl
90
* Method: bind0
91
* Signature: (ILjava/net/InetAddress;I)V
92
*/
93
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_bind0
94
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
95
jboolean exclBind)
96
{
97
SOCKETADDRESS sa;
98
int rv, sa_len = 0;
99
jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
100
101
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
102
&sa_len, v4MappedAddress) != 0) {
103
return;
104
}
105
106
rv = NET_WinBind(fd, &sa, sa_len, exclBind);
107
108
if (rv == SOCKET_ERROR)
109
NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
110
}
111
112
/*
113
* Class: java_net_PlainSocketImpl
114
* Method: connect0
115
* Signature: (ILjava/net/InetAddress;I)I
116
*/
117
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_connect0
118
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
119
SOCKETADDRESS sa;
120
int rv, sa_len = 0;
121
jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
122
123
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
124
&sa_len, v4MappedAddress) != 0) {
125
return -1;
126
}
127
128
rv = connect(fd, &sa.sa, sa_len);
129
if (rv == SOCKET_ERROR) {
130
int err = WSAGetLastError();
131
if (err == WSAEWOULDBLOCK) {
132
return java_net_PlainSocketImpl_WOULDBLOCK;
133
} else if (err == WSAEADDRNOTAVAIL) {
134
JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
135
"connect: Address is invalid on local machine,"
136
" or port is not valid on remote machine");
137
} else {
138
NET_ThrowNew(env, err, "connect");
139
}
140
// return value not important.
141
}
142
return rv;
143
}
144
145
/*
146
* Class: java_net_PlainSocketImpl
147
* Method: waitForConnect
148
* Signature: (II)V
149
*/
150
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_waitForConnect
151
(JNIEnv *env, jclass clazz, jint fd, jint timeout) {
152
int rv, retry;
153
int optlen = sizeof(rv);
154
fd_set wr, ex;
155
struct timeval t;
156
157
FD_ZERO(&wr);
158
FD_ZERO(&ex);
159
FD_SET(fd, &wr);
160
FD_SET(fd, &ex);
161
t.tv_sec = timeout / 1000;
162
t.tv_usec = (timeout % 1000) * 1000;
163
164
/*
165
* Wait for timeout, connection established or
166
* connection failed.
167
*/
168
rv = select(fd+1, 0, &wr, &ex, &t);
169
170
/*
171
* Timeout before connection is established/failed so
172
* we throw exception and shutdown input/output to prevent
173
* socket from being used.
174
* The socket should be closed immediately by the caller.
175
*/
176
if (rv == 0) {
177
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
178
"connect timed out");
179
shutdown(fd, SD_BOTH);
180
return;
181
}
182
183
/*
184
* Socket is writable or error occurred. On some Windows editions
185
* the socket will appear writable when the connect fails so we
186
* check for error rather than writable.
187
*/
188
if (!FD_ISSET(fd, &ex)) {
189
return; /* connection established */
190
}
191
192
/*
193
* Connection failed. The logic here is designed to work around
194
* bug on Windows NT whereby using getsockopt to obtain the
195
* last error (SO_ERROR) indicates there is no error. The workaround
196
* on NT is to allow winsock to be scheduled and this is done by
197
* yielding and retrying. As yielding is problematic in heavy
198
* load conditions we attempt up to 3 times to get the error reason.
199
*/
200
for (retry = 0; retry < 3; retry++) {
201
NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
202
(char*)&rv, &optlen);
203
if (rv) {
204
break;
205
}
206
Sleep(0);
207
}
208
209
if (rv == 0) {
210
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
211
"Unable to establish connection");
212
} else if (!ipv6_available() && rv == WSAEADDRNOTAVAIL) {
213
JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
214
"connect: Address is invalid on local machine,"
215
" or port is not valid on remote machine");
216
} else {
217
NET_ThrowNew(env, rv, "connect");
218
}
219
}
220
221
/*
222
* Class: java_net_PlainSocketImpl
223
* Method: localPort0
224
* Signature: (I)I
225
*/
226
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_localPort0
227
(JNIEnv *env, jclass clazz, jint fd) {
228
SOCKETADDRESS sa;
229
int len = sizeof(sa);
230
231
if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
232
if (WSAGetLastError() == WSAENOTSOCK) {
233
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
234
"Socket closed");
235
} else {
236
NET_ThrowNew(env, WSAGetLastError(), "getsockname failed");
237
}
238
return -1;
239
}
240
return (int) ntohs((u_short)GET_PORT(&sa));
241
}
242
243
/*
244
* Class: java_net_PlainSocketImpl
245
* Method: localAddress
246
* Signature: (ILjava/net/InetAddressContainer;)V
247
*/
248
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_localAddress
249
(JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) {
250
int port;
251
SOCKETADDRESS sa;
252
int len = sizeof(sa);
253
jobject iaObj;
254
jclass iaContainerClass;
255
jfieldID iaFieldID;
256
257
if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
258
NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
259
return;
260
}
261
iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
262
CHECK_NULL(iaObj);
263
264
iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);
265
iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;");
266
CHECK_NULL(iaFieldID);
267
(*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
268
}
269
270
/*
271
* Class: java_net_PlainSocketImpl
272
* Method: listen0
273
* Signature: (II)V
274
*/
275
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_listen0
276
(JNIEnv *env, jclass clazz, jint fd, jint backlog) {
277
if (listen(fd, backlog) == SOCKET_ERROR) {
278
NET_ThrowNew(env, WSAGetLastError(), "listen failed");
279
}
280
}
281
282
/*
283
* Class: java_net_PlainSocketImpl
284
* Method: accept0
285
* Signature: (I[Ljava/net/InetSocketAddress;)I
286
*/
287
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_accept0
288
(JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
289
int newfd, port = 0;
290
jobject isa;
291
jobject ia;
292
SOCKETADDRESS sa;
293
int len = sizeof(sa);
294
295
memset((char *)&sa, 0, len);
296
newfd = accept(fd, &sa.sa, &len);
297
298
if (newfd == INVALID_SOCKET) {
299
NET_ThrowNew(env, WSAGetLastError(), "accept failed");
300
return -1;
301
}
302
303
SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
304
305
ia = NET_SockaddrToInetAddress(env, &sa, &port);
306
if (ia == NULL){
307
closesocket(newfd);
308
return -1;
309
}
310
isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
311
if (isa == NULL) {
312
closesocket(newfd);
313
return -1;
314
}
315
(*env)->SetObjectArrayElement(env, isaa, 0, isa);
316
317
return newfd;
318
}
319
320
/*
321
* Class: java_net_PlainSocketImpl
322
* Method: waitForNewConnection
323
* Signature: (II)V
324
*/
325
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_waitForNewConnection
326
(JNIEnv *env, jclass clazz, jint fd, jint timeout) {
327
int rv;
328
329
rv = NET_Timeout(fd, timeout);
330
if (rv == 0) {
331
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
332
"Accept timed out");
333
} else if (rv == -1) {
334
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
335
} else if (rv == -2) {
336
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
337
"operation interrupted");
338
}
339
}
340
341
/*
342
* Class: java_net_PlainSocketImpl
343
* Method: available0
344
* Signature: (I)I
345
*/
346
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_available0
347
(JNIEnv *env, jclass clazz, jint fd) {
348
jint available = -1;
349
350
if ((ioctlsocket(fd, FIONREAD, &available)) == SOCKET_ERROR) {
351
NET_ThrowNew(env, WSAGetLastError(), "socket available");
352
}
353
354
return available;
355
}
356
357
/*
358
* Class: java_net_PlainSocketImpl
359
* Method: close0
360
* Signature: (I)V
361
*/
362
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_close0
363
(JNIEnv *env, jclass clazz, jint fd) {
364
NET_SocketClose(fd);
365
}
366
367
/*
368
* Class: java_net_PlainSocketImpl
369
* Method: shutdown0
370
* Signature: (II)V
371
*/
372
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_shutdown0
373
(JNIEnv *env, jclass clazz, jint fd, jint howto) {
374
shutdown(fd, howto);
375
}
376
377
/*
378
* Class: java_net_PlainSocketImpl
379
* Method: setIntOption
380
* Signature: (III)V
381
*/
382
JNIEXPORT void JNICALL
383
Java_java_net_PlainSocketImpl_setIntOption
384
(JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value)
385
{
386
int level = 0, opt = 0;
387
struct linger linger = {0, 0};
388
char *parg;
389
int arglen;
390
391
if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
392
JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
393
return;
394
}
395
396
if (opt == java_net_SocketOptions_SO_LINGER) {
397
parg = (char *)&linger;
398
arglen = sizeof(linger);
399
if (value >= 0) {
400
linger.l_onoff = 1;
401
linger.l_linger = (unsigned short)value;
402
} else {
403
linger.l_onoff = 0;
404
linger.l_linger = 0;
405
}
406
} else {
407
parg = (char *)&value;
408
arglen = sizeof(value);
409
}
410
411
if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {
412
NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
413
}
414
}
415
416
/*
417
* Class: java_net_PlainSocketImpl
418
* Method: setSoTimeout0
419
* Signature: (II)V
420
*/
421
JNIEXPORT void JNICALL
422
Java_java_net_PlainSocketImpl_setSoTimeout0
423
(JNIEnv *env, jclass clazz, jint fd, jint timeout)
424
{
425
/*
426
* SO_TIMEOUT is the socket option used to specify the timeout
427
* for ServerSocket.accept and Socket.getInputStream().read.
428
* It does not typically map to a native level socket option.
429
* For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
430
* socket option to specify a receive timeout on the socket. This
431
* receive timeout is applicable to Socket only and the socket
432
* option should not be set on ServerSocket.
433
*/
434
435
/*
436
* SO_RCVTIMEO is only supported on Microsoft's implementation
437
* of Windows Sockets so if WSAENOPROTOOPT returned then
438
* reset flag and timeout will be implemented using
439
* select() -- see SocketInputStream.socketRead.
440
*/
441
if (isRcvTimeoutSupported) {
442
/*
443
* Disable SO_RCVTIMEO if timeout is <= 5 second.
444
*/
445
if (timeout <= 5000) {
446
timeout = 0;
447
}
448
449
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
450
sizeof(timeout)) < 0) {
451
int err = WSAGetLastError();
452
if (err == WSAENOPROTOOPT) {
453
isRcvTimeoutSupported = JNI_FALSE;
454
} else {
455
NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO");
456
}
457
}
458
}
459
}
460
461
/*
462
* Class: java_net_PlainSocketImpl
463
* Method: getIntOption
464
* Signature: (II)I
465
*/
466
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_getIntOption
467
(JNIEnv *env, jclass clazz, jint fd, jint cmd)
468
{
469
int level = 0, opt = 0;
470
int result = 0;
471
struct linger linger = {0, 0};
472
char *arg;
473
int arglen;
474
475
if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
476
JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
477
return -1;
478
}
479
480
if (opt == java_net_SocketOptions_SO_LINGER) {
481
arg = (char *)&linger;
482
arglen = sizeof(linger);
483
} else {
484
arg = (char *)&result;
485
arglen = sizeof(result);
486
}
487
488
if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) {
489
NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
490
return -1;
491
}
492
493
if (opt == java_net_SocketOptions_SO_LINGER)
494
return linger.l_onoff ? linger.l_linger : -1;
495
else
496
return result;
497
}
498
499
/*
500
* Class: java_net_PlainSocketImpl
501
* Method: sendOOB
502
* Signature: (II)V
503
*/
504
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_sendOOB
505
(JNIEnv *env, jclass clazz, jint fd, jint data) {
506
jint n;
507
unsigned char d = (unsigned char) data & 0xff;
508
509
n = send(fd, (char *)&data, 1, MSG_OOB);
510
if (n == SOCKET_ERROR) {
511
NET_ThrowNew(env, WSAGetLastError(), "send");
512
}
513
}
514
515
/*
516
* Class: java_net_PlainSocketImpl
517
* Method: configureBlocking
518
* Signature: (IZ)V
519
*/
520
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_configureBlocking
521
(JNIEnv *env, jclass clazz, jint fd, jboolean blocking) {
522
u_long arg;
523
int result;
524
525
if (blocking == JNI_TRUE) {
526
arg = SET_BLOCKING; // 0
527
} else {
528
arg = SET_NONBLOCKING; // 1
529
}
530
531
result = ioctlsocket(fd, FIONBIO, &arg);
532
if (result == SOCKET_ERROR) {
533
NET_ThrowNew(env, WSAGetLastError(), "configureBlocking");
534
}
535
}
536
537