Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/net/TwoStacksPlainSocketImpl.c
32287 views
1
/*
2
* Copyright (c) 1997, 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
26
#include <windows.h>
27
#include <winsock2.h>
28
#include <ctype.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <malloc.h>
32
#include <sys/types.h>
33
34
#include "java_net_SocketOptions.h"
35
#include "java_net_TwoStacksPlainSocketImpl.h"
36
#include "java_net_InetAddress.h"
37
#include "java_io_FileDescriptor.h"
38
#include "java_lang_Integer.h"
39
40
#include "jvm.h"
41
#include "net_util.h"
42
#include "jni_util.h"
43
44
/************************************************************************
45
* TwoStacksPlainSocketImpl
46
*/
47
48
static jfieldID IO_fd_fdID;
49
50
jfieldID psi_fdID;
51
jfieldID psi_fd1ID;
52
jfieldID psi_addressID;
53
jfieldID psi_portID;
54
jfieldID psi_localportID;
55
jfieldID psi_timeoutID;
56
jfieldID psi_trafficClassID;
57
jfieldID psi_serverSocketID;
58
jfieldID psi_lastfdID;
59
60
/*
61
* the level of the TCP protocol for setsockopt and getsockopt
62
* we only want to look this up once, from the static initializer
63
* of TwoStacksPlainSocketImpl
64
*/
65
static int tcp_level = -1;
66
67
static int getFD(JNIEnv *env, jobject this) {
68
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
69
70
if (fdObj == NULL) {
71
return -1;
72
}
73
return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
74
}
75
76
static int getFD1(JNIEnv *env, jobject this) {
77
jobject fdObj = (*env)->GetObjectField(env, this, psi_fd1ID);
78
79
if (fdObj == NULL) {
80
return -1;
81
}
82
return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
83
}
84
85
86
/*
87
* The initProto function is called whenever TwoStacksPlainSocketImpl is
88
* loaded, to cache fieldIds for efficiency. This is called everytime
89
* the Java class is loaded.
90
*
91
* Class: java_net_TwoStacksPlainSocketImpl
92
* Method: initProto
93
94
* Signature: ()V
95
*/
96
JNIEXPORT void JNICALL
97
Java_java_net_TwoStacksPlainSocketImpl_initProto(JNIEnv *env, jclass cls) {
98
99
struct protoent *proto = getprotobyname("TCP");
100
tcp_level = (proto == 0 ? IPPROTO_TCP: proto->p_proto);
101
102
psi_fdID = (*env)->GetFieldID(env, cls , "fd", "Ljava/io/FileDescriptor;");
103
CHECK_NULL(psi_fdID);
104
psi_fd1ID =(*env)->GetFieldID(env, cls , "fd1", "Ljava/io/FileDescriptor;");
105
CHECK_NULL(psi_fd1ID);
106
psi_addressID = (*env)->GetFieldID(env, cls, "address",
107
"Ljava/net/InetAddress;");
108
CHECK_NULL(psi_addressID);
109
psi_portID = (*env)->GetFieldID(env, cls, "port", "I");
110
CHECK_NULL(psi_portID);
111
psi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I");
112
CHECK_NULL(psi_lastfdID);
113
psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");
114
CHECK_NULL(psi_localportID);
115
psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
116
CHECK_NULL(psi_timeoutID);
117
psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
118
CHECK_NULL(psi_trafficClassID);
119
psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket",
120
"Ljava/net/ServerSocket;");
121
CHECK_NULL(psi_serverSocketID);
122
IO_fd_fdID = NET_GetFileDescriptorID(env);
123
CHECK_NULL(IO_fd_fdID);
124
}
125
126
/*
127
* Class: java_net_TwoStacksPlainSocketImpl
128
* Method: socketCreate
129
* Signature: (Z)V
130
*/
131
JNIEXPORT void JNICALL
132
Java_java_net_TwoStacksPlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
133
jboolean stream) {
134
jobject fdObj, fd1Obj;
135
int fd, fd1;
136
137
fdObj = (*env)->GetObjectField(env, this, psi_fdID);
138
139
if (IS_NULL(fdObj)) {
140
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
141
"null fd object");
142
return;
143
}
144
fd = socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);
145
if (fd == -1) {
146
NET_ThrowCurrent(env, "create");
147
return;
148
} else {
149
/* Set socket attribute so it is not passed to any child process */
150
SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
151
(*env)->SetIntField(env, fdObj, IO_fd_fdID, (int)fd);
152
}
153
if (ipv6_available()) {
154
fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
155
156
if (IS_NULL(fd1Obj)) {
157
(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
158
NET_SocketClose(fd);
159
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
160
"null fd1 object");
161
return;
162
}
163
fd1 = socket(AF_INET6, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);
164
if (fd1 == -1) {
165
(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
166
NET_SocketClose(fd);
167
NET_ThrowCurrent(env, "create");
168
return;
169
} else {
170
/* Set socket attribute so it is not passed to any child process */
171
SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE);
172
(*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
173
}
174
} else {
175
(*env)->SetObjectField(env, this, psi_fd1ID, NULL);
176
}
177
}
178
179
/*
180
* inetAddress is the address object passed to the socket connect
181
* call.
182
*
183
* Class: java_net_TwoStacksPlainSocketImpl
184
* Method: socketConnect
185
* Signature: (Ljava/net/InetAddress;I)V
186
*/
187
JNIEXPORT void JNICALL
188
Java_java_net_TwoStacksPlainSocketImpl_socketConnect(JNIEnv *env, jobject this,
189
jobject iaObj, jint port,
190
jint timeout)
191
{
192
jint localport = (*env)->GetIntField(env, this, psi_localportID);
193
194
/* family and localport are int fields of iaObj */
195
int family;
196
jint fd, fd1=-1;
197
jint len;
198
int ipv6_supported = ipv6_available();
199
200
/* fd initially points to the IPv4 socket and fd1 to the IPv6 socket
201
* If we want to connect to IPv6 then we swap the two sockets/objects
202
* This way, fd is always the connected socket, and fd1 always gets closed.
203
*/
204
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
205
jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
206
207
SOCKETADDRESS him;
208
209
/* The result of the connection */
210
int connect_res;
211
memset((char *)&him, 0, sizeof(him));
212
213
if (!IS_NULL(fdObj)) {
214
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
215
}
216
217
if (ipv6_supported && !IS_NULL(fd1Obj)) {
218
fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
219
}
220
221
if (IS_NULL(iaObj)) {
222
JNU_ThrowNullPointerException(env, "inet address argument is null.");
223
return;
224
}
225
226
if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&him, &len, JNI_FALSE) != 0) {
227
return;
228
}
229
230
family = him.him.sa_family;
231
if (family == AF_INET6) {
232
if (!ipv6_supported) {
233
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
234
"Protocol family not supported");
235
return;
236
} else {
237
if (fd1 == -1) {
238
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
239
"Destination unreachable");
240
return;
241
}
242
/* close the v4 socket, and set fd to be the v6 socket */
243
(*env)->SetObjectField(env, this, psi_fdID, fd1Obj);
244
(*env)->SetObjectField(env, this, psi_fd1ID, NULL);
245
NET_SocketClose(fd);
246
fd = fd1; fdObj = fd1Obj;
247
}
248
} else {
249
if (fd1 != -1) {
250
(*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);
251
NET_SocketClose(fd1);
252
}
253
if (fd == -1) {
254
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
255
"Destination unreachable");
256
return;
257
}
258
}
259
(*env)->SetObjectField(env, this, psi_fd1ID, NULL);
260
261
if (timeout <= 0) {
262
connect_res = connect(fd, (struct sockaddr *) &him, SOCKETADDRESS_LEN(&him));
263
if (connect_res == SOCKET_ERROR) {
264
connect_res = WSAGetLastError();
265
}
266
} else {
267
int optval;
268
int optlen = sizeof(optval);
269
270
/* make socket non-blocking */
271
optval = 1;
272
ioctlsocket( fd, FIONBIO, &optval );
273
274
/* initiate the connect */
275
connect_res = connect(fd, (struct sockaddr *) &him, SOCKETADDRESS_LEN(&him));
276
if (connect_res == SOCKET_ERROR) {
277
if (WSAGetLastError() != WSAEWOULDBLOCK) {
278
connect_res = WSAGetLastError();
279
} else {
280
fd_set wr, ex;
281
struct timeval t;
282
283
FD_ZERO(&wr);
284
FD_ZERO(&ex);
285
FD_SET(fd, &wr);
286
FD_SET(fd, &ex);
287
t.tv_sec = timeout / 1000;
288
t.tv_usec = (timeout % 1000) * 1000;
289
290
/*
291
* Wait for timout, connection established or
292
* connection failed.
293
*/
294
connect_res = select(fd+1, 0, &wr, &ex, &t);
295
296
/*
297
* Timeout before connection is established/failed so
298
* we throw exception and shutdown input/output to prevent
299
* socket from being used.
300
* The socket should be closed immediately by the caller.
301
*/
302
if (connect_res == 0) {
303
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
304
"connect timed out");
305
shutdown( fd, SD_BOTH );
306
307
/* make socket blocking again - just in case */
308
optval = 0;
309
ioctlsocket( fd, FIONBIO, &optval );
310
return;
311
}
312
313
/*
314
* We must now determine if the connection has been established
315
* or if it has failed. The logic here is designed to work around
316
* bug on Windows NT whereby using getsockopt to obtain the
317
* last error (SO_ERROR) indicates there is no error. The workaround
318
* on NT is to allow winsock to be scheduled and this is done by
319
* yielding and retrying. As yielding is problematic in heavy
320
* load conditions we attempt up to 3 times to get the error reason.
321
*/
322
if (!FD_ISSET(fd, &ex)) {
323
connect_res = 0;
324
} else {
325
int retry;
326
for (retry=0; retry<3; retry++) {
327
NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
328
(char*)&connect_res, &optlen);
329
if (connect_res) {
330
break;
331
}
332
Sleep(0);
333
}
334
335
if (connect_res == 0) {
336
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
337
"Unable to establish connection");
338
return;
339
}
340
}
341
}
342
}
343
344
/* make socket blocking again */
345
optval = 0;
346
ioctlsocket(fd, FIONBIO, &optval);
347
}
348
349
if (connect_res) {
350
if (connect_res == WSAEADDRNOTAVAIL) {
351
JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
352
"connect: Address is invalid on local machine, or port is not valid on remote machine");
353
} else {
354
NET_ThrowNew(env, connect_res, "connect");
355
}
356
return;
357
}
358
359
(*env)->SetIntField(env, fdObj, IO_fd_fdID, (int)fd);
360
361
/* set the remote peer address and port */
362
(*env)->SetObjectField(env, this, psi_addressID, iaObj);
363
(*env)->SetIntField(env, this, psi_portID, port);
364
365
/*
366
* we need to initialize the local port field if bind was called
367
* previously to the connect (by the client) then localport field
368
* will already be initialized
369
*/
370
if (localport == 0) {
371
/* Now that we're a connected socket, let's extract the port number
372
* that the system chose for us and store it in the Socket object.
373
*/
374
u_short port;
375
int len = SOCKETADDRESS_LEN(&him);
376
if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
377
378
if (WSAGetLastError() == WSAENOTSOCK) {
379
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
380
"Socket closed");
381
} else {
382
NET_ThrowCurrent(env, "getsockname failed");
383
}
384
return;
385
}
386
port = ntohs ((u_short)GET_PORT(&him));
387
(*env)->SetIntField(env, this, psi_localportID, (int) port);
388
}
389
}
390
391
/*
392
* Class: java_net_TwoStacksPlainSocketImpl
393
* Method: socketBind
394
* Signature: (Ljava/net/InetAddress;I)V
395
*/
396
JNIEXPORT void JNICALL
397
Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this,
398
jobject iaObj, jint localport,
399
jboolean exclBind) {
400
401
/* fdObj is the FileDescriptor field on this */
402
jobject fdObj, fd1Obj;
403
/* fd is an int field on fdObj */
404
int fd, fd1, len = 0;
405
int ipv6_supported = ipv6_available();
406
407
/* family is an int field of iaObj */
408
int family;
409
int rv;
410
411
SOCKETADDRESS him;
412
413
fdObj = (*env)->GetObjectField(env, this, psi_fdID);
414
fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
415
416
family = getInetAddress_family(env, iaObj);
417
JNU_CHECK_EXCEPTION(env);
418
419
if (family == IPv6 && !ipv6_supported) {
420
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
421
"Protocol family not supported");
422
return;
423
}
424
425
if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {
426
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
427
"Socket closed");
428
return;
429
} else {
430
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
431
if (ipv6_supported) {
432
fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
433
}
434
}
435
if (IS_NULL(iaObj)) {
436
JNU_ThrowNullPointerException(env, "inet address argument");
437
return;
438
}
439
440
if (NET_InetAddressToSockaddr(env, iaObj, localport,
441
(struct sockaddr *)&him, &len, JNI_FALSE) != 0) {
442
return;
443
}
444
if (ipv6_supported) {
445
struct ipv6bind v6bind;
446
v6bind.addr = &him;
447
v6bind.ipv4_fd = fd;
448
v6bind.ipv6_fd = fd1;
449
rv = NET_BindV6(&v6bind, exclBind);
450
if (rv != -1) {
451
/* check if the fds have changed */
452
if (v6bind.ipv4_fd != fd) {
453
fd = v6bind.ipv4_fd;
454
if (fd == -1) {
455
/* socket is closed. */
456
(*env)->SetObjectField(env, this, psi_fdID, NULL);
457
} else {
458
/* socket was re-created */
459
(*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
460
}
461
}
462
if (v6bind.ipv6_fd != fd1) {
463
fd1 = v6bind.ipv6_fd;
464
if (fd1 == -1) {
465
/* socket is closed. */
466
(*env)->SetObjectField(env, this, psi_fd1ID, NULL);
467
} else {
468
/* socket was re-created */
469
(*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
470
}
471
}
472
} else {
473
/* NET_BindV6() closes both sockets upon a failure */
474
(*env)->SetObjectField(env, this, psi_fdID, NULL);
475
(*env)->SetObjectField(env, this, psi_fd1ID, NULL);
476
}
477
} else {
478
rv = NET_WinBind(fd, (struct sockaddr *)&him, len, exclBind);
479
}
480
481
if (rv == -1) {
482
NET_ThrowCurrent(env, "JVM_Bind");
483
return;
484
}
485
486
/* set the address */
487
(*env)->SetObjectField(env, this, psi_addressID, iaObj);
488
489
/* intialize the local port */
490
if (localport == 0) {
491
/* Now that we're a bound socket, let's extract the port number
492
* that the system chose for us and store it in the Socket object.
493
*/
494
int len = SOCKETADDRESS_LEN(&him);
495
u_short port;
496
fd = him.him.sa_family == AF_INET? fd: fd1;
497
498
if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
499
NET_ThrowCurrent(env, "getsockname in plain socketBind");
500
return;
501
}
502
port = ntohs ((u_short) GET_PORT (&him));
503
504
(*env)->SetIntField(env, this, psi_localportID, (int) port);
505
} else {
506
(*env)->SetIntField(env, this, psi_localportID, localport);
507
}
508
}
509
510
/*
511
* Class: java_net_TwoStacksPlainSocketImpl
512
* Method: socketListen
513
* Signature: (I)V
514
*/
515
JNIEXPORT void JNICALL
516
Java_java_net_TwoStacksPlainSocketImpl_socketListen (JNIEnv *env, jobject this,
517
jint count)
518
{
519
/* this FileDescriptor fd field */
520
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
521
jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
522
jobject address;
523
/* fdObj's int fd field */
524
int fd, fd1;
525
SOCKETADDRESS addr; int addrlen;
526
527
if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
528
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
529
"socket closed");
530
return;
531
}
532
533
if (!IS_NULL(fdObj)) {
534
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
535
}
536
/* Listen on V4 if address type is v4 or if v6 and address is ::0.
537
* Listen on V6 if address type is v6 or if v4 and address is 0.0.0.0.
538
* In cases, where we listen on one space only, we close the other socket.
539
*/
540
address = (*env)->GetObjectField(env, this, psi_addressID);
541
if (IS_NULL(address)) {
542
JNU_ThrowNullPointerException(env, "socket address");
543
return;
544
}
545
if (NET_InetAddressToSockaddr(env, address, 0, (struct sockaddr *)&addr,
546
&addrlen, JNI_FALSE) != 0) {
547
return;
548
}
549
550
if (addr.him.sa_family == AF_INET || IN6ADDR_ISANY(&addr.him6)) {
551
/* listen on v4 */
552
if (listen(fd, count) == -1) {
553
NET_ThrowCurrent(env, "listen failed");
554
}
555
} else {
556
NET_SocketClose (fd);
557
(*env)->SetObjectField(env, this, psi_fdID, NULL);
558
}
559
if (ipv6_available() && !IS_NULL(fd1Obj)) {
560
fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
561
if (addr.him.sa_family == AF_INET6 || addr.him4.sin_addr.s_addr == INADDR_ANY) {
562
/* listen on v6 */
563
if (listen(fd1, count) == -1) {
564
NET_ThrowCurrent(env, "listen failed");
565
}
566
} else {
567
NET_SocketClose (fd1);
568
(*env)->SetObjectField(env, this, psi_fd1ID, NULL);
569
}
570
}
571
}
572
573
/*
574
* Class: java_net_TwoStacksPlainSocketImpl
575
* Method: socketAccept
576
* Signature: (Ljava/net/SocketImpl;)V
577
*/
578
JNIEXPORT void JNICALL
579
Java_java_net_TwoStacksPlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
580
jobject socket)
581
{
582
/* fields on this */
583
jint port;
584
jint scope;
585
jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
586
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
587
jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
588
589
/* the FileDescriptor field on socket */
590
jobject socketFdObj;
591
592
/* cache the Inet4/6Address classes */
593
static jclass inet4Cls;
594
static jclass inet6Cls;
595
596
/* the InetAddress field on socket */
597
jobject socketAddressObj;
598
599
/* the fd int field on fdObj */
600
jint fd=-1, fd1=-1;
601
602
SOCKETADDRESS him;
603
jint len;
604
605
if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
606
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
607
"Socket closed");
608
return;
609
}
610
if (!IS_NULL(fdObj)) {
611
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
612
}
613
if (!IS_NULL(fd1Obj)) {
614
fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
615
}
616
if (IS_NULL(socket)) {
617
JNU_ThrowNullPointerException(env, "socket is null");
618
return;
619
} else {
620
socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
621
socketAddressObj = (*env)->GetObjectField(env, socket, psi_addressID);
622
}
623
if ((IS_NULL(socketAddressObj)) || (IS_NULL(socketFdObj))) {
624
JNU_ThrowNullPointerException(env, "socket address or fd obj");
625
return;
626
}
627
if (fd != -1 && fd1 != -1) {
628
fd_set rfds;
629
struct timeval t, *tP=&t;
630
int lastfd, res, fd2;
631
FD_ZERO(&rfds);
632
FD_SET(fd,&rfds);
633
FD_SET(fd1,&rfds);
634
if (timeout) {
635
t.tv_sec = timeout/1000;
636
t.tv_usec = (timeout%1000)*1000;
637
} else {
638
tP = NULL;
639
}
640
res = select (fd, &rfds, NULL, NULL, tP);
641
if (res == 0) {
642
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
643
"Accept timed out");
644
return;
645
} else if (res == 1) {
646
fd2 = FD_ISSET(fd, &rfds)? fd: fd1;
647
} else if (res == 2) {
648
/* avoid starvation */
649
lastfd = (*env)->GetIntField(env, this, psi_lastfdID);
650
if (lastfd != -1) {
651
fd2 = lastfd==fd? fd1: fd;
652
} else {
653
fd2 = fd;
654
}
655
(*env)->SetIntField(env, this, psi_lastfdID, fd2);
656
} else {
657
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
658
"select failed");
659
return;
660
}
661
if (fd2 == fd) { /* v4 */
662
len = sizeof (struct sockaddr_in);
663
} else {
664
len = sizeof (struct SOCKADDR_IN6);
665
}
666
fd = fd2;
667
} else {
668
int ret;
669
if (fd1 != -1) {
670
fd = fd1;
671
len = sizeof (struct SOCKADDR_IN6);
672
} else {
673
len = sizeof (struct sockaddr_in);
674
}
675
if (timeout) {
676
ret = NET_Timeout(fd, timeout);
677
if (ret == 0) {
678
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
679
"Accept timed out");
680
return;
681
} else if (ret == -1) {
682
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
683
/* REMIND: SOCKET CLOSED PROBLEM */
684
/* NET_ThrowCurrent(env, "Accept failed"); */
685
return;
686
} else if (ret == -2) {
687
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
688
"operation interrupted");
689
return;
690
}
691
}
692
}
693
fd = accept(fd, (struct sockaddr *)&him, &len);
694
if (fd < 0) {
695
/* REMIND: SOCKET CLOSED PROBLEM */
696
if (fd == -2) {
697
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
698
"operation interrupted");
699
} else {
700
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
701
"socket closed");
702
}
703
return;
704
}
705
SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, 0);
706
(*env)->SetIntField(env, socketFdObj, IO_fd_fdID, fd);
707
708
if (him.him.sa_family == AF_INET) {
709
if (inet4Cls == NULL) {
710
jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
711
if (c != NULL) {
712
inet4Cls = (*env)->NewGlobalRef(env, c);
713
(*env)->DeleteLocalRef(env, c);
714
}
715
}
716
717
/*
718
* fill up the remote peer port and address in the new socket structure
719
*/
720
if (inet4Cls != NULL) {
721
socketAddressObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
722
} else {
723
socketAddressObj = NULL;
724
}
725
if (socketAddressObj == NULL) {
726
/*
727
* FindClass or NewObject failed so close connection and
728
* exist (there will be a pending exception).
729
*/
730
NET_SocketClose(fd);
731
return;
732
}
733
734
setInetAddress_addr(env, socketAddressObj, ntohl(him.him4.sin_addr.s_addr));
735
JNU_CHECK_EXCEPTION(env);
736
setInetAddress_family(env, socketAddressObj, IPv4);
737
JNU_CHECK_EXCEPTION(env);
738
(*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
739
} else {
740
/* AF_INET6 -> Inet6Address */
741
if (inet6Cls == 0) {
742
jclass c = (*env)->FindClass(env, "java/net/Inet6Address");
743
if (c != NULL) {
744
inet6Cls = (*env)->NewGlobalRef(env, c);
745
(*env)->DeleteLocalRef(env, c);
746
}
747
}
748
749
if (inet6Cls != NULL) {
750
socketAddressObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID);
751
} else {
752
socketAddressObj = NULL;
753
}
754
if (socketAddressObj == NULL) {
755
/*
756
* FindClass or NewObject failed so close connection and
757
* exist (there will be a pending exception).
758
*/
759
NET_SocketClose(fd);
760
return;
761
}
762
setInet6Address_ipaddress(env, socketAddressObj, (const char *)&him.him6.sin6_addr);
763
setInetAddress_family(env, socketAddressObj, IPv6);
764
JNU_CHECK_EXCEPTION(env);
765
setInet6Address_scopeid(env, socketAddressObj, him.him6.sin6_scope_id);
766
767
}
768
/* fields common to AF_INET and AF_INET6 */
769
770
port = ntohs ((u_short) GET_PORT (&him));
771
(*env)->SetIntField(env, socket, psi_portID, (int)port);
772
port = (*env)->GetIntField(env, this, psi_localportID);
773
(*env)->SetIntField(env, socket, psi_localportID, port);
774
(*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
775
}
776
777
/*
778
* Class: java_net_TwoStacksPlainSocketImpl
779
* Method: socketAvailable
780
* Signature: ()I
781
*/
782
JNIEXPORT jint JNICALL
783
Java_java_net_TwoStacksPlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {
784
785
jint available = -1;
786
jint res;
787
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
788
jint fd;
789
790
if (IS_NULL(fdObj)) {
791
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
792
return -1;
793
} else {
794
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
795
}
796
res = ioctlsocket(fd, FIONREAD, &available);
797
/* if result isn't 0, it means an error */
798
if (res != 0) {
799
NET_ThrowNew(env, res, "socket available");
800
}
801
return available;
802
}
803
804
/*
805
* Class: java_net_TwoStacksPlainSocketImpl
806
* Method: socketClose
807
* Signature: ()V
808
*/
809
JNIEXPORT void JNICALL
810
Java_java_net_TwoStacksPlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
811
jboolean useDeferredClose) {
812
813
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
814
jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
815
jint fd=-1, fd1=-1;
816
817
if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
818
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
819
"socket already closed");
820
return;
821
}
822
if (!IS_NULL(fdObj)) {
823
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
824
}
825
if (!IS_NULL(fd1Obj)) {
826
fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
827
}
828
if (fd != -1) {
829
(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
830
NET_SocketClose(fd);
831
}
832
if (fd1 != -1) {
833
(*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);
834
NET_SocketClose(fd1);
835
}
836
}
837
838
/*
839
* Socket options for plainsocketImpl
840
*
841
*
842
* Class: java_net_TwoStacksPlainSocketImpl
843
* Method: socketNativeSetOption
844
* Signature: (IZLjava/lang/Object;)V
845
*/
846
JNIEXPORT void JNICALL
847
Java_java_net_TwoStacksPlainSocketImpl_socketNativeSetOption(JNIEnv *env,
848
jobject this,
849
jint cmd, jboolean on,
850
jobject value) {
851
int fd, fd1;
852
int level = 0, optname = 0, optlen = 0;
853
union {
854
int i;
855
struct linger ling;
856
} optval;
857
858
memset((char *)&optval, 0, sizeof(optval));
859
/*
860
* Get SOCKET and check that it hasn't been closed
861
*/
862
fd = getFD(env, this);
863
fd1 = getFD1(env, this);
864
if (fd < 0 && fd1 < 0) {
865
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
866
return;
867
}
868
869
/*
870
* SO_TIMEOUT is the socket option used to specify the timeout
871
* for ServerSocket.accept and Socket.getInputStream().read.
872
* It does not typically map to a native level socket option.
873
* For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
874
* socket option to specify a receive timeout on the socket. This
875
* receive timeout is applicable to Socket only and the socket
876
* option should not be set on ServerSocket.
877
*/
878
if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
879
880
/*
881
* Don't enable the socket option on ServerSocket as it's
882
* meaningless (we don't receive on a ServerSocket).
883
*/
884
jobject ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID);
885
if (ssObj != NULL) {
886
return;
887
}
888
889
/*
890
* SO_RCVTIMEO is only supported on Microsoft's implementation
891
* of Windows Sockets so if WSAENOPROTOOPT returned then
892
* reset flag and timeout will be implemented using
893
* select() -- see SocketInputStream.socketRead.
894
*/
895
if (isRcvTimeoutSupported) {
896
jclass iCls = (*env)->FindClass(env, "java/lang/Integer");
897
jfieldID i_valueID;
898
jint timeout;
899
900
CHECK_NULL(iCls);
901
i_valueID = (*env)->GetFieldID(env, iCls, "value", "I");
902
CHECK_NULL(i_valueID);
903
timeout = (*env)->GetIntField(env, value, i_valueID);
904
905
/*
906
* Disable SO_RCVTIMEO if timeout is <= 5 second.
907
*/
908
if (timeout <= 5000) {
909
timeout = 0;
910
}
911
912
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
913
sizeof(timeout)) < 0) {
914
if (WSAGetLastError() == WSAENOPROTOOPT) {
915
isRcvTimeoutSupported = JNI_FALSE;
916
} else {
917
NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO");
918
return;
919
}
920
}
921
if (fd1 != -1) {
922
if (setsockopt(fd1, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
923
sizeof(timeout)) < 0) {
924
NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO");
925
}
926
}
927
}
928
return;
929
}
930
931
/*
932
* Map the Java level socket option to the platform specific
933
* level
934
*/
935
if (NET_MapSocketOption(cmd, &level, &optname)) {
936
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
937
"Invalid option");
938
return;
939
}
940
941
switch (cmd) {
942
943
case java_net_SocketOptions_TCP_NODELAY :
944
case java_net_SocketOptions_SO_OOBINLINE :
945
case java_net_SocketOptions_SO_KEEPALIVE :
946
case java_net_SocketOptions_SO_REUSEADDR :
947
optval.i = (on ? 1 : 0);
948
optlen = sizeof(optval.i);
949
break;
950
951
case java_net_SocketOptions_SO_SNDBUF :
952
case java_net_SocketOptions_SO_RCVBUF :
953
case java_net_SocketOptions_IP_TOS :
954
{
955
jclass cls;
956
jfieldID fid;
957
958
cls = (*env)->FindClass(env, "java/lang/Integer");
959
CHECK_NULL(cls);
960
fid = (*env)->GetFieldID(env, cls, "value", "I");
961
CHECK_NULL(fid);
962
963
optval.i = (*env)->GetIntField(env, value, fid);
964
optlen = sizeof(optval.i);
965
}
966
break;
967
968
case java_net_SocketOptions_SO_LINGER :
969
{
970
jclass cls;
971
jfieldID fid;
972
973
cls = (*env)->FindClass(env, "java/lang/Integer");
974
CHECK_NULL(cls);
975
fid = (*env)->GetFieldID(env, cls, "value", "I");
976
CHECK_NULL(fid);
977
978
if (on) {
979
optval.ling.l_onoff = 1;
980
optval.ling.l_linger =
981
(unsigned short)(*env)->GetIntField(env, value, fid);
982
} else {
983
optval.ling.l_onoff = 0;
984
optval.ling.l_linger = 0;
985
}
986
optlen = sizeof(optval.ling);
987
}
988
break;
989
990
default: /* shouldn't get here */
991
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
992
"Option not supported by TwoStacksPlainSocketImpl");
993
return;
994
}
995
996
if (fd != -1) {
997
if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) {
998
NET_ThrowCurrent(env, "setsockopt");
999
}
1000
}
1001
1002
if (fd1 != -1) {
1003
if (NET_SetSockOpt(fd1, level, optname, (void *)&optval, optlen) < 0) {
1004
NET_ThrowCurrent(env, "setsockopt");
1005
}
1006
}
1007
}
1008
1009
1010
/*
1011
* Class: java_net_TwoStacksPlainSocketImpl
1012
* Method: socketGetOption
1013
* Signature: (I)I
1014
*/
1015
JNIEXPORT jint JNICALL
1016
Java_java_net_TwoStacksPlainSocketImpl_socketGetOption(JNIEnv *env, jobject this,
1017
jint opt, jobject iaContainerObj) {
1018
1019
int fd, fd1;
1020
int level = 0, optname = 0, optlen = 0;
1021
union {
1022
int i;
1023
struct linger ling;
1024
} optval;
1025
/*
1026
* Get SOCKET and check it hasn't been closed
1027
*/
1028
fd = getFD(env, this);
1029
fd1 = getFD1(env, this);
1030
memset((char *)&optval, 0, sizeof(optval));
1031
1032
if (fd < 0 && fd1 < 0) {
1033
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
1034
return -1;
1035
}
1036
if (fd < 0) {
1037
fd = fd1;
1038
}
1039
1040
/* For IPv6, we assume both sockets have the same setting always */
1041
1042
/*
1043
* SO_BINDADDR isn't a socket option
1044
*/
1045
if (opt == java_net_SocketOptions_SO_BINDADDR) {
1046
SOCKETADDRESS him;
1047
int len;
1048
int port;
1049
jobject iaObj;
1050
jclass iaCntrClass;
1051
jfieldID iaFieldID;
1052
1053
len = sizeof(him);
1054
memset((char *)&him, 0, len);
1055
1056
if (fd == -1) {
1057
/* must be an IPV6 only socket. Case where both sockets are != -1
1058
* is handled in java
1059
*/
1060
fd = getFD1 (env, this);
1061
}
1062
1063
if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) {
1064
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1065
"Error getting socket name");
1066
return -1;
1067
}
1068
iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
1069
CHECK_NULL_RETURN(iaObj, -1);
1070
1071
iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
1072
iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");
1073
CHECK_NULL_RETURN(iaFieldID, -1);
1074
(*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
1075
return 0; /* notice change from before */
1076
}
1077
1078
/*
1079
* Map the Java level socket option to the platform specific
1080
* level and option name.
1081
*/
1082
if (NET_MapSocketOption(opt, &level, &optname)) {
1083
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1084
return -1;
1085
}
1086
1087
/*
1088
* Args are int except for SO_LINGER
1089
*/
1090
if (opt == java_net_SocketOptions_SO_LINGER) {
1091
optlen = sizeof(optval.ling);
1092
} else {
1093
optlen = sizeof(optval.i);
1094
optval.i = 0;
1095
}
1096
1097
if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1098
NET_ThrowCurrent(env, "getsockopt");
1099
return -1;
1100
}
1101
1102
switch (opt) {
1103
case java_net_SocketOptions_SO_LINGER:
1104
return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
1105
1106
case java_net_SocketOptions_SO_SNDBUF:
1107
case java_net_SocketOptions_SO_RCVBUF:
1108
case java_net_SocketOptions_IP_TOS:
1109
return optval.i;
1110
1111
case java_net_SocketOptions_TCP_NODELAY :
1112
case java_net_SocketOptions_SO_OOBINLINE :
1113
case java_net_SocketOptions_SO_KEEPALIVE :
1114
case java_net_SocketOptions_SO_REUSEADDR :
1115
return (optval.i == 0) ? -1 : 1;
1116
1117
default: /* shouldn't get here */
1118
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1119
"Option not supported by TwoStacksPlainSocketImpl");
1120
return -1;
1121
}
1122
}
1123
1124
/*
1125
* Class: java_net_TwoStacksPlainSocketImpl
1126
* Method: socketShutdown
1127
* Signature: (I)V
1128
*/
1129
JNIEXPORT void JNICALL
1130
Java_java_net_TwoStacksPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
1131
jint howto)
1132
{
1133
1134
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1135
jint fd;
1136
1137
/*
1138
* WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
1139
* -1 already?
1140
*/
1141
if (IS_NULL(fdObj)) {
1142
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1143
"socket already closed");
1144
return;
1145
} else {
1146
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1147
}
1148
shutdown(fd, howto);
1149
}
1150
1151
/*
1152
* Class: java_net_TwoStacksPlainSocketImpl
1153
* Method: socketSendUrgentData
1154
* Signature: (B)V
1155
*/
1156
JNIEXPORT void JNICALL
1157
Java_java_net_TwoStacksPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
1158
jint data) {
1159
/* The fd field */
1160
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1161
int n, fd;
1162
unsigned char d = data & 0xff;
1163
1164
if (IS_NULL(fdObj)) {
1165
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1166
return;
1167
} else {
1168
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1169
/* Bug 4086704 - If the Socket associated with this file descriptor
1170
* was closed (sysCloseFD), the the file descriptor is set to -1.
1171
*/
1172
if (fd == -1) {
1173
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1174
return;
1175
}
1176
1177
}
1178
n = send(fd, (char *)&data, 1, MSG_OOB);
1179
if (n == JVM_IO_ERR) {
1180
NET_ThrowCurrent(env, "send");
1181
return;
1182
}
1183
if (n == JVM_IO_INTR) {
1184
JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
1185
return;
1186
}
1187
}
1188
1189