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