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 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 */ 59 jboolean 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 113 jint 114 handleSocketError(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 */ 150 JNIEXPORT void JNICALL 151 Java_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 */ 168 JNIEXPORT 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 */ 210 JNIEXPORT 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 */ 249 JNIEXPORT void JNICALL 250 Java_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 */ 261 JNIEXPORT jint JNICALL 262 Java_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 */ 290 JNIEXPORT void JNICALL 291 Java_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 */ 305 JNIEXPORT void JNICALL 306 Java_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 314 void 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 327 jobject 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 */ 347 JNIEXPORT 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 398 jobjectArray getRemoteAddresses(JNIEnv *env, jint fd, sctp_assoc_t id) { 399 void *addr_buf, *paddr; 400 int i, addrCount; 401 jobjectArray isaa; 402 403 #if defined(__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 */ 452 JNIEXPORT 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 */ 458 int 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 */ 491 JNIEXPORT 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 */ 531 JNIEXPORT 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 */ 571 JNIEXPORT 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 */ 592 JNIEXPORT 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 */ 615 JNIEXPORT 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 */ 640 JNIEXPORT 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 */ 663 JNIEXPORT 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 */ 684 JNIEXPORT 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 */ 740 JNIEXPORT 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 }