1 /*
2 * Copyright (c) 2009, 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
26 #include <stdlib.h>
27 #include <string.h>
28 #include <dlfcn.h>
29
30 #include "Sctp.h"
31 #include "jni.h"
32 #include "jni_util.h"
33 #include "nio_util.h"
34 #include "nio.h"
35 #include "net_util.h"
36 #include "net_util_md.h"
37 #include "sun_nio_ch_sctp_SctpNet.h"
38 #include "sun_nio_ch_sctp_SctpStdSocketOption.h"
39
40 static jclass isaCls = 0;
41 static jmethodID isaCtrID = 0;
42
43 static const char* nativeSctpLib = "libsctp.so.1";
44 static jboolean funcsLoaded = JNI_FALSE;
45
46 #ifndef __FreeBSD__
47 sctp_getladdrs_func* nio_sctp_getladdrs;
48 sctp_freeladdrs_func* nio_sctp_freeladdrs;
49 sctp_getpaddrs_func* nio_sctp_getpaddrs;
50 sctp_freepaddrs_func* nio_sctp_freepaddrs;
51 sctp_bindx_func* nio_sctp_bindx;
52 sctp_peeloff_func* nio_sctp_peeloff;
53 #endif
54
DEF_JNI_OnLoad(JavaVM * vm,void * reserved)55 JNIEXPORT jint JNICALL DEF_JNI_OnLoad
56 (JavaVM *vm, void *reserved) {
57 return JNI_VERSION_1_2;
58 }
59
60 static int preCloseFD = -1; /* File descriptor to which we dup other fd's
61 before closing them for real */
62
63 /**
64 * Loads the native sctp library that contains the socket extension
65 * functions, as well as locating the individual functions.
66 * There will be a pending exception if this method returns false.
67 */
loadSocketExtensionFuncs(JNIEnv * env)68 jboolean loadSocketExtensionFuncs
69 (JNIEnv* env) {
70 #ifndef __FreeBSD__
71 if (dlopen(nativeSctpLib, RTLD_GLOBAL | RTLD_LAZY) == NULL) {
72 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
73 dlerror());
74 return JNI_FALSE;
75 }
76
77 if ((nio_sctp_getladdrs = (sctp_getladdrs_func*)
78 dlsym(RTLD_DEFAULT, "sctp_getladdrs")) == NULL) {
79 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
80 dlerror());
81 return JNI_FALSE;
82 }
83
84 if ((nio_sctp_freeladdrs = (sctp_freeladdrs_func*)
85 dlsym(RTLD_DEFAULT, "sctp_freeladdrs")) == NULL) {
86 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
87 dlerror());
88 return JNI_FALSE;
89 }
90
91 if ((nio_sctp_getpaddrs = (sctp_getpaddrs_func*)
92 dlsym(RTLD_DEFAULT, "sctp_getpaddrs")) == NULL) {
93 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
94 dlerror());
95 return JNI_FALSE;
96 }
97
98 if ((nio_sctp_freepaddrs = (sctp_freepaddrs_func*)
99 dlsym(RTLD_DEFAULT, "sctp_freepaddrs")) == NULL) {
100 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
101 dlerror());
102 return JNI_FALSE;
103 }
104
105 if ((nio_sctp_bindx = (sctp_bindx_func*)
106 dlsym(RTLD_DEFAULT, "sctp_bindx")) == NULL) {
107 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
108 dlerror());
109 return JNI_FALSE;
110 }
111
112 if ((nio_sctp_peeloff = (sctp_peeloff_func*)
113 dlsym(RTLD_DEFAULT, "sctp_peeloff")) == NULL) {
114 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
115 dlerror());
116 return JNI_FALSE;
117 }
118 #endif
119
120 funcsLoaded = JNI_TRUE;
121 return JNI_TRUE;
122 }
123
124 jint
handleSocketError(JNIEnv * env,jint errorValue)125 handleSocketError(JNIEnv *env, jint errorValue)
126 {
127 char *xn;
128 switch (errorValue) {
129 case EINPROGRESS: /* Non-blocking connect */
130 return 0;
131 case EPROTO:
132 xn= JNU_JAVANETPKG "ProtocolException";
133 break;
134 case ECONNREFUSED:
135 xn = JNU_JAVANETPKG "ConnectException";
136 break;
137 case ETIMEDOUT:
138 xn = JNU_JAVANETPKG "ConnectException";
139 break;
140 case EHOSTUNREACH:
141 xn = JNU_JAVANETPKG "NoRouteToHostException";
142 break;
143 case EADDRINUSE: /* Fall through */
144 case EADDRNOTAVAIL:
145 xn = JNU_JAVANETPKG "BindException";
146 break;
147 default:
148 xn = JNU_JAVANETPKG "SocketException";
149 break;
150 }
151 errno = errorValue;
152 JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
153 return IOS_THROWN;
154 }
155
156 /*
157 * Class: sun_nio_ch_sctp_SctpNet
158 * Method: init
159 * Signature: ()V
160 */
161 JNIEXPORT void JNICALL
Java_sun_nio_ch_sctp_SctpNet_init(JNIEnv * env,jclass cl)162 Java_sun_nio_ch_sctp_SctpNet_init
163 (JNIEnv *env, jclass cl) {
164 int sp[2];
165 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
166 JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
167 return;
168 }
169 preCloseFD = sp[0];
170 close(sp[1]);
171 initInetAddressIDs(env);
172 }
173
174 /*
175 * Class: sun_nio_ch_sctp_SctpNet
176 * Method: socket0
177 * Signature: (Z)I
178 */
Java_sun_nio_ch_sctp_SctpNet_socket0(JNIEnv * env,jclass klass,jboolean oneToOne)179 JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpNet_socket0
180 (JNIEnv *env, jclass klass, jboolean oneToOne) {
181 int fd;
182 struct sctp_event_subscribe event;
183 #ifdef AF_INET6
184 int domain = ipv6_available() ? AF_INET6 : AF_INET;
185 #else
186 int domain = AF_INET;
187 #endif
188
189 /* Try to load the socket API extension functions */
190 if (!funcsLoaded && !loadSocketExtensionFuncs(env)) {
191 return 0;
192 }
193
194 fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP);
195
196 if (fd < 0) {
197 return handleSocketError(env, errno);
198 }
199
200 /* Enable events */
201 memset(&event, 0, sizeof(event));
202 event.sctp_data_io_event = 1;
203 event.sctp_association_event = 1;
204 event.sctp_address_event = 1;
205 event.sctp_send_failure_event = 1;
206 //event.sctp_peer_error_event = 1;
207 event.sctp_shutdown_event = 1;
208 //event.sctp_partial_delivery_event = 1;
209 //event.sctp_adaptation_layer_event = 1;
210 if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) {
211 handleSocketError(env, errno);
212 }
213 return fd;
214 }
215
216 /*
217 * Class: sun_nio_ch_sctp_SctpNet
218 * Method: bindx
219 * Signature: (I[Ljava/net/InetAddress;IIZ)V
220 */
Java_sun_nio_ch_sctp_SctpNet_bindx(JNIEnv * env,jclass klass,jint fd,jobjectArray addrs,jint port,jint addrsLength,jboolean add,jboolean preferIPv6)221 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_bindx
222 (JNIEnv *env, jclass klass, jint fd, jobjectArray addrs, jint port,
223 jint addrsLength, jboolean add, jboolean preferIPv6) {
224 SOCKETADDRESS *sap, *tmpSap;
225 int i;
226 jobject ia;
227
228 if (addrsLength < 1)
229 return;
230
231 if ((sap = calloc(addrsLength, sizeof(SOCKETADDRESS))) == NULL) {
232 JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
233 return;
234 }
235
236 tmpSap = sap;
237 for (i = 0; i < addrsLength; i++) {
238 ia = (*env)->GetObjectArrayElement(env, addrs, i);
239 if (NET_InetAddressToSockaddr(env, ia, port, tmpSap, NULL,
240 preferIPv6) != 0) {
241 free(sap);
242 return;
243 }
244 tmpSap++;
245 }
246
247 if (nio_sctp_bindx(fd, (void *)sap, addrsLength, add ? SCTP_BINDX_ADD_ADDR :
248 SCTP_BINDX_REM_ADDR) != 0) {
249 handleSocketError(env, errno);
250 }
251
252 free(sap);
253 }
254
255 /*
256 * Class: sun_nio_ch_sctp_SctpNet
257 * Method: listen0
258 * Signature: (II)V
259 */
260 JNIEXPORT void JNICALL
Java_sun_nio_ch_sctp_SctpNet_listen0(JNIEnv * env,jclass cl,jint fd,jint backlog)261 Java_sun_nio_ch_sctp_SctpNet_listen0
262 (JNIEnv *env, jclass cl, jint fd, jint backlog) {
263 if (listen(fd, backlog) < 0)
264 handleSocketError(env, errno);
265 }
266
267 /*
268 * Class: sun_nio_ch_sctp_SctpNet
269 * Method: connect0
270 * Signature: (ILjava/net/InetAddress;I)I
271 */
272 JNIEXPORT jint JNICALL
Java_sun_nio_ch_sctp_SctpNet_connect0(JNIEnv * env,jclass clazz,int fd,jobject iao,jint port)273 Java_sun_nio_ch_sctp_SctpNet_connect0
274 (JNIEnv *env, jclass clazz, int fd, jobject iao, jint port) {
275 SOCKETADDRESS sa;
276 int sa_len = 0;
277 int rv;
278
279 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,
280 JNI_TRUE) != 0) {
281 return IOS_THROWN;
282 }
283
284 rv = connect(fd, &sa.sa, sa_len);
285 if (rv != 0) {
286 if (errno == EINPROGRESS) {
287 return IOS_UNAVAILABLE;
288 } else if (errno == EINTR) {
289 return IOS_INTERRUPTED;
290 }
291 return handleSocketError(env, errno);
292 }
293 return 1;
294 }
295
296 /*
297 * Class: sun_nio_ch_sctp_SctpNet
298 * Method: close0
299 * Signature: (I)V
300 */
301 JNIEXPORT void JNICALL
Java_sun_nio_ch_sctp_SctpNet_close0(JNIEnv * env,jclass clazz,jint fd)302 Java_sun_nio_ch_sctp_SctpNet_close0
303 (JNIEnv *env, jclass clazz, jint fd) {
304 if (fd != -1) {
305 int rv = close(fd);
306 if (rv < 0)
307 JNU_ThrowIOExceptionWithLastError(env, "Close failed");
308 }
309 }
310
311 /*
312 * Class: sun_nio_ch_sctp_SctpNet
313 * Method: preClose0
314 * Signature: (I)V
315 */
316 JNIEXPORT void JNICALL
Java_sun_nio_ch_sctp_SctpNet_preClose0(JNIEnv * env,jclass clazz,jint fd)317 Java_sun_nio_ch_sctp_SctpNet_preClose0
318 (JNIEnv *env, jclass clazz, jint fd) {
319 if (preCloseFD >= 0) {
320 if (dup2(preCloseFD, fd) < 0)
321 JNU_ThrowIOExceptionWithLastError(env, "dup2 failed");
322 }
323 }
324
initializeISA(JNIEnv * env)325 void initializeISA(JNIEnv* env) {
326 if (isaCls == 0) {
327 jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress");
328 CHECK_NULL(c);
329 isaCtrID = (*env)->GetMethodID(env, c, "<init>",
330 "(Ljava/net/InetAddress;I)V");
331 CHECK_NULL(isaCtrID);
332 isaCls = (*env)->NewGlobalRef(env, c);
333 CHECK_NULL(isaCls);
334 (*env)->DeleteLocalRef(env, c);
335 }
336 }
337
SockAddrToInetSocketAddress(JNIEnv * env,SOCKETADDRESS * sap)338 jobject SockAddrToInetSocketAddress(JNIEnv *env, SOCKETADDRESS *sap) {
339 int port = 0;
340
341 jobject ia = NET_SockaddrToInetAddress(env, sap, &port);
342 if (ia == NULL)
343 return NULL;
344
345 if (isaCls == 0) {
346 initializeISA(env);
347 CHECK_NULL_RETURN(isaCls, NULL);
348 }
349
350 return (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
351 }
352
353 /*
354 * Class: sun_nio_ch_sctp_SctpNet
355 * Method: getLocalAddresses0
356 * Signature: (I)[Ljava/net/SocketAddress;
357 */
Java_sun_nio_ch_sctp_SctpNet_getLocalAddresses0(JNIEnv * env,jclass klass,jint fd)358 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_sctp_SctpNet_getLocalAddresses0
359 (JNIEnv *env, jclass klass, jint fd)
360 {
361 void *addr_buf, *laddr;
362 int i, addrCount;
363 jobjectArray isaa;
364
365 if ((addrCount = nio_sctp_getladdrs(fd, 0, (struct sockaddr **)&addr_buf)) == -1) {
366 handleSocketError(env, errno);
367 return NULL;
368 }
369
370 if (addrCount < 1)
371 return NULL;
372
373 if (isaCls == 0) {
374 initializeISA(env);
375 CHECK_NULL_RETURN(isaCls, NULL);
376 }
377
378 isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
379 if (isaa == NULL) {
380 nio_sctp_freeladdrs(addr_buf);
381 return NULL;
382 }
383
384 laddr = addr_buf;
385 for (i = 0; i < addrCount; i++) {
386 int port = 0;
387 jobject ia, isa = NULL;
388 ia = NET_SockaddrToInetAddress(env, (SOCKETADDRESS *)addr_buf, &port);
389 if (ia != NULL)
390 isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
391 if (isa == NULL)
392 break;
393 (*env)->SetObjectArrayElement(env, isaa, i, isa);
394
395 if (((struct sockaddr *)addr_buf)->sa_family == AF_INET)
396 addr_buf = ((struct sockaddr_in *)addr_buf) + 1;
397 else
398 addr_buf = ((struct sockaddr_in6 *)addr_buf) + 1;
399 }
400
401 nio_sctp_freeladdrs(laddr);
402 return isaa;
403 }
404
getRemoteAddresses(JNIEnv * env,jint fd,sctp_assoc_t id)405 jobjectArray getRemoteAddresses(JNIEnv *env, jint fd, sctp_assoc_t id) {
406 void *addr_buf, *paddr;
407 int i, addrCount;
408 jobjectArray isaa;
409
410 if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr **)&addr_buf)) == -1) {
411 handleSocketError(env, errno);
412 return NULL;
413 }
414
415 if (addrCount < 1)
416 return NULL;
417
418 if (isaCls == 0) {
419 initializeISA(env);
420 CHECK_NULL_RETURN(isaCls, NULL);
421 }
422
423 isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
424 if (isaa == NULL) {
425 nio_sctp_freepaddrs(addr_buf);
426 return NULL;
427 }
428
429 paddr = addr_buf;
430 for (i = 0; i < addrCount; i++) {
431 int port = 0;
432 jobject ia, isa = NULL;
433 ia = NET_SockaddrToInetAddress(env, (SOCKETADDRESS *)addr_buf, &port);
434 if (ia != NULL)
435 isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
436 if (isa == NULL)
437 break;
438 (*env)->SetObjectArrayElement(env, isaa, i, isa);
439
440 if (((struct sockaddr *)addr_buf)->sa_family == AF_INET)
441 addr_buf = ((struct sockaddr_in *)addr_buf) + 1;
442 else
443 addr_buf = ((struct sockaddr_in6 *)addr_buf) + 1;
444 }
445
446 nio_sctp_freepaddrs(paddr);
447 return isaa;
448 }
449
450 /*
451 * Class: sun_nio_ch_sctp_SctpNet
452 * Method: getRemoteAddresses0
453 * Signature: (II)[Ljava/net/SocketAddress;
454 */
Java_sun_nio_ch_sctp_SctpNet_getRemoteAddresses0(JNIEnv * env,jclass klass,jint fd,jint assocId)455 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_sctp_SctpNet_getRemoteAddresses0
456 (JNIEnv *env, jclass klass, jint fd, jint assocId) {
457 return getRemoteAddresses(env, fd, assocId);
458 }
459
460 /* Map the Java level option to the native level */
mapSocketOption(jint cmd,int * level,int * optname)461 int mapSocketOption
462 (jint cmd, int *level, int *optname) {
463 static struct {
464 jint cmd;
465 int level;
466 int optname;
467 } const opts[] = {
468 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_DISABLE_FRAGMENTS, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS },
469 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_EXPLICIT_COMPLETE, IPPROTO_SCTP, SCTP_EXPLICIT_EOR },
470 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_FRAGMENT_INTERLEAVE, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE },
471 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_NODELAY, IPPROTO_SCTP, SCTP_NODELAY },
472 { sun_nio_ch_sctp_SctpStdSocketOption_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF },
473 { sun_nio_ch_sctp_SctpStdSocketOption_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF },
474 { sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER, SOL_SOCKET, SO_LINGER } };
475
476 int i;
477 for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
478 if (cmd == opts[i].cmd) {
479 *level = opts[i].level;
480 *optname = opts[i].optname;
481 return 0;
482 }
483 }
484
485 /* not found */
486 return -1;
487 }
488
489 /*
490 * Class: sun_nio_ch_sctp_SctpNet
491 * Method: setIntOption0
492 * Signature: (III)V
493 */
Java_sun_nio_ch_sctp_SctpNet_setIntOption0(JNIEnv * env,jclass klass,jint fd,jint opt,int arg)494 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setIntOption0
495 (JNIEnv *env, jclass klass, jint fd, jint opt, int arg) {
496 int klevel, kopt;
497 int result;
498 struct linger linger;
499 void *parg;
500 int arglen;
501
502 if (mapSocketOption(opt, &klevel, &kopt) < 0) {
503 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
504 "Unsupported socket option");
505 return;
506 }
507
508 if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER) {
509 parg = (void *)&linger;
510 arglen = sizeof(linger);
511 if (arg >= 0) {
512 linger.l_onoff = 1;
513 linger.l_linger = arg;
514 } else {
515 linger.l_onoff = 0;
516 linger.l_linger = 0;
517 }
518 } else {
519 parg = (void *)&arg;
520 arglen = sizeof(arg);
521 }
522
523 if (NET_SetSockOpt(fd, klevel, kopt, parg, arglen) < 0) {
524 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
525 "sun_nio_ch_sctp_SctpNet.setIntOption0");
526 }
527 }
528
529 /*
530 * Class: sun_nio_ch_sctp_SctpNet
531 * Method: getIntOption0
532 * Signature: (II)I
533 */
Java_sun_nio_ch_sctp_SctpNet_getIntOption0(JNIEnv * env,jclass klass,jint fd,jint opt)534 JNIEXPORT int JNICALL Java_sun_nio_ch_sctp_SctpNet_getIntOption0
535 (JNIEnv *env, jclass klass, jint fd, jint opt) {
536 int klevel, kopt;
537 int result;
538 struct linger linger;
539 void *arg;
540 int arglen;
541
542 memset((char *) &linger, 0, sizeof(linger));
543 if (mapSocketOption(opt, &klevel, &kopt) < 0) {
544 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
545 "Unsupported socket option");
546 return -1;
547 }
548
549 if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER) {
550 arg = (void *)&linger;
551 arglen = sizeof(linger);
552 } else {
553 arg = (void *)&result;
554 arglen = sizeof(result);
555 }
556
557 if (NET_GetSockOpt(fd, klevel, kopt, arg, &arglen) < 0) {
558 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
559 "sun.nio.ch.Net.getIntOption");
560 return -1;
561 }
562
563 if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER)
564 return linger.l_onoff ? linger.l_linger : -1;
565 else
566 return result;
567 }
568
569 /*
570 * Class: sun_nio_ch_sctp_SctpNet
571 * Method: getPrimAddrOption0
572 * Signature: (II)Ljava/net/SocketAddress;
573 */
Java_sun_nio_ch_sctp_SctpNet_getPrimAddrOption0(JNIEnv * env,jclass klass,jint fd,jint assocId)574 JNIEXPORT jobject JNICALL Java_sun_nio_ch_sctp_SctpNet_getPrimAddrOption0
575 (JNIEnv *env, jclass klass, jint fd, jint assocId) {
576 struct sctp_setprim prim;
577 unsigned int prim_len = sizeof(prim);
578
579 prim.ssp_assoc_id = assocId;
580
581 if (getsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, &prim_len) < 0) {
582 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
583 "sun.nio.ch.SctpNet.getPrimAddrOption0");
584 return NULL;
585 }
586
587 return SockAddrToInetSocketAddress(env, (SOCKETADDRESS *)&prim.ssp_addr);
588 }
589
590 /*
591 * Class: sun_nio_ch_sctp_SctpNet
592 * Method: setPrimAddrOption0
593 * Signature: (IILjava/net/InetAddress;I)V
594 */
Java_sun_nio_ch_sctp_SctpNet_setPrimAddrOption0(JNIEnv * env,jclass klass,jint fd,jint assocId,jobject iaObj,jint port)595 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPrimAddrOption0
596 (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) {
597 struct sctp_setprim prim;
598
599 if (NET_InetAddressToSockaddr(env, iaObj, port,
600 (SOCKETADDRESS *)&prim.ssp_addr,
601 NULL, JNI_TRUE) != 0) {
602 return;
603 }
604
605 prim.ssp_assoc_id = assocId;
606
607 if (setsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, sizeof(prim)) < 0) {
608 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
609 "sun.nio.ch.SctpNet.setPrimAddrOption0");
610 }
611 }
612
613 /*
614 * Class: sun_nio_ch_sctp_SctpNet
615 * Method: setPeerPrimAddrOption0
616 * Signature: (IILjava/net/InetAddress;I)V
617 */
Java_sun_nio_ch_sctp_SctpNet_setPeerPrimAddrOption0(JNIEnv * env,jclass klass,jint fd,jint assocId,jobject iaObj,jint port,jboolean preferIPv6)618 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPeerPrimAddrOption0
619 (JNIEnv *env, jclass klass, jint fd, jint assocId,
620 jobject iaObj, jint port, jboolean preferIPv6) {
621 struct sctp_setpeerprim prim;
622
623 if (NET_InetAddressToSockaddr(env, iaObj, port,
624 (SOCKETADDRESS *)&prim.sspp_addr,
625 NULL, preferIPv6) != 0) {
626 return;
627 }
628
629 prim.sspp_assoc_id = assocId;
630
631 if (setsockopt(fd, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR, &prim,
632 sizeof(prim)) < 0) {
633 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
634 "sun.nio.ch.SctpNet.setPeerPrimAddrOption0");
635 }
636 }
637
638 /*
639 * Class: sun_nio_ch_sctp_SctpNet
640 * Method: getInitMsgOption0
641 * Signature: (I[I)V
642 */
Java_sun_nio_ch_sctp_SctpNet_getInitMsgOption0(JNIEnv * env,jclass klass,jint fd,jintArray retVal)643 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_getInitMsgOption0
644 (JNIEnv *env, jclass klass, jint fd, jintArray retVal) {
645 struct sctp_initmsg sctp_initmsg;
646 unsigned int sim_len = sizeof(sctp_initmsg);
647 int vals[2];
648
649 if (getsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
650 &sim_len) < 0) {
651 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
652 "sun.nio.ch.SctpNet.getInitMsgOption0");
653 return;
654 }
655
656 vals[0] = sctp_initmsg.sinit_max_instreams;
657 vals[1] = sctp_initmsg.sinit_num_ostreams;
658 (*env)->SetIntArrayRegion(env, retVal, 0, 2, vals);
659 }
660
661 /*
662 * Class: sun_nio_ch_sctp_SctpNet
663 * Method: setInitMsgOption0
664 * Signature: (III)V
665 */
Java_sun_nio_ch_sctp_SctpNet_setInitMsgOption0(JNIEnv * env,jclass klass,jint fd,jint inArg,jint outArg)666 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setInitMsgOption0
667 (JNIEnv *env, jclass klass, jint fd, jint inArg, jint outArg) {
668 struct sctp_initmsg sctp_initmsg;
669
670 sctp_initmsg.sinit_max_instreams = (unsigned int)inArg;
671 sctp_initmsg.sinit_num_ostreams = (unsigned int)outArg;
672 sctp_initmsg.sinit_max_attempts = 0; // default
673 sctp_initmsg.sinit_max_init_timeo = 0; // default
674
675 if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
676 sizeof(sctp_initmsg)) < 0) {
677 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
678 "sun.nio.ch.SctpNet.setInitMsgOption0");
679 }
680 }
681
682 /*
683 * Class: sun_nio_ch_sctp_SctpNet
684 * Method: shutdown0
685 * Signature: (II)V
686 */
Java_sun_nio_ch_sctp_SctpNet_shutdown0(JNIEnv * env,jclass klass,jint fd,jint assocId)687 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_shutdown0
688 (JNIEnv *env, jclass klass, jint fd, jint assocId) {
689 int rv;
690 struct msghdr msg[1];
691 struct iovec iov[1];
692 int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo));
693 char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))];
694 struct cmsghdr* cmsg;
695 struct sctp_sndrcvinfo *sri;
696
697 /* SctpSocketChannel */
698 if (assocId < 0) {
699 shutdown(fd, SHUT_WR);
700 return;
701 }
702
703 memset(msg, 0, sizeof (*msg));
704 memset(cbuf, 0, cbuf_size);
705 msg->msg_name = NULL;
706 msg->msg_namelen = 0;
707 iov->iov_base = NULL;
708 iov->iov_len = 0;
709 msg->msg_iov = iov;
710 msg->msg_iovlen = 1;
711 msg->msg_control = cbuf;
712 msg->msg_controllen = cbuf_size;
713 msg->msg_flags = 0;
714
715 cmsg = CMSG_FIRSTHDR(msg);
716 cmsg->cmsg_level = IPPROTO_SCTP;
717 cmsg->cmsg_type = SCTP_SNDRCV;
718 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
719
720 /* Initialize the payload: */
721 sri = (struct sctp_sndrcvinfo*) CMSG_DATA(cmsg);
722 memset(sri, 0, sizeof (*sri));
723
724 if (assocId > 0) {
725 sri->sinfo_assoc_id = assocId;
726 }
727
728 sri->sinfo_flags = sri->sinfo_flags | SCTP_EOF;
729
730 /* Sum of the length of all control messages in the buffer. */
731 msg->msg_controllen = cmsg->cmsg_len;
732
733 if ((rv = sendmsg(fd, msg, 0)) < 0) {
734 handleSocketError(env, errno);
735 }
736 }
737
738 /*
739 * Class: sun_nio_ch_sctp_SctpNet
740 * Method: branch
741 * Signature: (II)I
742 */
Java_sun_nio_ch_sctp_SctpNet_branch0(JNIEnv * env,jclass klass,jint fd,jint assocId)743 JNIEXPORT int JNICALL Java_sun_nio_ch_sctp_SctpNet_branch0
744 (JNIEnv *env, jclass klass, jint fd, jint assocId) {
745 int newfd = 0;
746 if ((newfd = nio_sctp_peeloff(fd, assocId)) < 0) {
747 handleSocketError(env, errno);
748 }
749
750 return newfd;
751 }
752