1 /* 2 * Copyright (c) 2009, 2012, 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 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 } 161 162 /* 163 * Class: sun_nio_ch_sctp_SctpNet 164 * Method: socket0 165 * Signature: (Z)I 166 */ 167 JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpNet_socket0 168 (JNIEnv *env, jclass klass, jboolean oneToOne) { 169 int fd; 170 struct sctp_event_subscribe event; 171 #ifdef AF_INET6 172 int domain = ipv6_available() ? AF_INET6 : AF_INET; 173 #else 174 int domain = AF_INET; 175 #endif 176 177 /* Try to load the socket API extension functions */ 178 if (!funcsLoaded && !loadSocketExtensionFuncs(env)) { 179 return 0; 180 } 181 182 fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); 183 184 if (fd < 0) { 185 return handleSocketError(env, errno); 186 } 187 188 /* Enable events */ 189 memset(&event, 0, sizeof(event)); 190 event.sctp_data_io_event = 1; 191 event.sctp_association_event = 1; 192 event.sctp_address_event = 1; 193 event.sctp_send_failure_event = 1; 194 //event.sctp_peer_error_event = 1; 195 event.sctp_shutdown_event = 1; 196 //event.sctp_partial_delivery_event = 1; 197 //event.sctp_adaptation_layer_event = 1; 198 if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) { 199 handleSocketError(env, errno); 200 } 201 return fd; 202 } 203 204 /* 205 * Class: sun_nio_ch_sctp_SctpNet 206 * Method: bindx 207 * Signature: (I[Ljava/net/InetAddress;IIZ)V 208 */ 209 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_bindx 210 (JNIEnv *env, jclass klass, jint fd, jobjectArray addrs, jint port, 211 jint addrsLength, jboolean add, jboolean preferIPv6) { 212 SOCKADDR *sap, *tmpSap; 213 int i, sa_len = sizeof(SOCKADDR); 214 jobject ia; 215 216 if (addrsLength < 1) 217 return; 218 219 if ((sap = calloc(addrsLength, sa_len)) == NULL) { 220 JNU_ThrowOutOfMemoryError(env, "heap allocation failure"); 221 return; 222 } 223 224 tmpSap = sap; 225 for (i=0; i<addrsLength; i++) { 226 ia = (*env)->GetObjectArrayElement(env, addrs, i); 227 if (NET_InetAddressToSockaddr(env, ia, port, (struct sockaddr*)tmpSap, 228 &sa_len, preferIPv6) != 0) { 229 free(sap); 230 return; 231 } 232 tmpSap++; 233 } 234 235 if (nio_sctp_bindx(fd, (void*)sap, addrsLength, add ? SCTP_BINDX_ADD_ADDR : 236 SCTP_BINDX_REM_ADDR) != 0) { 237 handleSocketError(env, errno); 238 } 239 240 free(sap); 241 } 242 243 /* 244 * Class: sun_nio_ch_sctp_SctpNet 245 * Method: listen0 246 * Signature: (II)V 247 */ 248 JNIEXPORT void JNICALL 249 Java_sun_nio_ch_sctp_SctpNet_listen0 250 (JNIEnv *env, jclass cl, jint fd, jint backlog) { 251 if (listen(fd, backlog) < 0) 252 handleSocketError(env, errno); 253 } 254 255 /* 256 * Class: sun_nio_ch_sctp_SctpNet 257 * Method: connect0 258 * Signature: (ILjava/net/InetAddress;I)I 259 */ 260 JNIEXPORT jint JNICALL 261 Java_sun_nio_ch_sctp_SctpNet_connect0 262 (JNIEnv *env, jclass clazz, int fd, jobject iao, jint port) { 263 SOCKADDR sa; 264 int sa_len = SOCKADDR_LEN; 265 int rv; 266 267 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, 268 &sa_len, JNI_TRUE) != 0) { 269 return IOS_THROWN; 270 } 271 272 rv = connect(fd, (struct sockaddr *)&sa, sa_len); 273 if (rv != 0) { 274 if (errno == EINPROGRESS) { 275 return IOS_UNAVAILABLE; 276 } else if (errno == EINTR) { 277 return IOS_INTERRUPTED; 278 } 279 return handleSocketError(env, errno); 280 } 281 return 1; 282 } 283 284 /* 285 * Class: sun_nio_ch_sctp_SctpNet 286 * Method: close0 287 * Signature: (I)V 288 */ 289 JNIEXPORT void JNICALL 290 Java_sun_nio_ch_sctp_SctpNet_close0 291 (JNIEnv *env, jclass clazz, jint fd) { 292 if (fd != -1) { 293 int rv = close(fd); 294 if (rv < 0) 295 JNU_ThrowIOExceptionWithLastError(env, "Close failed"); 296 } 297 } 298 299 /* 300 * Class: sun_nio_ch_sctp_SctpNet 301 * Method: preClose0 302 * Signature: (I)V 303 */ 304 JNIEXPORT void JNICALL 305 Java_sun_nio_ch_sctp_SctpNet_preClose0 306 (JNIEnv *env, jclass clazz, jint fd) { 307 if (preCloseFD >= 0) { 308 if (dup2(preCloseFD, fd) < 0) 309 JNU_ThrowIOExceptionWithLastError(env, "dup2 failed"); 310 } 311 } 312 313 void initializeISA 314 (JNIEnv* env) { 315 if (isaCls == 0) { 316 jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress"); 317 CHECK_NULL(c); 318 isaCls = (*env)->NewGlobalRef(env, c); 319 CHECK_NULL(isaCls); 320 (*env)->DeleteLocalRef(env, c); 321 isaCtrID = (*env)->GetMethodID(env, isaCls, "<init>", 322 "(Ljava/net/InetAddress;I)V"); 323 } 324 } 325 326 jobject SockAddrToInetSocketAddress 327 (JNIEnv *env, struct sockaddr* 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 void *addr_buf, *laddr; 350 struct sockaddr* sap; 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 isa = NULL, ia; 381 sap = (struct sockaddr*)addr_buf; 382 ia = NET_SockaddrToInetAddress(env, sap, &port); 383 if (ia != NULL) 384 isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port); 385 if (isa == NULL) 386 break; 387 (*env)->SetObjectArrayElement(env, isaa, i, isa); 388 389 if (sap->sa_family == AF_INET) 390 addr_buf = ((struct sockaddr_in*)addr_buf) + 1; 391 else 392 addr_buf = ((struct sockaddr_in6*)addr_buf) + 1; 393 } 394 395 nio_sctp_freeladdrs(laddr); 396 return isaa; 397 } 398 399 jobjectArray getRemoteAddresses 400 (JNIEnv *env, jint fd, sctp_assoc_t id) { 401 void *addr_buf, *paddr; 402 struct sockaddr* sap; 403 int i, addrCount; 404 jobjectArray isaa; 405 406 #if __solaris__ 407 if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) { 408 #else /* __linux__ */ 409 if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr**)&addr_buf)) == -1) { 410 #endif 411 handleSocketError(env, errno); 412 return NULL; 413 } 414 415 if (addrCount < 1) 416 return NULL; 417 418 if (isaCls == 0) { 419 initializeISA(env); 420 CHECK_NULL_RETURN(isaCls, NULL); 421 } 422 423 isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL); 424 if (isaa == NULL) { 425 nio_sctp_freepaddrs(addr_buf); 426 return NULL; 427 } 428 429 paddr = addr_buf; 430 for (i=0; i<addrCount; i++) { 431 jobject ia, isa = NULL; 432 int port; 433 sap = (struct sockaddr*)addr_buf; 434 ia = NET_SockaddrToInetAddress(env, sap, &port); 435 if (ia != NULL) 436 isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port); 437 if (isa == NULL) 438 break; 439 (*env)->SetObjectArrayElement(env, isaa, i, isa); 440 441 if (sap->sa_family == AF_INET) 442 addr_buf = ((struct sockaddr_in*)addr_buf) + 1; 443 else 444 addr_buf = ((struct sockaddr_in6*)addr_buf) + 1; 445 } 446 447 nio_sctp_freepaddrs(paddr); 448 449 return isaa; 450 } 451 452 /* 453 * Class: sun_nio_ch_sctp_SctpNet 454 * Method: getRemoteAddresses0 455 * Signature: (II)[Ljava/net/SocketAddress; 456 */ 457 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_sctp_SctpNet_getRemoteAddresses0 458 (JNIEnv *env, jclass klass, jint fd, jint assocId) { 459 return getRemoteAddresses(env, fd, assocId); 460 } 461 462 /* Map the Java level option to the native level */ 463 int mapSocketOption 464 (jint cmd, int *level, int *optname) { 465 static struct { 466 jint cmd; 467 int level; 468 int optname; 469 } const opts[] = { 470 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_DISABLE_FRAGMENTS, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS }, 471 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_EXPLICIT_COMPLETE, IPPROTO_SCTP, SCTP_EXPLICIT_EOR }, 472 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_FRAGMENT_INTERLEAVE, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE }, 473 { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_NODELAY, IPPROTO_SCTP, SCTP_NODELAY }, 474 { sun_nio_ch_sctp_SctpStdSocketOption_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF }, 475 { sun_nio_ch_sctp_SctpStdSocketOption_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF }, 476 { sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER, SOL_SOCKET, SO_LINGER } }; 477 478 int i; 479 for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) { 480 if (cmd == opts[i].cmd) { 481 *level = opts[i].level; 482 *optname = opts[i].optname; 483 return 0; 484 } 485 } 486 487 /* not found */ 488 return -1; 489 } 490 491 /* 492 * Class: sun_nio_ch_sctp_SctpNet 493 * Method: setIntOption0 494 * Signature: (III)V 495 */ 496 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setIntOption0 497 (JNIEnv *env, jclass klass, jint fd, jint opt, int arg) { 498 int klevel, kopt; 499 int result; 500 struct linger linger; 501 void *parg; 502 int arglen; 503 504 if (mapSocketOption(opt, &klevel, &kopt) < 0) { 505 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 506 "Unsupported socket option"); 507 return; 508 } 509 510 if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER) { 511 parg = (void *)&linger; 512 arglen = sizeof(linger); 513 if (arg >= 0) { 514 linger.l_onoff = 1; 515 linger.l_linger = arg; 516 } else { 517 linger.l_onoff = 0; 518 linger.l_linger = 0; 519 } 520 } else { 521 parg = (void *)&arg; 522 arglen = sizeof(arg); 523 } 524 525 if (NET_SetSockOpt(fd, klevel, kopt, parg, arglen) < 0) { 526 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 527 "sun_nio_ch_sctp_SctpNet.setIntOption0"); 528 } 529 } 530 531 /* 532 * Class: sun_nio_ch_sctp_SctpNet 533 * Method: getIntOption0 534 * Signature: (II)I 535 */ 536 JNIEXPORT int JNICALL Java_sun_nio_ch_sctp_SctpNet_getIntOption0 537 (JNIEnv *env, jclass klass, jint fd, jint opt) { 538 int klevel, kopt; 539 int result; 540 struct linger linger; 541 void *arg; 542 int arglen; 543 544 if (mapSocketOption(opt, &klevel, &kopt) < 0) { 545 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 546 "Unsupported socket option"); 547 return -1; 548 } 549 550 if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER) { 551 arg = (void *)&linger; 552 arglen = sizeof(linger); 553 } else { 554 arg = (void *)&result; 555 arglen = sizeof(result); 556 } 557 558 if (NET_GetSockOpt(fd, klevel, kopt, arg, &arglen) < 0) { 559 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 560 "sun.nio.ch.Net.getIntOption"); 561 return -1; 562 } 563 564 if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER) 565 return linger.l_onoff ? linger.l_linger : -1; 566 else 567 return result; 568 } 569 570 /* 571 * Class: sun_nio_ch_sctp_SctpNet 572 * Method: getPrimAddrOption0 573 * Signature: (II)Ljava/net/SocketAddress; 574 */ 575 JNIEXPORT jobject JNICALL Java_sun_nio_ch_sctp_SctpNet_getPrimAddrOption0 576 (JNIEnv *env, jclass klass, jint fd, jint assocId) { 577 struct sctp_setprim prim; 578 unsigned int prim_len = sizeof(prim); 579 struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr; 580 581 prim.ssp_assoc_id = assocId; 582 583 if (getsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, &prim_len) < 0) { 584 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 585 "sun.nio.ch.SctpNet.getPrimAddrOption0"); 586 return NULL; 587 } 588 589 return SockAddrToInetSocketAddress(env, sap); 590 } 591 592 /* 593 * Class: sun_nio_ch_sctp_SctpNet 594 * Method: setPrimAddrOption0 595 * Signature: (IILjava/net/InetAddress;I)V 596 */ 597 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPrimAddrOption0 598 (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) { 599 struct sctp_setprim prim; 600 struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr; 601 int sap_len; 602 603 if (NET_InetAddressToSockaddr(env, iaObj, port, sap, 604 &sap_len, JNI_TRUE) != 0) { 605 return; 606 } 607 608 prim.ssp_assoc_id = assocId; 609 610 if (setsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, sizeof(prim)) < 0) { 611 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 612 "sun.nio.ch.SctpNet.setPrimAddrOption0"); 613 } 614 } 615 616 /* 617 * Class: sun_nio_ch_sctp_SctpNet 618 * Method: setPeerPrimAddrOption0 619 * Signature: (IILjava/net/InetAddress;I)V 620 */ 621 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPeerPrimAddrOption0 622 (JNIEnv *env, jclass klass, jint fd, jint assocId, 623 jobject iaObj, jint port, jboolean preferIPv6) { 624 struct sctp_setpeerprim prim; 625 struct sockaddr* sap = (struct sockaddr*)&prim.sspp_addr; 626 int sap_len; 627 628 if (NET_InetAddressToSockaddr(env, iaObj, port, sap, 629 &sap_len, 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 }