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