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
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 #ifdef __solaris__
366 if ((addrCount = nio_sctp_getladdrs(fd, 0, (void **)&addr_buf)) == -1) {
367 #else /* __linux__ */
368 if ((addrCount = nio_sctp_getladdrs(fd, 0, (struct sockaddr **)&addr_buf)) == -1) {
369 #endif
370 handleSocketError(env, errno);
371 return NULL;
372 }
373
374 if (addrCount < 1)
375 return NULL;
376
377 if (isaCls == 0) {
378 initializeISA(env);
379 CHECK_NULL_RETURN(isaCls, NULL);
380 }
381
382 isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
383 if (isaa == NULL) {
384 nio_sctp_freeladdrs(addr_buf);
385 return NULL;
386 }
387
388 laddr = addr_buf;
389 for (i = 0; i < addrCount; i++) {
390 int port = 0;
391 jobject ia, isa = NULL;
392 ia = NET_SockaddrToInetAddress(env, (SOCKETADDRESS *)addr_buf, &port);
393 if (ia != NULL)
394 isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
395 if (isa == NULL)
396 break;
397 (*env)->SetObjectArrayElement(env, isaa, i, isa);
398
399 if (((struct sockaddr *)addr_buf)->sa_family == AF_INET)
400 addr_buf = ((struct sockaddr_in *)addr_buf) + 1;
401 else
402 addr_buf = ((struct sockaddr_in6 *)addr_buf) + 1;
403 }
404
405 nio_sctp_freeladdrs(laddr);
406 return isaa;
407 }
408
409 jobjectArray getRemoteAddresses(JNIEnv *env, jint fd, sctp_assoc_t id) {
410 void *addr_buf, *paddr;
411 int i, addrCount;
412 jobjectArray isaa;
413
414 #if __solaris__
415 if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) {
416 #else /* __linux__ */
417 if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr **)&addr_buf)) == -1) {
418 #endif
419 handleSocketError(env, errno);
420 return NULL;
421 }
422
423 if (addrCount < 1)
424 return NULL;
425
426 if (isaCls == 0) {
427 initializeISA(env);
428 CHECK_NULL_RETURN(isaCls, NULL);
429 }
430
431 isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
432 if (isaa == NULL) {
433 nio_sctp_freepaddrs(addr_buf);
434 return NULL;
435 }
436
437 paddr = addr_buf;
438 for (i = 0; i < addrCount; i++) {
439 int port = 0;
440 jobject ia, isa = NULL;
441 ia = NET_SockaddrToInetAddress(env, (SOCKETADDRESS *)addr_buf, &port);
442 if (ia != NULL)
443 isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
444 if (isa == NULL)
445 break;
446 (*env)->SetObjectArrayElement(env, isaa, i, isa);
447
448 if (((struct sockaddr *)addr_buf)->sa_family == AF_INET)
449 addr_buf = ((struct sockaddr_in *)addr_buf) + 1;
450 else
451 addr_buf = ((struct sockaddr_in6 *)addr_buf) + 1;
452 }
453
454 nio_sctp_freepaddrs(paddr);
455 return isaa;
456 }
457
458 /*
459 * Class: sun_nio_ch_sctp_SctpNet
460 * Method: getRemoteAddresses0
461 * Signature: (II)[Ljava/net/SocketAddress;
462 */
463 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_sctp_SctpNet_getRemoteAddresses0
464 (JNIEnv *env, jclass klass, jint fd, jint assocId) {
465 return getRemoteAddresses(env, fd, assocId);
466 }
467
468 /* Map the Java level option to the native level */
469 int mapSocketOption
470 (jint cmd, int *level, int *optname) {
471 static struct {
472 jint cmd;
473 int level;
474 int optname;
475 } const opts[] = {
476 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_DISABLE_FRAGMENTS, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS },
477 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_EXPLICIT_COMPLETE, IPPROTO_SCTP, SCTP_EXPLICIT_EOR },
478 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_FRAGMENT_INTERLEAVE, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE },
479 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_NODELAY, IPPROTO_SCTP, SCTP_NODELAY },
480 { sun_nio_ch_sctp_SctpStdSocketOption_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF },
481 { sun_nio_ch_sctp_SctpStdSocketOption_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF },
482 { sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER, SOL_SOCKET, SO_LINGER } };
483
484 int i;
485 for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
486 if (cmd == opts[i].cmd) {
487 *level = opts[i].level;
488 *optname = opts[i].optname;
489 return 0;
490 }
491 }
492
493 /* not found */
494 return -1;
495 }
496
497 /*
498 * Class: sun_nio_ch_sctp_SctpNet
499 * Method: setIntOption0
500 * Signature: (III)V
501 */
502 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setIntOption0
503 (JNIEnv *env, jclass klass, jint fd, jint opt, int arg) {
504 int klevel, kopt;
505 int result;
506 struct linger linger;
507 void *parg;
508 int arglen;
509
510 if (mapSocketOption(opt, &klevel, &kopt) < 0) {
511 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
512 "Unsupported socket option");
513 return;
514 }
515
516 if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER) {
517 parg = (void *)&linger;
518 arglen = sizeof(linger);
519 if (arg >= 0) {
520 linger.l_onoff = 1;
521 linger.l_linger = arg;
522 } else {
523 linger.l_onoff = 0;
524 linger.l_linger = 0;
525 }
526 } else {
527 parg = (void *)&arg;
528 arglen = sizeof(arg);
529 }
530
531 if (NET_SetSockOpt(fd, klevel, kopt, parg, arglen) < 0) {
532 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
533 "sun_nio_ch_sctp_SctpNet.setIntOption0");
534 }
535 }
536
537 /*
538 * Class: sun_nio_ch_sctp_SctpNet
539 * Method: getIntOption0
540 * Signature: (II)I
541 */
542 JNIEXPORT int JNICALL Java_sun_nio_ch_sctp_SctpNet_getIntOption0
543 (JNIEnv *env, jclass klass, jint fd, jint opt) {
544 int klevel, kopt;
545 int result;
546 struct linger linger;
547 void *arg;
548 int arglen;
549
550 memset((char *) &linger, 0, sizeof(linger));
551 if (mapSocketOption(opt, &klevel, &kopt) < 0) {
552 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
553 "Unsupported socket option");
554 return -1;
555 }
556
557 if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER) {
558 arg = (void *)&linger;
559 arglen = sizeof(linger);
560 } else {
561 arg = (void *)&result;
562 arglen = sizeof(result);
563 }
564
565 if (NET_GetSockOpt(fd, klevel, kopt, arg, &arglen) < 0) {
566 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
567 "sun.nio.ch.Net.getIntOption");
568 return -1;
569 }
570
571 if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER)
572 return linger.l_onoff ? linger.l_linger : -1;
573 else
574 return result;
575 }
576
577 /*
578 * Class: sun_nio_ch_sctp_SctpNet
579 * Method: getPrimAddrOption0
580 * Signature: (II)Ljava/net/SocketAddress;
581 */
582 JNIEXPORT jobject JNICALL Java_sun_nio_ch_sctp_SctpNet_getPrimAddrOption0
583 (JNIEnv *env, jclass klass, jint fd, jint assocId) {
584 struct sctp_setprim prim;
585 unsigned int prim_len = sizeof(prim);
586
587 prim.ssp_assoc_id = assocId;
588
589 if (getsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, &prim_len) < 0) {
590 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
591 "sun.nio.ch.SctpNet.getPrimAddrOption0");
592 return NULL;
593 }
594
595 return SockAddrToInetSocketAddress(env, (SOCKETADDRESS *)&prim.ssp_addr);
596 }
597
598 /*
599 * Class: sun_nio_ch_sctp_SctpNet
600 * Method: setPrimAddrOption0
601 * Signature: (IILjava/net/InetAddress;I)V
602 */
603 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPrimAddrOption0
604 (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) {
605 struct sctp_setprim prim;
606
607 if (NET_InetAddressToSockaddr(env, iaObj, port,
608 (SOCKETADDRESS *)&prim.ssp_addr,
609 NULL, JNI_TRUE) != 0) {
610 return;
611 }
612
613 prim.ssp_assoc_id = assocId;
614
615 if (setsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, sizeof(prim)) < 0) {
616 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
617 "sun.nio.ch.SctpNet.setPrimAddrOption0");
618 }
619 }
620
621 /*
622 * Class: sun_nio_ch_sctp_SctpNet
623 * Method: setPeerPrimAddrOption0
624 * Signature: (IILjava/net/InetAddress;I)V
625 */
626 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPeerPrimAddrOption0
627 (JNIEnv *env, jclass klass, jint fd, jint assocId,
628 jobject iaObj, jint port, jboolean preferIPv6) {
629 struct sctp_setpeerprim prim;
630
631 if (NET_InetAddressToSockaddr(env, iaObj, port,
632 (SOCKETADDRESS *)&prim.sspp_addr,
633 NULL, preferIPv6) != 0) {
634 return;
635 }
636
637 prim.sspp_assoc_id = assocId;
638
639 if (setsockopt(fd, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR, &prim,
640 sizeof(prim)) < 0) {
641 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
642 "sun.nio.ch.SctpNet.setPeerPrimAddrOption0");
643 }
644 }
645
646 /*
647 * Class: sun_nio_ch_sctp_SctpNet
648 * Method: getInitMsgOption0
649 * Signature: (I[I)V
650 */
651 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_getInitMsgOption0
652 (JNIEnv *env, jclass klass, jint fd, jintArray retVal) {
653 struct sctp_initmsg sctp_initmsg;
654 unsigned int sim_len = sizeof(sctp_initmsg);
655 int vals[2];
656
657 if (getsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
658 &sim_len) < 0) {
659 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
660 "sun.nio.ch.SctpNet.getInitMsgOption0");
661 return;
662 }
663
664 vals[0] = sctp_initmsg.sinit_max_instreams;
665 vals[1] = sctp_initmsg.sinit_num_ostreams;
666 (*env)->SetIntArrayRegion(env, retVal, 0, 2, vals);
667 }
668
669 /*
670 * Class: sun_nio_ch_sctp_SctpNet
671 * Method: setInitMsgOption0
672 * Signature: (III)V
673 */
674 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setInitMsgOption0
675 (JNIEnv *env, jclass klass, jint fd, jint inArg, jint outArg) {
676 struct sctp_initmsg sctp_initmsg;
677
678 sctp_initmsg.sinit_max_instreams = (unsigned int)inArg;
679 sctp_initmsg.sinit_num_ostreams = (unsigned int)outArg;
680 sctp_initmsg.sinit_max_attempts = 0; // default
681 sctp_initmsg.sinit_max_init_timeo = 0; // default
682
683 if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
684 sizeof(sctp_initmsg)) < 0) {
685 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
686 "sun.nio.ch.SctpNet.setInitMsgOption0");
687 }
688 }
689
690 /*
691 * Class: sun_nio_ch_sctp_SctpNet
692 * Method: shutdown0
693 * Signature: (II)V
694 */
695 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_shutdown0
696 (JNIEnv *env, jclass klass, jint fd, jint assocId) {
697 int rv;
698 struct msghdr msg[1];
699 struct iovec iov[1];
700 int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo));
701 char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))];
702 struct cmsghdr* cmsg;
703 struct sctp_sndrcvinfo *sri;
704
705 /* SctpSocketChannel */
706 if (assocId < 0) {
707 shutdown(fd, SHUT_WR);
708 return;
709 }
710
711 memset(msg, 0, sizeof (*msg));
712 memset(cbuf, 0, cbuf_size);
713 msg->msg_name = NULL;
714 msg->msg_namelen = 0;
715 iov->iov_base = NULL;
716 iov->iov_len = 0;
717 msg->msg_iov = iov;
718 msg->msg_iovlen = 1;
719 msg->msg_control = cbuf;
720 msg->msg_controllen = cbuf_size;
721 msg->msg_flags = 0;
722
723 cmsg = CMSG_FIRSTHDR(msg);
724 cmsg->cmsg_level = IPPROTO_SCTP;
725 cmsg->cmsg_type = SCTP_SNDRCV;
726 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
727
728 /* Initialize the payload: */
729 sri = (struct sctp_sndrcvinfo*) CMSG_DATA(cmsg);
730 memset(sri, 0, sizeof (*sri));
731
732 if (assocId > 0) {
733 sri->sinfo_assoc_id = assocId;
734 }
735
736 sri->sinfo_flags = sri->sinfo_flags | SCTP_EOF;
737
738 /* Sum of the length of all control messages in the buffer. */
739 msg->msg_controllen = cmsg->cmsg_len;
740
741 if ((rv = sendmsg(fd, msg, 0)) < 0) {
742 handleSocketError(env, errno);
743 }
744 }
745
746 /*
747 * Class: sun_nio_ch_sctp_SctpNet
748 * Method: branch
749 * Signature: (II)I
750 */
751 JNIEXPORT int JNICALL Java_sun_nio_ch_sctp_SctpNet_branch0
752 (JNIEnv *env, jclass klass, jint fd, jint assocId) {
753 int newfd = 0;
754 if ((newfd = nio_sctp_peeloff(fd, assocId)) < 0) {
755 handleSocketError(env, errno);
756 }
757
758 return newfd;
759 }
760