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