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