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