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