1 /* 2 * Copyright (c) 2001, 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 <sys/types.h> 27 #include <sys/socket.h> 28 #include <string.h> 29 #include <netinet/in.h> 30 #include <netinet/tcp.h> 31 32 #include "jni.h" 33 #include "jni_util.h" 34 #include "jvm.h" 35 #include "jlong.h" 36 #include "sun_nio_ch_Net.h" 37 #include "net_util.h" 38 #include "net_util_md.h" 39 #include "nio_util.h" 40 #include "nio.h" 41 42 /** 43 * Definitions for source-specific multicast to allow for building 44 * with older header files. 45 */ 46 47 #ifdef __solaris__ 48 49 #ifndef IP_BLOCK_SOURCE 50 51 #define IP_BLOCK_SOURCE 0x15 52 #define IP_UNBLOCK_SOURCE 0x16 53 #define IP_ADD_SOURCE_MEMBERSHIP 0x17 54 #define IP_DROP_SOURCE_MEMBERSHIP 0x18 55 56 #define MCAST_BLOCK_SOURCE 0x2b 57 #define MCAST_UNBLOCK_SOURCE 0x2c 58 #define MCAST_JOIN_SOURCE_GROUP 0x2d 59 #define MCAST_LEAVE_SOURCE_GROUP 0x2e 60 61 #endif /* IP_BLOCK_SOURCE */ 62 63 struct my_ip_mreq_source { 64 struct in_addr imr_multiaddr; 65 struct in_addr imr_sourceaddr; 66 struct in_addr imr_interface; 67 }; 68 69 /* 70 * Use #pragma pack() construct to force 32-bit alignment on amd64. 71 */ 72 #if defined(amd64) 73 #pragma pack(4) 74 #endif 75 76 struct my_group_source_req { 77 uint32_t gsr_interface; /* interface index */ 78 struct sockaddr_storage gsr_group; /* group address */ 79 struct sockaddr_storage gsr_source; /* source address */ 80 }; 81 82 #if defined(amd64) 83 #pragma pack() 84 #endif 85 86 #endif /* __solaris__ */ 87 88 89 #ifdef __linux__ 90 91 #ifndef IP_BLOCK_SOURCE 92 93 #define IP_BLOCK_SOURCE 38 94 #define IP_UNBLOCK_SOURCE 37 95 #define IP_ADD_SOURCE_MEMBERSHIP 39 96 #define IP_DROP_SOURCE_MEMBERSHIP 40 97 98 #define MCAST_BLOCK_SOURCE 43 99 #define MCAST_UNBLOCK_SOURCE 44 100 #define MCAST_JOIN_SOURCE_GROUP 42 101 #define MCAST_LEAVE_SOURCE_GROUP 45 102 103 #endif /* IP_BLOCK_SOURCE */ 104 105 struct my_ip_mreq_source { 106 struct in_addr imr_multiaddr; 107 struct in_addr imr_interface; 108 struct in_addr imr_sourceaddr; 109 }; 110 111 struct my_group_source_req { 112 uint32_t gsr_interface; /* interface index */ 113 struct sockaddr_storage gsr_group; /* group address */ 114 struct sockaddr_storage gsr_source; /* source address */ 115 }; 116 117 #endif /* __linux__ */ 118 119 120 #define COPY_INET6_ADDRESS(env, source, target) \ 121 (*env)->GetByteArrayRegion(env, source, 0, 16, target) 122 123 /* 124 * Copy IPv6 group, interface index, and IPv6 source address 125 * into group_source_req structure. 126 */ 127 #ifdef AF_INET6 128 static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index, 129 jbyteArray source, struct my_group_source_req* req) 130 { 131 struct sockaddr_in6* sin6; 132 133 req->gsr_interface = (uint32_t)index; 134 135 sin6 = (struct sockaddr_in6*)&(req->gsr_group); 136 sin6->sin6_family = AF_INET6; 137 COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr)); 138 139 sin6 = (struct sockaddr_in6*)&(req->gsr_source); 140 sin6->sin6_family = AF_INET6; 141 COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr)); 142 } 143 #endif 144 145 JNIEXPORT void JNICALL 146 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) 147 { 148 /* Here because Windows native code does need to init IDs */ 149 } 150 151 JNIEXPORT jboolean JNICALL 152 Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) 153 { 154 return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; 155 } 156 157 JNIEXPORT int JNICALL 158 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, 159 jboolean stream, jboolean reuse) 160 { 161 int fd; 162 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); 163 #ifdef AF_INET6 164 int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; 165 #else 166 int domain = AF_INET; 167 #endif 168 169 fd = socket(domain, type, 0); 170 if (fd < 0) { 171 return handleSocketError(env, errno); 172 } 173 174 #ifdef AF_INET6 175 /* Disable IPV6_V6ONLY to ensure dual-socket support */ 176 if (domain == AF_INET6) { 177 int arg = 0; 178 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 179 sizeof(int)) < 0) { 180 JNU_ThrowByNameWithLastError(env, 181 JNU_JAVANETPKG "SocketException", 182 "sun.nio.ch.Net.setIntOption"); 183 close(fd); 184 return -1; 185 } 186 } 187 #endif 188 189 if (reuse) { 190 int arg = 1; 191 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, 192 sizeof(arg)) < 0) { 193 JNU_ThrowByNameWithLastError(env, 194 JNU_JAVANETPKG "SocketException", 195 "sun.nio.ch.Net.setIntOption"); 196 close(fd); 197 return -1; 198 } 199 } 200 #if defined(__linux__) && defined(AF_INET6) 201 /* By default, Linux uses the route default */ 202 if (domain == AF_INET6 && type == SOCK_DGRAM) { 203 int arg = 1; 204 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, 205 sizeof(arg)) < 0) { 206 JNU_ThrowByNameWithLastError(env, 207 JNU_JAVANETPKG "SocketException", 208 "sun.nio.ch.Net.setIntOption"); 209 close(fd); 210 return -1; 211 } 212 } 213 #endif 214 return fd; 215 } 216 217 JNIEXPORT void JNICALL 218 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6, 219 jobject fdo, jobject iao, int port) 220 { 221 SOCKADDR sa; 222 int sa_len = SOCKADDR_LEN; 223 int rv = 0; 224 225 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { 226 return; 227 } 228 229 rv = NET_Bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); 230 if (rv != 0) { 231 handleSocketError(env, errno); 232 } 233 } 234 235 JNIEXPORT void JNICALL 236 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) 237 { 238 if (listen(fdval(env, fdo), backlog) < 0) 239 handleSocketError(env, errno); 240 } 241 242 JNIEXPORT jint JNICALL 243 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, 244 jobject fdo, jobject iao, jint port) 245 { 246 SOCKADDR sa; 247 int sa_len = SOCKADDR_LEN; 248 int rv; 249 250 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, 251 &sa_len, preferIPv6) != 0) 252 { 253 return IOS_THROWN; 254 } 255 256 rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); 257 if (rv != 0) { 258 if (errno == EINPROGRESS) { 259 return IOS_UNAVAILABLE; 260 } else if (errno == EINTR) { 261 return IOS_INTERRUPTED; 262 } 263 return handleSocketError(env, errno); 264 } 265 return 1; 266 } 267 268 JNIEXPORT jint JNICALL 269 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) 270 { 271 SOCKADDR sa; 272 socklen_t sa_len = SOCKADDR_LEN; 273 if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { 274 handleSocketError(env, errno); 275 return -1; 276 } 277 return NET_GetPortFromSockaddr((struct sockaddr *)&sa); 278 } 279 280 JNIEXPORT jobject JNICALL 281 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 282 { 283 SOCKADDR sa; 284 socklen_t sa_len = SOCKADDR_LEN; 285 int port; 286 if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { 287 handleSocketError(env, errno); 288 return NULL; 289 } 290 return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); 291 } 292 293 JNIEXPORT jint JNICALL 294 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 295 jboolean mayNeedConversion, jint level, jint opt) 296 { 297 int result; 298 struct linger linger; 299 u_char carg; 300 void *arg; 301 socklen_t arglen; 302 int n; 303 304 /* Option value is an int except for a few specific cases */ 305 306 arg = (void *)&result; 307 arglen = sizeof(result); 308 309 if (level == IPPROTO_IP && 310 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 311 arg = (void*)&carg; 312 arglen = sizeof(carg); 313 } 314 315 if (level == SOL_SOCKET && opt == SO_LINGER) { 316 arg = (void *)&linger; 317 arglen = sizeof(linger); 318 } 319 320 if (mayNeedConversion) { 321 n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen); 322 } else { 323 n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); 324 } 325 if (n < 0) { 326 JNU_ThrowByNameWithLastError(env, 327 JNU_JAVANETPKG "SocketException", 328 "sun.nio.ch.Net.getIntOption"); 329 return -1; 330 } 331 332 if (level == IPPROTO_IP && 333 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) 334 { 335 return (jint)carg; 336 } 337 338 if (level == SOL_SOCKET && opt == SO_LINGER) 339 return linger.l_onoff ? (jint)linger.l_linger : (jint)-1; 340 341 return (jint)result; 342 } 343 344 JNIEXPORT void JNICALL 345 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 346 jboolean mayNeedConversion, jint level, jint opt, jint arg) 347 { 348 int result; 349 struct linger linger; 350 u_char carg; 351 void *parg; 352 int arglen, n; 353 354 /* Option value is an int except for a few specific cases */ 355 356 parg = (void*)&arg; 357 arglen = sizeof(arg); 358 359 if (level == IPPROTO_IP && 360 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 361 parg = (void*)&carg; 362 arglen = sizeof(carg); 363 carg = (u_char)arg; 364 } 365 366 if (level == SOL_SOCKET && opt == SO_LINGER) { 367 parg = (void *)&linger; 368 arglen = sizeof(linger); 369 if (arg >= 0) { 370 linger.l_onoff = 1; 371 linger.l_linger = arg; 372 } else { 373 linger.l_onoff = 0; 374 linger.l_linger = 0; 375 } 376 } 377 378 if (mayNeedConversion) { 379 n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); 380 } else { 381 n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); 382 } 383 if (n < 0) { 384 JNU_ThrowByNameWithLastError(env, 385 JNU_JAVANETPKG "SocketException", 386 "sun.nio.ch.Net.setIntOption"); 387 } 388 } 389 390 JNIEXPORT jint JNICALL 391 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, 392 jint group, jint interf, jint source) 393 { 394 struct ip_mreq mreq; 395 struct my_ip_mreq_source mreq_source; 396 int opt, n, optlen; 397 void* optval; 398 399 if (source == 0) { 400 mreq.imr_multiaddr.s_addr = htonl(group); 401 mreq.imr_interface.s_addr = htonl(interf); 402 opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; 403 optval = (void*)&mreq; 404 optlen = sizeof(mreq); 405 } else { 406 mreq_source.imr_multiaddr.s_addr = htonl(group); 407 mreq_source.imr_sourceaddr.s_addr = htonl(source); 408 mreq_source.imr_interface.s_addr = htonl(interf); 409 opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; 410 optval = (void*)&mreq_source; 411 optlen = sizeof(mreq_source); 412 } 413 414 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); 415 if (n < 0) { 416 if (join && (errno == ENOPROTOOPT)) 417 return IOS_UNAVAILABLE; 418 handleSocketError(env, errno); 419 } 420 return 0; 421 } 422 423 JNIEXPORT jint JNICALL 424 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, 425 jint group, jint interf, jint source) 426 { 427 struct my_ip_mreq_source mreq_source; 428 int n; 429 int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; 430 431 mreq_source.imr_multiaddr.s_addr = htonl(group); 432 mreq_source.imr_sourceaddr.s_addr = htonl(source); 433 mreq_source.imr_interface.s_addr = htonl(interf); 434 435 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, 436 (void*)&mreq_source, sizeof(mreq_source)); 437 if (n < 0) { 438 if (block && (errno == ENOPROTOOPT)) 439 return IOS_UNAVAILABLE; 440 handleSocketError(env, errno); 441 } 442 return 0; 443 } 444 445 JNIEXPORT jint JNICALL 446 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, 447 jbyteArray group, jint index, jbyteArray source) 448 { 449 #ifdef AF_INET6 450 struct ipv6_mreq mreq6; 451 struct my_group_source_req req; 452 int opt, n, optlen; 453 void* optval; 454 455 if (source == NULL) { 456 COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); 457 mreq6.ipv6mr_interface = (int)index; 458 opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; 459 optval = (void*)&mreq6; 460 optlen = sizeof(mreq6); 461 } else { 462 #ifdef __linux__ 463 /* Include-mode filtering broken on Linux at least to 2.6.24 */ 464 return IOS_UNAVAILABLE; 465 #else 466 initGroupSourceReq(env, group, index, source, &req); 467 opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; 468 optval = (void*)&req; 469 optlen = sizeof(req); 470 #endif 471 } 472 473 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen); 474 if (n < 0) { 475 if (join && (errno == ENOPROTOOPT)) 476 return IOS_UNAVAILABLE; 477 handleSocketError(env, errno); 478 } 479 return 0; 480 #else 481 JNU_ThrowInternalError(env, "Should not get here"); 482 return IOS_THROWN; 483 #endif /* AF_INET6 */ 484 } 485 486 JNIEXPORT jint JNICALL 487 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, 488 jbyteArray group, jint index, jbyteArray source) 489 { 490 #ifdef AF_INET6 491 struct my_group_source_req req; 492 int n; 493 int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; 494 495 initGroupSourceReq(env, group, index, source, &req); 496 497 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, 498 (void*)&req, sizeof(req)); 499 if (n < 0) { 500 if (block && (errno == ENOPROTOOPT)) 501 return IOS_UNAVAILABLE; 502 handleSocketError(env, errno); 503 } 504 return 0; 505 #else 506 JNU_ThrowInternalError(env, "Should not get here"); 507 return IOS_THROWN; 508 #endif 509 } 510 511 JNIEXPORT void JNICALL 512 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) 513 { 514 struct in_addr in; 515 int arglen = sizeof(struct in_addr); 516 int n; 517 518 in.s_addr = htonl(interf); 519 520 n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, 521 (void*)&(in.s_addr), arglen); 522 if (n < 0) { 523 handleSocketError(env, errno); 524 } 525 } 526 527 JNIEXPORT jint JNICALL 528 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) 529 { 530 struct in_addr in; 531 socklen_t arglen = sizeof(struct in_addr); 532 int n; 533 534 n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); 535 if (n < 0) { 536 handleSocketError(env, errno); 537 return -1; 538 } 539 return ntohl(in.s_addr); 540 } 541 542 JNIEXPORT void JNICALL 543 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) 544 { 545 int value = (jint)index; 546 int arglen = sizeof(value); 547 int n; 548 549 n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, 550 (void*)&(index), arglen); 551 if (n < 0) { 552 handleSocketError(env, errno); 553 } 554 } 555 556 JNIEXPORT jint JNICALL 557 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) 558 { 559 int index; 560 socklen_t arglen = sizeof(index); 561 int n; 562 563 n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); 564 if (n < 0) { 565 handleSocketError(env, errno); 566 return -1; 567 } 568 return (jint)index; 569 } 570 571 JNIEXPORT void JNICALL 572 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) 573 { 574 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD : 575 (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR; 576 if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN)) 577 handleSocketError(env, errno); 578 } 579 580 /* Declared in nio_util.h */ 581 582 jint 583 handleSocketError(JNIEnv *env, jint errorValue) 584 { 585 char *xn; 586 switch (errorValue) { 587 case EINPROGRESS: /* Non-blocking connect */ 588 return 0; 589 case EPROTO: 590 xn = JNU_JAVANETPKG "ProtocolException"; 591 break; 592 case ECONNREFUSED: 593 xn = JNU_JAVANETPKG "ConnectException"; 594 break; 595 case ETIMEDOUT: 596 xn = JNU_JAVANETPKG "ConnectException"; 597 break; 598 case EHOSTUNREACH: 599 xn = JNU_JAVANETPKG "NoRouteToHostException"; 600 break; 601 case EADDRINUSE: /* Fall through */ 602 case EADDRNOTAVAIL: 603 xn = JNU_JAVANETPKG "BindException"; 604 break; 605 default: 606 xn = JNU_JAVANETPKG "SocketException"; 607 break; 608 } 609 errno = errorValue; 610 JNU_ThrowByNameWithLastError(env, xn, "NioSocketError"); 611 return IOS_THROWN; 612 }