1 /* 2 * Copyright (c) 2009, 2015, 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 SOCKADDR *sap, *tmpSap; 214 int i, sa_len = sizeof(SOCKADDR); 215 jobject ia; 216 217 if (addrsLength < 1) 218 return; 219 220 if ((sap = calloc(addrsLength, sa_len)) == 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, (struct sockaddr*)tmpSap, 229 &sa_len, 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 SOCKADDR sa; 265 int sa_len = SOCKADDR_LEN; 266 int rv; 267 268 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, 269 &sa_len, JNI_TRUE) != 0) { 270 return IOS_THROWN; 271 } 272 273 rv = connect(fd, (struct sockaddr *)&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 315 (JNIEnv* env) { 316 if (isaCls == 0) { 317 jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress"); 318 CHECK_NULL(c); 319 isaCtrID = (*env)->GetMethodID(env, c, "<init>", 320 "(Ljava/net/InetAddress;I)V"); 321 CHECK_NULL(isaCtrID); 322 isaCls = (*env)->NewGlobalRef(env, c); 323 CHECK_NULL(isaCls); 324 (*env)->DeleteLocalRef(env, c); 325 } 326 } 327 328 jobject SockAddrToInetSocketAddress 329 (JNIEnv *env, struct sockaddr* sap) { 330 int port = 0; 331 332 jobject ia = NET_SockaddrToInetAddress(env, sap, &port); 333 if (ia == NULL) 334 return NULL; 335 336 if (isaCls == 0) { 337 initializeISA(env); 338 CHECK_NULL_RETURN(isaCls, NULL); 339 } 340 341 return (*env)->NewObject(env, isaCls, isaCtrID, ia, port); 342 } 343 344 /* 345 * Class: sun_nio_ch_sctp_SctpNet 346 * Method: getLocalAddresses0 347 * Signature: (I)[Ljava/net/SocketAddress; 348 */ 349 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_sctp_SctpNet_getLocalAddresses0 350 (JNIEnv *env, jclass klass, jint fd) { 351 void *addr_buf, *laddr; 352 struct sockaddr* sap; 353 int i, addrCount; 354 jobjectArray isaa; 355 356 #ifdef __solaris__ 357 if ((addrCount = nio_sctp_getladdrs(fd, 0, (void **)&addr_buf)) == -1) { 358 #else /* __linux__ */ 359 if ((addrCount = nio_sctp_getladdrs(fd, 0, (struct sockaddr **)&addr_buf)) == -1) { 360 #endif 361 handleSocketError(env, errno); 362 return NULL; 363 } 364 365 if (addrCount < 1) 366 return NULL; 367 368 if (isaCls == 0) { 369 initializeISA(env); 370 CHECK_NULL_RETURN(isaCls, NULL); 371 } 372 373 isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL); 374 if (isaa == NULL) { 375 nio_sctp_freeladdrs(addr_buf); 376 return NULL; 377 } 378 379 laddr = addr_buf; 380 for (i=0; i<addrCount; i++) { 381 int port = 0; 382 jobject isa = NULL, ia; 383 sap = (struct sockaddr*)addr_buf; 384 ia = NET_SockaddrToInetAddress(env, sap, &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 (sap->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 402 (JNIEnv *env, jint fd, sctp_assoc_t id) { 403 void *addr_buf, *paddr; 404 struct sockaddr* sap; 405 int i, addrCount; 406 jobjectArray isaa; 407 408 #if __solaris__ 409 if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) { 410 #else /* __linux__ */ 411 if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr**)&addr_buf)) == -1) { 412 #endif 413 handleSocketError(env, errno); 414 return NULL; 415 } 416 417 if (addrCount < 1) 418 return NULL; 419 420 if (isaCls == 0) { 421 initializeISA(env); 422 CHECK_NULL_RETURN(isaCls, NULL); 423 } 424 425 isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL); 426 if (isaa == NULL) { 427 nio_sctp_freepaddrs(addr_buf); 428 return NULL; 429 } 430 431 paddr = addr_buf; 432 for (i=0; i<addrCount; i++) { 433 jobject ia, isa = NULL; 434 int port = 0; 435 sap = (struct sockaddr*)addr_buf; 436 ia = NET_SockaddrToInetAddress(env, sap, &port); 437 if (ia != NULL) 438 isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port); 439 if (isa == NULL) 440 break; 441 (*env)->SetObjectArrayElement(env, isaa, i, isa); 442 443 if (sap->sa_family == AF_INET) 444 addr_buf = ((struct sockaddr_in*)addr_buf) + 1; 445 else 446 addr_buf = ((struct sockaddr_in6*)addr_buf) + 1; 447 } 448 449 nio_sctp_freepaddrs(paddr); 450 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 struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr; 583 584 prim.ssp_assoc_id = assocId; 585 586 if (getsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, &prim_len) < 0) { 587 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 588 "sun.nio.ch.SctpNet.getPrimAddrOption0"); 589 return NULL; 590 } 591 592 return SockAddrToInetSocketAddress(env, sap); 593 } 594 595 /* 596 * Class: sun_nio_ch_sctp_SctpNet 597 * Method: setPrimAddrOption0 598 * Signature: (IILjava/net/InetAddress;I)V 599 */ 600 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPrimAddrOption0 601 (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) { 602 struct sctp_setprim prim; 603 struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr; 604 int sap_len = sizeof(sap); 605 606 if (NET_InetAddressToSockaddr(env, iaObj, port, sap, 607 &sap_len, JNI_TRUE) != 0) { 608 return; 609 } 610 611 prim.ssp_assoc_id = assocId; 612 613 if (setsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, sizeof(prim)) < 0) { 614 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 615 "sun.nio.ch.SctpNet.setPrimAddrOption0"); 616 } 617 } 618 619 /* 620 * Class: sun_nio_ch_sctp_SctpNet 621 * Method: setPeerPrimAddrOption0 622 * Signature: (IILjava/net/InetAddress;I)V 623 */ 624 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPeerPrimAddrOption0 625 (JNIEnv *env, jclass klass, jint fd, jint assocId, 626 jobject iaObj, jint port, jboolean preferIPv6) { 627 struct sctp_setpeerprim prim; 628 struct sockaddr* sap = (struct sockaddr*)&prim.sspp_addr; 629 int sap_len = sizeof(sap); 630 631 if (NET_InetAddressToSockaddr(env, iaObj, port, sap, 632 &sap_len, preferIPv6) != 0) { 633 return; 634 } 635 636 prim.sspp_assoc_id = assocId; 637 638 if (setsockopt(fd, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR, &prim, 639 sizeof(prim)) < 0) { 640 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 641 "sun.nio.ch.SctpNet.setPeerPrimAddrOption0"); 642 } 643 } 644 645 /* 646 * Class: sun_nio_ch_sctp_SctpNet 647 * Method: getInitMsgOption0 648 * Signature: (I[I)V 649 */ 650 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_getInitMsgOption0 651 (JNIEnv *env, jclass klass, jint fd, jintArray retVal) { 652 struct sctp_initmsg sctp_initmsg; 653 unsigned int sim_len = sizeof(sctp_initmsg); 654 int vals[2]; 655 656 if (getsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg, 657 &sim_len) < 0) { 658 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 659 "sun.nio.ch.SctpNet.getInitMsgOption0"); 660 return; 661 } 662 663 vals[0] = sctp_initmsg.sinit_max_instreams; 664 vals[1] = sctp_initmsg.sinit_num_ostreams; 665 (*env)->SetIntArrayRegion(env, retVal, 0, 2, vals); 666 } 667 668 /* 669 * Class: sun_nio_ch_sctp_SctpNet 670 * Method: setInitMsgOption0 671 * Signature: (III)V 672 */ 673 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setInitMsgOption0 674 (JNIEnv *env, jclass klass, jint fd, jint inArg, jint outArg) { 675 struct sctp_initmsg sctp_initmsg; 676 677 sctp_initmsg.sinit_max_instreams = (unsigned int)inArg; 678 sctp_initmsg.sinit_num_ostreams = (unsigned int)outArg; 679 sctp_initmsg.sinit_max_attempts = 0; // default 680 sctp_initmsg.sinit_max_init_timeo = 0; // default 681 682 if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg, 683 sizeof(sctp_initmsg)) < 0) { 684 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 685 "sun.nio.ch.SctpNet.setInitMsgOption0"); 686 } 687 } 688 689 /* 690 * Class: sun_nio_ch_sctp_SctpNet 691 * Method: shutdown0 692 * Signature: (II)V 693 */ 694 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_shutdown0 695 (JNIEnv *env, jclass klass, jint fd, jint assocId) { 696 int rv; 697 struct msghdr msg[1]; 698 struct iovec iov[1]; 699 int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo)); 700 char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))]; 701 struct cmsghdr* cmsg; 702 struct sctp_sndrcvinfo *sri; 703 704 /* SctpSocketChannel */ 705 if (assocId < 0) { 706 shutdown(fd, SHUT_WR); 707 return; 708 } 709 710 memset(msg, 0, sizeof (*msg)); 711 memset(cbuf, 0, cbuf_size); 712 msg->msg_name = NULL; 713 msg->msg_namelen = 0; 714 iov->iov_base = NULL; 715 iov->iov_len = 0; 716 msg->msg_iov = iov; 717 msg->msg_iovlen = 1; 718 msg->msg_control = cbuf; 719 msg->msg_controllen = cbuf_size; 720 msg->msg_flags = 0; 721 722 cmsg = CMSG_FIRSTHDR(msg); 723 cmsg->cmsg_level = IPPROTO_SCTP; 724 cmsg->cmsg_type = SCTP_SNDRCV; 725 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 726 727 /* Initialize the payload: */ 728 sri = (struct sctp_sndrcvinfo*) CMSG_DATA(cmsg); 729 memset(sri, 0, sizeof (*sri)); 730 731 if (assocId > 0) { 732 sri->sinfo_assoc_id = assocId; 733 } 734 735 sri->sinfo_flags = sri->sinfo_flags | SCTP_EOF; 736 737 /* Sum of the length of all control messages in the buffer. */ 738 msg->msg_controllen = cmsg->cmsg_len; 739 740 if ((rv = sendmsg(fd, msg, 0)) < 0) { 741 handleSocketError(env, errno); 742 } 743 } 744 745 /* 746 * Class: sun_nio_ch_sctp_SctpNet 747 * Method: branch 748 * Signature: (II)I 749 */ 750 JNIEXPORT int JNICALL Java_sun_nio_ch_sctp_SctpNet_branch0 751 (JNIEnv *env, jclass klass, jint fd, jint assocId) { 752 int newfd = 0; 753 if ((newfd = nio_sctp_peeloff(fd, assocId)) < 0) { 754 handleSocketError(env, errno); 755 } 756 757 return newfd; 758 }