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