Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/java/net/PlainSocketImpl.c
32287 views
1
/*
2
* Copyright (c) 1997, 2012, 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 <errno.h>
27
#include <string.h>
28
#include <sys/types.h>
29
#include <sys/socket.h>
30
#if defined(__linux__) && !defined(USE_SELECT)
31
#include <sys/poll.h>
32
#endif
33
#include <netinet/tcp.h> /* Defines TCP_NODELAY, needed for 2.6 */
34
#include <netinet/in.h>
35
#ifdef __linux__
36
#include <netinet/ip.h>
37
#endif
38
#include <netdb.h>
39
#include <stdlib.h>
40
41
#ifdef __solaris__
42
#include <fcntl.h>
43
#endif
44
#ifdef __linux__
45
#include <unistd.h>
46
#endif
47
48
#include "jvm.h"
49
#include "jni_util.h"
50
#include "net_util.h"
51
52
#include "java_net_SocketOptions.h"
53
#include "java_net_PlainSocketImpl.h"
54
55
/************************************************************************
56
* PlainSocketImpl
57
*/
58
59
static jfieldID IO_fd_fdID;
60
61
jfieldID psi_fdID;
62
jfieldID psi_addressID;
63
jfieldID psi_ipaddressID;
64
jfieldID psi_portID;
65
jfieldID psi_localportID;
66
jfieldID psi_timeoutID;
67
jfieldID psi_trafficClassID;
68
jfieldID psi_serverSocketID;
69
jfieldID psi_fdLockID;
70
jfieldID psi_closePendingID;
71
72
extern void setDefaultScopeID(JNIEnv *env, struct sockaddr *him);
73
74
/*
75
* file descriptor used for dup2
76
*/
77
static int marker_fd = -1;
78
79
80
#define SET_NONBLOCKING(fd) { \
81
int flags = fcntl(fd, F_GETFL); \
82
flags |= O_NONBLOCK; \
83
fcntl(fd, F_SETFL, flags); \
84
}
85
86
#define SET_BLOCKING(fd) { \
87
int flags = fcntl(fd, F_GETFL); \
88
flags &= ~O_NONBLOCK; \
89
fcntl(fd, F_SETFL, flags); \
90
}
91
92
/*
93
* Create the marker file descriptor by establishing a loopback connection
94
* which we shutdown but do not close the fd. The result is an fd that
95
* can be used for read/write.
96
*/
97
static int getMarkerFD()
98
{
99
int sv[2];
100
101
#ifdef AF_UNIX
102
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
103
return -1;
104
}
105
#else
106
return -1;
107
#endif
108
109
/*
110
* Finally shutdown sv[0] (any reads to this fd will get
111
* EOF; any writes will get an error).
112
*/
113
JVM_SocketShutdown(sv[0], 2);
114
JVM_SocketClose(sv[1]);
115
116
return sv[0];
117
}
118
119
/*
120
* Return the file descriptor given a PlainSocketImpl
121
*/
122
static int getFD(JNIEnv *env, jobject this) {
123
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
124
CHECK_NULL_RETURN(fdObj, -1);
125
return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
126
}
127
128
/*
129
* The initroto function is called whenever PlainSocketImpl is
130
* loaded, to cache field IDs for efficiency. This is called every time
131
* the Java class is loaded.
132
*
133
* Class: java_net_PlainSocketImpl
134
* Method: initProto
135
* Signature: ()V
136
*/
137
JNIEXPORT void JNICALL
138
Java_java_net_PlainSocketImpl_initProto(JNIEnv *env, jclass cls) {
139
psi_fdID = (*env)->GetFieldID(env, cls , "fd",
140
"Ljava/io/FileDescriptor;");
141
CHECK_NULL(psi_fdID);
142
psi_addressID = (*env)->GetFieldID(env, cls, "address",
143
"Ljava/net/InetAddress;");
144
CHECK_NULL(psi_addressID);
145
psi_portID = (*env)->GetFieldID(env, cls, "port", "I");
146
CHECK_NULL(psi_portID);
147
psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");
148
CHECK_NULL(psi_localportID);
149
psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
150
CHECK_NULL(psi_timeoutID);
151
psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
152
CHECK_NULL(psi_trafficClassID);
153
psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket",
154
"Ljava/net/ServerSocket;");
155
CHECK_NULL(psi_serverSocketID);
156
psi_fdLockID = (*env)->GetFieldID(env, cls, "fdLock",
157
"Ljava/lang/Object;");
158
CHECK_NULL(psi_fdLockID);
159
psi_closePendingID = (*env)->GetFieldID(env, cls, "closePending", "Z");
160
CHECK_NULL(psi_closePendingID);
161
IO_fd_fdID = NET_GetFileDescriptorID(env);
162
CHECK_NULL(IO_fd_fdID);
163
164
initInetAddressIDs(env);
165
JNU_CHECK_EXCEPTION(env);
166
167
/* Create the marker fd used for dup2 */
168
marker_fd = getMarkerFD();
169
}
170
171
/* a global reference to the java.net.SocketException class. In
172
* socketCreate, we ensure that this is initialized. This is to
173
* prevent the problem where socketCreate runs out of file
174
* descriptors, and is then unable to load the exception class.
175
*/
176
static jclass socketExceptionCls;
177
178
/*
179
* Class: java_net_PlainSocketImpl
180
* Method: socketCreate
181
* Signature: (Z)V */
182
JNIEXPORT void JNICALL
183
Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
184
jboolean stream) {
185
jobject fdObj, ssObj;
186
int fd;
187
int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
188
#ifdef AF_INET6
189
int domain = ipv6_available() ? AF_INET6 : AF_INET;
190
#else
191
int domain = AF_INET;
192
#endif
193
194
if (socketExceptionCls == NULL) {
195
jclass c = (*env)->FindClass(env, "java/net/SocketException");
196
CHECK_NULL(c);
197
socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c);
198
CHECK_NULL(socketExceptionCls);
199
}
200
fdObj = (*env)->GetObjectField(env, this, psi_fdID);
201
202
if (fdObj == NULL) {
203
(*env)->ThrowNew(env, socketExceptionCls, "null fd object");
204
return;
205
}
206
207
if ((fd = JVM_Socket(domain, type, 0)) == JVM_IO_ERR) {
208
/* note: if you run out of fds, you may not be able to load
209
* the exception class, and get a NoClassDefFoundError
210
* instead.
211
*/
212
NET_ThrowNew(env, errno, "can't create socket");
213
return;
214
}
215
216
#ifdef AF_INET6
217
/* Disable IPV6_V6ONLY to ensure dual-socket support */
218
if (domain == AF_INET6) {
219
int arg = 0;
220
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
221
sizeof(int)) < 0) {
222
NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
223
close(fd);
224
return;
225
}
226
}
227
#endif /* AF_INET6 */
228
229
/*
230
* If this is a server socket then enable SO_REUSEADDR
231
* automatically and set to non blocking.
232
*/
233
ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID);
234
if (ssObj != NULL) {
235
int arg = 1;
236
SET_NONBLOCKING(fd);
237
if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
238
sizeof(arg)) < 0) {
239
NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");
240
close(fd);
241
return;
242
}
243
}
244
245
(*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
246
}
247
248
/*
249
* inetAddress is the address object passed to the socket connect
250
* call.
251
*
252
* Class: java_net_PlainSocketImpl
253
* Method: socketConnect
254
* Signature: (Ljava/net/InetAddress;I)V
255
*/
256
JNIEXPORT void JNICALL
257
Java_java_net_PlainSocketImpl_socketConnect(JNIEnv *env, jobject this,
258
jobject iaObj, jint port,
259
jint timeout)
260
{
261
jint localport = (*env)->GetIntField(env, this, psi_localportID);
262
int len = 0;
263
264
/* fdObj is the FileDescriptor field on this */
265
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
266
267
jclass clazz = (*env)->GetObjectClass(env, this);
268
269
jobject fdLock;
270
271
jint trafficClass = (*env)->GetIntField(env, this, psi_trafficClassID);
272
273
/* fd is an int field on iaObj */
274
jint fd;
275
276
SOCKADDR him;
277
/* The result of the connection */
278
int connect_rv = -1;
279
280
if (IS_NULL(fdObj)) {
281
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
282
return;
283
} else {
284
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
285
}
286
if (IS_NULL(iaObj)) {
287
JNU_ThrowNullPointerException(env, "inet address argument null.");
288
return;
289
}
290
291
/* connect */
292
if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
293
return;
294
}
295
setDefaultScopeID(env, (struct sockaddr *)&him);
296
297
#ifdef AF_INET6
298
if (trafficClass != 0 && ipv6_available()) {
299
NET_SetTrafficClass((struct sockaddr *)&him, trafficClass);
300
}
301
#endif /* AF_INET6 */
302
if (timeout <= 0) {
303
connect_rv = NET_Connect(fd, (struct sockaddr *)&him, len);
304
#ifdef __solaris__
305
if (connect_rv == JVM_IO_ERR && errno == EINPROGRESS ) {
306
307
/* This can happen if a blocking connect is interrupted by a signal.
308
* See 6343810.
309
*/
310
while (1) {
311
#ifndef USE_SELECT
312
{
313
struct pollfd pfd;
314
pfd.fd = fd;
315
pfd.events = POLLOUT;
316
317
connect_rv = NET_Poll(&pfd, 1, -1);
318
}
319
#else
320
{
321
fd_set wr, ex;
322
323
FD_ZERO(&wr);
324
FD_SET(fd, &wr);
325
FD_ZERO(&ex);
326
FD_SET(fd, &ex);
327
328
connect_rv = NET_Select(fd+1, 0, &wr, &ex, 0);
329
}
330
#endif
331
332
if (connect_rv == JVM_IO_ERR) {
333
if (errno == EINTR) {
334
continue;
335
} else {
336
break;
337
}
338
}
339
if (connect_rv > 0) {
340
int optlen;
341
/* has connection been established */
342
optlen = sizeof(connect_rv);
343
if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
344
(void*)&connect_rv, &optlen) <0) {
345
connect_rv = errno;
346
}
347
348
if (connect_rv != 0) {
349
/* restore errno */
350
errno = connect_rv;
351
connect_rv = JVM_IO_ERR;
352
}
353
break;
354
}
355
}
356
}
357
#endif
358
} else {
359
/*
360
* A timeout was specified. We put the socket into non-blocking
361
* mode, connect, and then wait for the connection to be
362
* established, fail, or timeout.
363
*/
364
SET_NONBLOCKING(fd);
365
366
/* no need to use NET_Connect as non-blocking */
367
connect_rv = connect(fd, (struct sockaddr *)&him, len);
368
369
/* connection not established immediately */
370
if (connect_rv != 0) {
371
int optlen;
372
jlong prevTime = JVM_CurrentTimeMillis(env, 0);
373
374
if (errno != EINPROGRESS) {
375
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
376
"connect failed");
377
SET_BLOCKING(fd);
378
return;
379
}
380
381
/*
382
* Wait for the connection to be established or a
383
* timeout occurs. poll/select needs to handle EINTR in
384
* case lwp sig handler redirects any process signals to
385
* this thread.
386
*/
387
while (1) {
388
jlong newTime;
389
#ifndef USE_SELECT
390
{
391
struct pollfd pfd;
392
pfd.fd = fd;
393
pfd.events = POLLOUT;
394
395
errno = 0;
396
connect_rv = NET_Poll(&pfd, 1, timeout);
397
}
398
#else
399
{
400
fd_set wr, ex;
401
struct timeval t;
402
403
t.tv_sec = timeout / 1000;
404
t.tv_usec = (timeout % 1000) * 1000;
405
406
FD_ZERO(&wr);
407
FD_SET(fd, &wr);
408
FD_ZERO(&ex);
409
FD_SET(fd, &ex);
410
411
errno = 0;
412
connect_rv = NET_Select(fd+1, 0, &wr, &ex, &t);
413
}
414
#endif
415
416
if (connect_rv >= 0) {
417
break;
418
}
419
if (errno != EINTR) {
420
break;
421
}
422
423
/*
424
* The poll was interrupted so adjust timeout and
425
* restart
426
*/
427
newTime = JVM_CurrentTimeMillis(env, 0);
428
timeout -= (newTime - prevTime);
429
if (timeout <= 0) {
430
connect_rv = 0;
431
break;
432
}
433
prevTime = newTime;
434
435
} /* while */
436
437
if (connect_rv == 0) {
438
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
439
"connect timed out");
440
441
/*
442
* Timeout out but connection may still be established.
443
* At the high level it should be closed immediately but
444
* just in case we make the socket blocking again and
445
* shutdown input & output.
446
*/
447
SET_BLOCKING(fd);
448
JVM_SocketShutdown(fd, 2);
449
return;
450
}
451
452
/* has connection been established */
453
optlen = sizeof(connect_rv);
454
if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
455
&optlen) <0) {
456
connect_rv = errno;
457
}
458
}
459
460
/* make socket blocking again */
461
SET_BLOCKING(fd);
462
463
/* restore errno */
464
if (connect_rv != 0) {
465
errno = connect_rv;
466
connect_rv = JVM_IO_ERR;
467
}
468
}
469
470
/* report the appropriate exception */
471
if (connect_rv < 0) {
472
473
#ifdef __linux__
474
/*
475
* Linux/GNU distribution setup /etc/hosts so that
476
* InetAddress.getLocalHost gets back the loopback address
477
* rather than the host address. Thus a socket can be
478
* bound to the loopback address and the connect will
479
* fail with EADDRNOTAVAIL. In addition the Linux kernel
480
* returns the wrong error in this case - it returns EINVAL
481
* instead of EADDRNOTAVAIL. We handle this here so that
482
* a more descriptive exception text is used.
483
*/
484
if (connect_rv == JVM_IO_ERR && errno == EINVAL) {
485
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
486
"Invalid argument or cannot assign requested address");
487
return;
488
}
489
#endif
490
if (connect_rv == JVM_IO_INTR) {
491
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
492
"operation interrupted");
493
#if defined(EPROTO)
494
} else if (errno == EPROTO) {
495
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ProtocolException",
496
"Protocol error");
497
#endif
498
} else if (errno == ECONNREFUSED) {
499
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
500
"Connection refused");
501
} else if (errno == ETIMEDOUT) {
502
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
503
"Connection timed out");
504
} else if (errno == EHOSTUNREACH) {
505
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",
506
"Host unreachable");
507
} else if (errno == EADDRNOTAVAIL) {
508
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",
509
"Address not available");
510
} else if ((errno == EISCONN) || (errno == EBADF)) {
511
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
512
"Socket closed");
513
} else {
514
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "connect failed");
515
}
516
return;
517
}
518
519
(*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
520
521
/* set the remote peer address and port */
522
(*env)->SetObjectField(env, this, psi_addressID, iaObj);
523
(*env)->SetIntField(env, this, psi_portID, port);
524
525
/*
526
* we need to initialize the local port field if bind was called
527
* previously to the connect (by the client) then localport field
528
* will already be initialized
529
*/
530
if (localport == 0) {
531
/* Now that we're a connected socket, let's extract the port number
532
* that the system chose for us and store it in the Socket object.
533
*/
534
len = SOCKADDR_LEN;
535
if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) {
536
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
537
"Error getting socket name");
538
} else {
539
localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
540
(*env)->SetIntField(env, this, psi_localportID, localport);
541
}
542
}
543
}
544
545
/*
546
* Class: java_net_PlainSocketImpl
547
* Method: socketBind
548
* Signature: (Ljava/net/InetAddress;I)V
549
*/
550
JNIEXPORT void JNICALL
551
Java_java_net_PlainSocketImpl_socketBind(JNIEnv *env, jobject this,
552
jobject iaObj, jint localport) {
553
554
/* fdObj is the FileDescriptor field on this */
555
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
556
/* fd is an int field on fdObj */
557
int fd;
558
int len;
559
SOCKADDR him;
560
561
if (IS_NULL(fdObj)) {
562
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
563
"Socket closed");
564
return;
565
} else {
566
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
567
}
568
if (IS_NULL(iaObj)) {
569
JNU_ThrowNullPointerException(env, "iaObj is null.");
570
return;
571
}
572
573
/* bind */
574
if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
575
return;
576
}
577
setDefaultScopeID(env, (struct sockaddr *)&him);
578
579
if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0) {
580
if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
581
errno == EPERM || errno == EACCES) {
582
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
583
"Bind failed");
584
} else {
585
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
586
"Bind failed");
587
}
588
return;
589
}
590
591
/* set the address */
592
(*env)->SetObjectField(env, this, psi_addressID, iaObj);
593
594
/* initialize the local port */
595
if (localport == 0) {
596
/* Now that we're a connected socket, let's extract the port number
597
* that the system chose for us and store it in the Socket object.
598
*/
599
if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) {
600
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
601
"Error getting socket name");
602
return;
603
}
604
localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
605
(*env)->SetIntField(env, this, psi_localportID, localport);
606
} else {
607
(*env)->SetIntField(env, this, psi_localportID, localport);
608
}
609
}
610
611
/*
612
* Class: java_net_PlainSocketImpl
613
* Method: socketListen
614
* Signature: (I)V
615
*/
616
JNIEXPORT void JNICALL
617
Java_java_net_PlainSocketImpl_socketListen (JNIEnv *env, jobject this,
618
jint count)
619
{
620
/* this FileDescriptor fd field */
621
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
622
/* fdObj's int fd field */
623
int fd;
624
625
if (IS_NULL(fdObj)) {
626
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
627
"Socket closed");
628
return;
629
} else {
630
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
631
}
632
633
/*
634
* Workaround for bugid 4101691 in Solaris 2.6. See 4106600.
635
* If listen backlog is Integer.MAX_VALUE then subtract 1.
636
*/
637
if (count == 0x7fffffff)
638
count -= 1;
639
640
if (JVM_Listen(fd, count) == JVM_IO_ERR) {
641
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
642
"Listen failed");
643
}
644
}
645
646
/*
647
* Class: java_net_PlainSocketImpl
648
* Method: socketAccept
649
* Signature: (Ljava/net/SocketImpl;)V
650
*/
651
JNIEXPORT void JNICALL
652
Java_java_net_PlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
653
jobject socket)
654
{
655
/* fields on this */
656
int port;
657
jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
658
jlong prevTime = 0;
659
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
660
661
/* the FileDescriptor field on socket */
662
jobject socketFdObj;
663
/* the InetAddress field on socket */
664
jobject socketAddressObj;
665
666
/* the ServerSocket fd int field on fdObj */
667
jint fd;
668
669
/* accepted fd */
670
jint newfd;
671
672
SOCKADDR him;
673
int len;
674
675
len = SOCKADDR_LEN;
676
677
if (IS_NULL(fdObj)) {
678
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
679
"Socket closed");
680
return;
681
} else {
682
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
683
}
684
if (IS_NULL(socket)) {
685
JNU_ThrowNullPointerException(env, "socket is null");
686
return;
687
}
688
689
/*
690
* accept connection but ignore ECONNABORTED indicating that
691
* connection was eagerly accepted by the OS but was reset
692
* before accept() was called.
693
*
694
* If accept timeout in place and timeout is adjusted with
695
* each ECONNABORTED or EWOULDBLOCK to ensure that semantics
696
* of timeout are preserved.
697
*/
698
for (;;) {
699
int ret;
700
701
/* first usage pick up current time */
702
if (prevTime == 0 && timeout > 0) {
703
prevTime = JVM_CurrentTimeMillis(env, 0);
704
}
705
706
/* passing a timeout of 0 to poll will return immediately,
707
but in the case of ServerSocket 0 means infinite. */
708
if (timeout <= 0) {
709
ret = NET_Timeout(fd, -1);
710
} else {
711
ret = NET_Timeout(fd, timeout);
712
}
713
if (ret == 0) {
714
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
715
"Accept timed out");
716
return;
717
} else if (ret == JVM_IO_ERR) {
718
if (errno == EBADF) {
719
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
720
} else if (errno == ENOMEM) {
721
JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
722
} else {
723
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Accept failed");
724
}
725
return;
726
} else if (ret == JVM_IO_INTR) {
727
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
728
"operation interrupted");
729
return;
730
}
731
732
newfd = NET_Accept(fd, (struct sockaddr *)&him, (jint*)&len);
733
734
/* connection accepted */
735
if (newfd >= 0) {
736
SET_BLOCKING(newfd);
737
break;
738
}
739
740
/* non (ECONNABORTED or EWOULDBLOCK) error */
741
if (!(errno == ECONNABORTED || errno == EWOULDBLOCK)) {
742
break;
743
}
744
745
/* ECONNABORTED or EWOULDBLOCK error so adjust timeout if there is one. */
746
if (timeout) {
747
jlong currTime = JVM_CurrentTimeMillis(env, 0);
748
timeout -= (currTime - prevTime);
749
750
if (timeout <= 0) {
751
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
752
"Accept timed out");
753
return;
754
}
755
prevTime = currTime;
756
}
757
}
758
759
if (newfd < 0) {
760
if (newfd == -2) {
761
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
762
"operation interrupted");
763
} else {
764
if (errno == EINVAL) {
765
errno = EBADF;
766
}
767
if (errno == EBADF) {
768
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
769
} else {
770
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Accept failed");
771
}
772
}
773
return;
774
}
775
776
/*
777
* fill up the remote peer port and address in the new socket structure.
778
*/
779
socketAddressObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
780
if (socketAddressObj == NULL) {
781
/* should be pending exception */
782
close(newfd);
783
return;
784
}
785
786
/*
787
* Populate SocketImpl.fd.fd
788
*/
789
socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
790
(*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd);
791
792
(*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
793
(*env)->SetIntField(env, socket, psi_portID, port);
794
/* also fill up the local port information */
795
port = (*env)->GetIntField(env, this, psi_localportID);
796
(*env)->SetIntField(env, socket, psi_localportID, port);
797
}
798
799
800
/*
801
* Class: java_net_PlainSocketImpl
802
* Method: socketAvailable
803
* Signature: ()I
804
*/
805
JNIEXPORT jint JNICALL
806
Java_java_net_PlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {
807
808
jint ret = -1;
809
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
810
jint fd;
811
812
if (IS_NULL(fdObj)) {
813
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
814
"Socket closed");
815
return -1;
816
} else {
817
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
818
}
819
/* JVM_SocketAvailable returns 0 for failure, 1 for success */
820
if (!JVM_SocketAvailable(fd, &ret)){
821
if (errno == ECONNRESET) {
822
JNU_ThrowByName(env, "sun/net/ConnectionResetException", "");
823
} else {
824
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
825
"ioctl FIONREAD failed");
826
}
827
}
828
return ret;
829
}
830
831
/*
832
* Class: java_net_PlainSocketImpl
833
* Method: socketClose0
834
* Signature: (Z)V
835
*/
836
JNIEXPORT void JNICALL
837
Java_java_net_PlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
838
jboolean useDeferredClose) {
839
840
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
841
jint fd;
842
843
if (IS_NULL(fdObj)) {
844
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
845
"socket already closed");
846
return;
847
} else {
848
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
849
}
850
if (fd != -1) {
851
if (useDeferredClose && marker_fd >= 0) {
852
NET_Dup2(marker_fd, fd);
853
} else {
854
(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
855
NET_SocketClose(fd);
856
}
857
}
858
}
859
860
/*
861
* Class: java_net_PlainSocketImpl
862
* Method: socketShutdown
863
* Signature: (I)V
864
*/
865
JNIEXPORT void JNICALL
866
Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
867
jint howto)
868
{
869
870
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
871
jint fd;
872
873
/*
874
* WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
875
* -1 already?
876
*/
877
if (IS_NULL(fdObj)) {
878
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
879
"socket already closed");
880
return;
881
} else {
882
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
883
}
884
JVM_SocketShutdown(fd, howto);
885
}
886
887
888
/*
889
* Class: java_net_PlainSocketImpl
890
* Method: socketSetOption0
891
* Signature: (IZLjava/lang/Object;)V
892
*/
893
JNIEXPORT void JNICALL
894
Java_java_net_PlainSocketImpl_socketSetOption0(JNIEnv *env, jobject this,
895
jint cmd, jboolean on,
896
jobject value) {
897
int fd;
898
int level, optname, optlen;
899
union {
900
int i;
901
struct linger ling;
902
} optval;
903
904
/*
905
* Check that socket hasn't been closed
906
*/
907
fd = getFD(env, this);
908
if (fd < 0) {
909
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
910
"Socket closed");
911
return;
912
}
913
914
/*
915
* SO_TIMEOUT is a NOOP on Solaris/Linux
916
*/
917
if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
918
return;
919
}
920
921
/*
922
* Map the Java level socket option to the platform specific
923
* level and option name.
924
*/
925
if (NET_MapSocketOption(cmd, &level, &optname)) {
926
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
927
return;
928
}
929
930
switch (cmd) {
931
case java_net_SocketOptions_SO_SNDBUF :
932
case java_net_SocketOptions_SO_RCVBUF :
933
case java_net_SocketOptions_SO_LINGER :
934
case java_net_SocketOptions_IP_TOS :
935
{
936
jclass cls;
937
jfieldID fid;
938
939
cls = (*env)->FindClass(env, "java/lang/Integer");
940
CHECK_NULL(cls);
941
fid = (*env)->GetFieldID(env, cls, "value", "I");
942
CHECK_NULL(fid);
943
944
if (cmd == java_net_SocketOptions_SO_LINGER) {
945
if (on) {
946
optval.ling.l_onoff = 1;
947
optval.ling.l_linger = (*env)->GetIntField(env, value, fid);
948
} else {
949
optval.ling.l_onoff = 0;
950
optval.ling.l_linger = 0;
951
}
952
optlen = sizeof(optval.ling);
953
} else {
954
optval.i = (*env)->GetIntField(env, value, fid);
955
optlen = sizeof(optval.i);
956
}
957
958
break;
959
}
960
961
/* Boolean -> int */
962
default :
963
optval.i = (on ? 1 : 0);
964
optlen = sizeof(optval.i);
965
966
}
967
968
if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
969
#if defined(__solaris__) || defined(_AIX)
970
if (errno == EINVAL) {
971
// On Solaris setsockopt will set errno to EINVAL if the socket
972
// is closed. The default error message is then confusing
973
char fullMsg[128];
974
jio_snprintf(fullMsg, sizeof(fullMsg), "Invalid option or socket reset by remote peer");
975
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);
976
return;
977
}
978
#endif /* __solaris__ */
979
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
980
"Error setting socket option");
981
}
982
}
983
984
/*
985
* Class: java_net_PlainSocketImpl
986
* Method: socketGetOption
987
* Signature: (I)I
988
*/
989
JNIEXPORT jint JNICALL
990
Java_java_net_PlainSocketImpl_socketGetOption(JNIEnv *env, jobject this,
991
jint cmd, jobject iaContainerObj) {
992
993
int fd;
994
int level, optname, optlen;
995
union {
996
int i;
997
struct linger ling;
998
} optval;
999
1000
/*
1001
* Check that socket hasn't been closed
1002
*/
1003
fd = getFD(env, this);
1004
if (fd < 0) {
1005
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1006
"Socket closed");
1007
return -1;
1008
}
1009
1010
/*
1011
* SO_BINDADDR isn't a socket option
1012
*/
1013
if (cmd == java_net_SocketOptions_SO_BINDADDR) {
1014
SOCKADDR him;
1015
socklen_t len = 0;
1016
int port;
1017
jobject iaObj;
1018
jclass iaCntrClass;
1019
jfieldID iaFieldID;
1020
1021
len = SOCKADDR_LEN;
1022
1023
if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) {
1024
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1025
"Error getting socket name");
1026
return -1;
1027
}
1028
iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
1029
CHECK_NULL_RETURN(iaObj, -1);
1030
1031
iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
1032
iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");
1033
CHECK_NULL_RETURN(iaFieldID, -1);
1034
(*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
1035
return 0; /* notice change from before */
1036
}
1037
1038
/*
1039
* Map the Java level socket option to the platform specific
1040
* level and option name.
1041
*/
1042
if (NET_MapSocketOption(cmd, &level, &optname)) {
1043
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1044
return -1;
1045
}
1046
1047
/*
1048
* Args are int except for SO_LINGER
1049
*/
1050
if (cmd == java_net_SocketOptions_SO_LINGER) {
1051
optlen = sizeof(optval.ling);
1052
} else {
1053
optlen = sizeof(optval.i);
1054
}
1055
1056
if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1057
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1058
"Error getting socket option");
1059
return -1;
1060
}
1061
1062
switch (cmd) {
1063
case java_net_SocketOptions_SO_LINGER:
1064
return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
1065
1066
case java_net_SocketOptions_SO_SNDBUF:
1067
case java_net_SocketOptions_SO_RCVBUF:
1068
case java_net_SocketOptions_IP_TOS:
1069
return optval.i;
1070
1071
default :
1072
return (optval.i == 0) ? -1 : 1;
1073
}
1074
}
1075
1076
1077
/*
1078
* Class: java_net_PlainSocketImpl
1079
* Method: socketSendUrgentData
1080
* Signature: (B)V
1081
*/
1082
JNIEXPORT void JNICALL
1083
Java_java_net_PlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
1084
jint data) {
1085
/* The fd field */
1086
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1087
int n, fd;
1088
unsigned char d = data & 0xFF;
1089
1090
if (IS_NULL(fdObj)) {
1091
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1092
return;
1093
} else {
1094
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1095
/* Bug 4086704 - If the Socket associated with this file descriptor
1096
* was closed (sysCloseFD), the the file descriptor is set to -1.
1097
*/
1098
if (fd == -1) {
1099
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1100
return;
1101
}
1102
1103
}
1104
n = JVM_Send(fd, (char *)&d, 1, MSG_OOB);
1105
if (n == JVM_IO_ERR) {
1106
NET_ThrowByNameWithLastError(env, "java/io/IOException", "Write failed");
1107
return;
1108
}
1109
if (n == JVM_IO_INTR) {
1110
JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
1111
return;
1112
}
1113
}
1114
1115