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/ExtendedOptionsImpl.c
32287 views
1
/*
2
* Copyright (c) 2014, 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 <jni.h>
27
#include <string.h>
28
#if defined(__linux__) || defined(MACOSX)
29
#include <netinet/tcp.h>
30
#include <netinet/in.h>
31
#endif
32
33
#include "net_util.h"
34
#include "jdk_net_SocketFlow.h"
35
36
static jclass sf_status_class; /* Status enum type */
37
38
static jfieldID sf_status;
39
static jfieldID sf_priority;
40
static jfieldID sf_bandwidth;
41
42
static jfieldID sf_fd_fdID; /* FileDescriptor.fd */
43
44
/* References to the literal enum values */
45
46
static jobject sfs_NOSTATUS;
47
static jobject sfs_OK;
48
static jobject sfs_NOPERMISSION;
49
static jobject sfs_NOTCONNECTED;
50
static jobject sfs_NOTSUPPORTED;
51
static jobject sfs_ALREADYCREATED;
52
static jobject sfs_INPROGRESS;
53
static jobject sfs_OTHER;
54
55
static jobject getEnumField(JNIEnv *env, char *name);
56
static void setStatus(JNIEnv *env, jobject obj, int errval);
57
58
/* OS specific code is implemented in these three functions */
59
60
static jboolean flowSupported0() ;
61
62
/*
63
* Class: sun_net_ExtendedOptionsImpl
64
* Method: init
65
* Signature: ()V
66
*/
67
JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init
68
(JNIEnv *env, jclass UNUSED) {
69
70
static int initialized = 0;
71
jclass c;
72
73
/* Global class references */
74
75
if (initialized) {
76
return;
77
}
78
79
c = (*env)->FindClass(env, "jdk/net/SocketFlow$Status");
80
CHECK_NULL(c);
81
sf_status_class = (*env)->NewGlobalRef(env, c);
82
CHECK_NULL(sf_status_class);
83
84
/* int "fd" field of java.io.FileDescriptor */
85
86
c = (*env)->FindClass(env, "java/io/FileDescriptor");
87
CHECK_NULL(c);
88
sf_fd_fdID = (*env)->GetFieldID(env, c, "fd", "I");
89
CHECK_NULL(sf_fd_fdID);
90
91
92
/* SocketFlow fields */
93
94
c = (*env)->FindClass(env, "jdk/net/SocketFlow");
95
CHECK_NULL(c);
96
97
/* status */
98
99
sf_status = (*env)->GetFieldID(env, c, "status",
100
"Ljdk/net/SocketFlow$Status;");
101
CHECK_NULL(sf_status);
102
103
/* priority */
104
105
sf_priority = (*env)->GetFieldID(env, c, "priority", "I");
106
CHECK_NULL(sf_priority);
107
108
/* bandwidth */
109
110
sf_bandwidth = (*env)->GetFieldID(env, c, "bandwidth", "J");
111
CHECK_NULL(sf_bandwidth);
112
113
/* Initialize the static enum values */
114
115
sfs_NOSTATUS = getEnumField(env, "NO_STATUS");
116
CHECK_NULL(sfs_NOSTATUS);
117
sfs_OK = getEnumField(env, "OK");
118
CHECK_NULL(sfs_OK);
119
sfs_NOPERMISSION = getEnumField(env, "NO_PERMISSION");
120
CHECK_NULL(sfs_NOPERMISSION);
121
sfs_NOTCONNECTED = getEnumField(env, "NOT_CONNECTED");
122
CHECK_NULL(sfs_NOTCONNECTED);
123
sfs_NOTSUPPORTED = getEnumField(env, "NOT_SUPPORTED");
124
CHECK_NULL(sfs_NOTSUPPORTED);
125
sfs_ALREADYCREATED = getEnumField(env, "ALREADY_CREATED");
126
CHECK_NULL(sfs_ALREADYCREATED);
127
sfs_INPROGRESS = getEnumField(env, "IN_PROGRESS");
128
CHECK_NULL(sfs_INPROGRESS);
129
sfs_OTHER = getEnumField(env, "OTHER");
130
CHECK_NULL(sfs_OTHER);
131
initialized = JNI_TRUE;
132
}
133
134
static jobject getEnumField(JNIEnv *env, char *name) {
135
jobject f;
136
jfieldID fID = (*env)->GetStaticFieldID(env, sf_status_class, name,
137
"Ljdk/net/SocketFlow$Status;");
138
CHECK_NULL_RETURN(fID, NULL);
139
140
f = (*env)->GetStaticObjectField(env, sf_status_class, fID);
141
CHECK_NULL_RETURN(f, NULL);
142
f = (*env)->NewGlobalRef(env, f);
143
CHECK_NULL_RETURN(f, NULL);
144
return f;
145
}
146
147
/*
148
* Retrieve the int file-descriptor from a public socket type object.
149
* Gets impl, then the FileDescriptor from the impl, and then the fd
150
* from that.
151
*/
152
static int getFD(JNIEnv *env, jobject fileDesc) {
153
return (*env)->GetIntField(env, fileDesc, sf_fd_fdID);
154
}
155
156
/**
157
* Sets the status field of a SocketFlow to one of the
158
* canned enum values
159
*/
160
static void setStatus (JNIEnv *env, jobject obj, int errval) {
161
switch (errval) {
162
case 0: /* OK */
163
(*env)->SetObjectField(env, obj, sf_status, sfs_OK);
164
break;
165
case EPERM:
166
(*env)->SetObjectField(env, obj, sf_status, sfs_NOPERMISSION);
167
break;
168
case ENOTCONN:
169
(*env)->SetObjectField(env, obj, sf_status, sfs_NOTCONNECTED);
170
break;
171
case EOPNOTSUPP:
172
(*env)->SetObjectField(env, obj, sf_status, sfs_NOTSUPPORTED);
173
break;
174
case EALREADY:
175
(*env)->SetObjectField(env, obj, sf_status, sfs_ALREADYCREATED);
176
break;
177
case EINPROGRESS:
178
(*env)->SetObjectField(env, obj, sf_status, sfs_INPROGRESS);
179
break;
180
default:
181
(*env)->SetObjectField(env, obj, sf_status, sfs_OTHER);
182
break;
183
}
184
}
185
186
#ifdef __solaris__
187
188
/*
189
* Class: sun_net_ExtendedOptionsImpl
190
* Method: setFlowOption
191
* Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V
192
*/
193
JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption
194
(JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) {
195
int fd = getFD(env, fileDesc);
196
197
if (fd < 0) {
198
NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed");
199
return;
200
} else {
201
sock_flow_props_t props;
202
jlong bandwidth;
203
int rv;
204
205
jint priority = (*env)->GetIntField(env, flow, sf_priority);
206
memset(&props, 0, sizeof(props));
207
props.sfp_version = SOCK_FLOW_PROP_VERSION1;
208
209
if (priority != jdk_net_SocketFlow_UNSET) {
210
props.sfp_mask |= SFP_PRIORITY;
211
props.sfp_priority = priority;
212
}
213
bandwidth = (*env)->GetLongField(env, flow, sf_bandwidth);
214
if (bandwidth > -1) {
215
props.sfp_mask |= SFP_MAXBW;
216
props.sfp_maxbw = (uint64_t) bandwidth;
217
}
218
rv = setsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props));
219
if (rv < 0) {
220
if (errno == ENOPROTOOPT) {
221
JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
222
"unsupported socket option");
223
} else if (errno == EACCES || errno == EPERM) {
224
NET_ERROR(env, JNU_JAVANETPKG "SocketException",
225
"Permission denied");
226
} else {
227
NET_ERROR(env, JNU_JAVANETPKG "SocketException",
228
"set option SO_FLOW_SLA failed");
229
}
230
return;
231
}
232
setStatus(env, flow, props.sfp_status);
233
}
234
}
235
236
/*
237
* Class: sun_net_ExtendedOptionsImpl
238
* Method: getFlowOption
239
* Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V
240
*/
241
JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption
242
(JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) {
243
int fd = getFD(env, fileDesc);
244
245
if (fd < 0) {
246
NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed");
247
return;
248
} else {
249
sock_flow_props_t props;
250
int status;
251
socklen_t sz = sizeof(props);
252
253
int rv = getsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, &sz);
254
if (rv < 0) {
255
if (errno == ENOPROTOOPT) {
256
JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
257
"unsupported socket option");
258
} else if (errno == EACCES || errno == EPERM) {
259
NET_ERROR(env, JNU_JAVANETPKG "SocketException",
260
"Permission denied");
261
} else {
262
NET_ERROR(env, JNU_JAVANETPKG "SocketException",
263
"set option SO_FLOW_SLA failed");
264
}
265
return;
266
}
267
/* first check status to see if flow exists */
268
status = props.sfp_status;
269
setStatus(env, flow, status);
270
if (status == 0) { /* OK */
271
/* can set the other fields now */
272
if (props.sfp_mask & SFP_PRIORITY) {
273
(*env)->SetIntField(env, flow, sf_priority, props.sfp_priority);
274
}
275
if (props.sfp_mask & SFP_MAXBW) {
276
(*env)->SetLongField(env, flow, sf_bandwidth,
277
(jlong)props.sfp_maxbw);
278
}
279
}
280
}
281
}
282
283
static jboolean flowsupported;
284
static jboolean flowsupported_set = JNI_FALSE;
285
286
static jboolean flowSupported0() {
287
/* Do a simple dummy call, and try to figure out from that */
288
sock_flow_props_t props;
289
int rv, s;
290
if (flowsupported_set) {
291
return flowsupported;
292
}
293
s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
294
if (s < 0) {
295
flowsupported = JNI_FALSE;
296
flowsupported_set = JNI_TRUE;
297
return JNI_FALSE;
298
}
299
memset(&props, 0, sizeof(props));
300
props.sfp_version = SOCK_FLOW_PROP_VERSION1;
301
props.sfp_mask |= SFP_PRIORITY;
302
props.sfp_priority = SFP_PRIO_NORMAL;
303
rv = setsockopt(s, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props));
304
if (rv != 0 && errno == ENOPROTOOPT) {
305
rv = JNI_FALSE;
306
} else {
307
rv = JNI_TRUE;
308
}
309
close(s);
310
flowsupported = rv;
311
flowsupported_set = JNI_TRUE;
312
return flowsupported;
313
}
314
315
#else /* __solaris__ */
316
317
/* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */
318
319
JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption
320
(JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) {
321
JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
322
"unsupported socket option");
323
}
324
325
JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption
326
(JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) {
327
JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
328
"unsupported socket option");
329
}
330
331
static jboolean flowSupported0() {
332
return JNI_FALSE;
333
}
334
335
#endif /* __solaris__ */
336
337
// Keep alive options are available for MACOSX and Linux only for
338
// the time being.
339
#if defined(__linux__) || defined(MACOSX)
340
341
// Map socket option level/name to OS specific constant
342
#ifdef __linux__
343
#define SOCK_OPT_LEVEL SOL_TCP
344
#define SOCK_OPT_NAME_KEEPIDLE TCP_KEEPIDLE
345
#define SOCK_OPT_NAME_KEEPIDLE_STR "TCP_KEEPIDLE"
346
#endif
347
#ifdef MACOSX
348
#define SOCK_OPT_LEVEL IPPROTO_TCP
349
#define SOCK_OPT_NAME_KEEPIDLE TCP_KEEPALIVE
350
#define SOCK_OPT_NAME_KEEPIDLE_STR "TCP_KEEPALIVE"
351
#endif
352
353
static jint socketOptionSupported(jint sockopt) {
354
jint one = 1;
355
jint rv, s;
356
s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
357
if (s < 0) {
358
return 0;
359
}
360
rv = setsockopt(s, SOCK_OPT_LEVEL, sockopt, (void *) &one, sizeof (one));
361
if (rv != 0 && errno == ENOPROTOOPT) {
362
rv = 0;
363
} else {
364
rv = 1;
365
}
366
close(s);
367
return rv;
368
}
369
370
static void handleError(JNIEnv *env, jint rv, const char *errmsg) {
371
if (rv < 0) {
372
if (errno == ENOPROTOOPT) {
373
JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
374
"unsupported socket option");
375
} else {
376
JNU_ThrowByNameWithLastError(env, "java/net/SocketException", errmsg);
377
}
378
}
379
}
380
381
static void setTcpSocketOption
382
(JNIEnv *env, jobject fileDesc, jint optval, int opt, int optlevel, const char* errmsg) {
383
int fd = getFD(env, fileDesc);
384
385
if (fd < 0) {
386
NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed");
387
return;
388
} else {
389
jint rv = setsockopt(fd, optlevel, opt, &optval, sizeof (optval));
390
handleError(env, rv, errmsg);
391
}
392
}
393
394
static jint getTcpSocketOption
395
(JNIEnv *env, jobject fileDesc, int opt, int optlevel, const char* errmsg) {
396
int fd = getFD(env, fileDesc);
397
398
if (fd < 0) {
399
NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed");
400
return -1;
401
} else {
402
jint optval, rv;
403
socklen_t sz = sizeof (optval);
404
rv = getsockopt(fd, optlevel, opt, &optval, &sz);
405
handleError(env, rv, errmsg);
406
return optval;
407
}
408
}
409
410
#else /* __linux__ || MACOSX */
411
412
// On AIX and Solaris these constants aren't defined. Map them to a
413
// value so that the code below compiles. Values aren't used as
414
// on those platforms UnsupportedOperationException will be thrown
415
// instead.
416
#define SOCK_OPT_LEVEL -1
417
#define SOCK_OPT_NAME_KEEPIDLE -1
418
#define SOCK_OPT_NAME_KEEPIDLE_STR "TCP_KEEPIDLE"
419
#define TCP_KEEPCNT -1
420
#define TCP_KEEPINTVL -1
421
#define SOCK_OPT_LEVEL -1
422
#define SOCK_OPT_NAME_KEEPIDLE -1
423
424
/* Keep alive options not supported for non-linux/non-macosx so throw UnsupportedOpExc */
425
426
static void setTcpSocketOption
427
(JNIEnv *env, jobject fileDesc, jint optval, int opt, int optlevel, const char* errmsg) {
428
JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
429
"unsupported socket option");
430
}
431
432
static jint getTcpSocketOption
433
(JNIEnv *env, jobject fileDesc, int opt, int optlevel, const char* errmsg) {
434
JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
435
"unsupported socket option");
436
}
437
438
#endif /* __linux__ || MACOSX*/
439
440
JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported
441
(JNIEnv *env, jclass UNUSED) {
442
return flowSupported0();
443
}
444
445
#if defined(__linux__) || defined(MACOSX)
446
447
/*
448
* Class: sun_net_ExtendedOptionsImpl
449
* Method: keepAliveOptionsSupported
450
* Signature: ()Z
451
*/
452
JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_keepAliveOptionsSupported
453
(JNIEnv *env, jobject unused) {
454
return socketOptionSupported(SOCK_OPT_NAME_KEEPIDLE) && socketOptionSupported(TCP_KEEPCNT)
455
&& socketOptionSupported(TCP_KEEPINTVL);
456
}
457
458
#else
459
460
/*
461
* Class: sun_net_ExtendedOptionsImpl
462
* Method: keepAliveOptionsSupported
463
* Signature: ()Z
464
*/
465
JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_keepAliveOptionsSupported
466
(JNIEnv *env, jobject unused) {
467
return JNI_FALSE;
468
}
469
470
#endif /* __linux__ || MACOSX */
471
472
/*
473
* Class: sun_net_ExtendedOptionsImpl
474
* Method: setTcpKeepAliveProbes
475
* Signature: (Ljava/io/FileDescriptor;I)V
476
*/
477
JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setTcpKeepAliveProbes
478
(JNIEnv *env, jobject unused, jobject fileDesc, jint optval) {
479
setTcpSocketOption(env, fileDesc, optval, TCP_KEEPCNT, SOCK_OPT_LEVEL,
480
"set option TCP_KEEPCNT failed");
481
}
482
483
/*
484
* Class: sun_net_ExtendedOptionsImpl
485
* Method: setTcpKeepAliveTime
486
* Signature: (Ljava/io/FileDescriptor;I)V
487
*/
488
JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setTcpKeepAliveTime
489
(JNIEnv *env, jobject unused, jobject fileDesc, jint optval) {
490
setTcpSocketOption(env, fileDesc, optval, SOCK_OPT_NAME_KEEPIDLE, SOCK_OPT_LEVEL,
491
"set option " SOCK_OPT_NAME_KEEPIDLE_STR " failed");
492
}
493
494
/*
495
* Class: sun_net_ExtendedOptionsImpl
496
* Method: setTcpKeepAliveIntvl
497
* Signature: (Ljava/io/FileDescriptor;I)V
498
*/
499
JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setTcpKeepAliveIntvl
500
(JNIEnv *env, jobject unused, jobject fileDesc, jint optval) {
501
setTcpSocketOption(env, fileDesc, optval, TCP_KEEPINTVL, SOCK_OPT_LEVEL,
502
"set option TCP_KEEPINTVL failed");
503
}
504
505
/*
506
* Class: sun_net_ExtendedOptionsImpl
507
* Method: getTcpKeepAliveProbes
508
* Signature: (Ljava/io/FileDescriptor;)I
509
*/
510
JNIEXPORT jint JNICALL Java_sun_net_ExtendedOptionsImpl_getTcpKeepAliveProbes
511
(JNIEnv *env, jobject unused, jobject fileDesc) {
512
return getTcpSocketOption(env, fileDesc, TCP_KEEPCNT, SOCK_OPT_LEVEL,
513
"get option TCP_KEEPCNT failed");
514
}
515
516
/*
517
* Class: sun_net_ExtendedOptionsImpl
518
* Method: getTcpKeepAliveTime
519
* Signature: (Ljava/io/FileDescriptor;)I
520
*/
521
JNIEXPORT jint JNICALL Java_sun_net_ExtendedOptionsImpl_getTcpKeepAliveTime
522
(JNIEnv *env, jobject unused, jobject fileDesc) {
523
return getTcpSocketOption(env, fileDesc, SOCK_OPT_NAME_KEEPIDLE, SOCK_OPT_LEVEL,
524
"get option " SOCK_OPT_NAME_KEEPIDLE_STR " failed");
525
}
526
527
/*
528
* Class: sun_net_ExtendedOptionsImpl
529
* Method: getTcpKeepAliveIntvl
530
* Signature: (Ljava/io/FileDescriptor;)I
531
*/
532
JNIEXPORT jint JNICALL Java_sun_net_ExtendedOptionsImpl_getTcpKeepAliveIntvl
533
(JNIEnv *env, jobject unused, jobject fileDesc) {
534
return getTcpSocketOption(env, fileDesc, TCP_KEEPINTVL, SOCK_OPT_LEVEL,
535
"get option TCP_KEEPINTVL failed");
536
}
537
538