annotate src/solaris/native/java/net/net_util_md.c @ 6685:95eeca6dc691

8015743: Address internet addresses Summary: moved Inet6Address fields to holder class Reviewed-by: chegar, alanb, skoivu, khazra
author michaelm
date Wed, 03 Jul 2013 17:54:38 +0100
parents eefd9678efbd
children b5326675e374 e935cd4139c6
rev   line source
duke@0 1 /*
coffeys@5135 2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
duke@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 4 *
duke@0 5 * This code is free software; you can redistribute it and/or modify it
duke@0 6 * under the terms of the GNU General Public License version 2 only, as
ohair@2362 7 * published by the Free Software Foundation. Oracle designates this
duke@0 8 * particular file as subject to the "Classpath" exception as provided
ohair@2362 9 * by Oracle in the LICENSE file that accompanied this code.
duke@0 10 *
duke@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 15 * accompanied this code).
duke@0 16 *
duke@0 17 * You should have received a copy of the GNU General Public License version
duke@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 20 *
ohair@2362 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@2362 22 * or visit www.oracle.com if you need additional information or have any
ohair@2362 23 * questions.
duke@0 24 */
duke@0 25
duke@0 26 #include <errno.h>
duke@0 27 #include <string.h>
duke@0 28 #include <sys/types.h>
duke@0 29 #include <sys/socket.h>
duke@0 30 #include <netinet/tcp.h> /* Defines TCP_NODELAY, needed for 2.6 */
duke@0 31 #include <netinet/in.h>
duke@0 32 #include <net/if.h>
duke@0 33 #include <netdb.h>
duke@0 34 #include <stdlib.h>
duke@0 35 #include <dlfcn.h>
michaelm@4628 36
michaelm@4628 37 #ifndef _ALLBSD_SOURCE
michaelm@3123 38 #include <values.h>
michaelm@4628 39 #else
michaelm@4628 40 #include <limits.h>
michaelm@4628 41 #include <sys/param.h>
michaelm@4628 42 #include <sys/sysctl.h>
michaelm@4628 43 #ifndef MAXINT
michaelm@4628 44 #define MAXINT INT_MAX
michaelm@4628 45 #endif
michaelm@4628 46 #endif
duke@0 47
duke@0 48 #ifdef __solaris__
duke@0 49 #include <sys/sockio.h>
duke@0 50 #include <stropts.h>
duke@0 51 #include <inet/nd.h>
duke@0 52 #endif
duke@0 53
duke@0 54 #ifdef __linux__
duke@0 55 #include <arpa/inet.h>
duke@0 56 #include <net/route.h>
duke@0 57 #include <sys/utsname.h>
duke@0 58
duke@0 59 #ifndef IPV6_FLOWINFO_SEND
duke@0 60 #define IPV6_FLOWINFO_SEND 33
duke@0 61 #endif
duke@0 62
duke@0 63 #endif
duke@0 64
duke@0 65 #include "jni_util.h"
duke@0 66 #include "jvm.h"
duke@0 67 #include "net_util.h"
duke@0 68
duke@0 69 #include "java_net_SocketOptions.h"
duke@0 70
duke@0 71 /* needed from libsocket on Solaris 8 */
duke@0 72
duke@0 73 getaddrinfo_f getaddrinfo_ptr = NULL;
duke@0 74 freeaddrinfo_f freeaddrinfo_ptr = NULL;
martin@2801 75 gai_strerror_f gai_strerror_ptr = NULL;
duke@0 76 getnameinfo_f getnameinfo_ptr = NULL;
duke@0 77
duke@0 78 /*
coffeys@5135 79 * EXCLBIND socket options only on Solaris
duke@0 80 */
duke@0 81 #if defined(__solaris__) && !defined(TCP_EXCLBIND)
duke@0 82 #define TCP_EXCLBIND 0x21
duke@0 83 #endif
duke@0 84 #if defined(__solaris__) && !defined(UDP_EXCLBIND)
duke@0 85 #define UDP_EXCLBIND 0x0101
duke@0 86 #endif
duke@0 87
michaelm@4634 88 void setDefaultScopeID(JNIEnv *env, struct sockaddr *him)
michaelm@4634 89 {
michaelm@4634 90 #ifdef MACOSX
michaelm@4645 91 static jclass ni_class = NULL;
michaelm@4645 92 static jfieldID ni_defaultIndexID;
michaelm@4645 93 if (ni_class == NULL) {
michaelm@4645 94 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
michaelm@4645 95 CHECK_NULL(c);
michaelm@4645 96 c = (*env)->NewGlobalRef(env, c);
michaelm@4645 97 CHECK_NULL(c);
michaelm@4645 98 ni_defaultIndexID = (*env)->GetStaticFieldID(
michaelm@4645 99 env, c, "defaultIndex", "I");
michaelm@4645 100 ni_class = c;
michaelm@4645 101 }
michaelm@4634 102 int defaultIndex;
michaelm@4634 103 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)him;
michaelm@4634 104 if (sin6->sin6_family == AF_INET6 && (sin6->sin6_scope_id == 0)) {
michaelm@4634 105 defaultIndex = (*env)->GetStaticIntField(env, ni_class,
michaelm@4634 106 ni_defaultIndexID);
michaelm@4634 107 sin6->sin6_scope_id = defaultIndex;
michaelm@4634 108 }
michaelm@4634 109 #endif
michaelm@4634 110 }
michaelm@4634 111
khazra@4780 112 int getDefaultScopeID(JNIEnv *env) {
khazra@4780 113 static jclass ni_class = NULL;
khazra@4780 114 static jfieldID ni_defaultIndexID;
khazra@4780 115 if (ni_class == NULL) {
khazra@4780 116 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
khazra@4780 117 CHECK_NULL(c);
khazra@4780 118 c = (*env)->NewGlobalRef(env, c);
khazra@4780 119 CHECK_NULL(c);
khazra@4780 120 ni_defaultIndexID = (*env)->GetStaticFieldID(
khazra@4780 121 env, c, "defaultIndex", "I");
khazra@4780 122 ni_class = c;
khazra@4780 123 }
khazra@4780 124 int defaultIndex = 0;
khazra@4780 125 defaultIndex = (*env)->GetStaticIntField(env, ni_class,
khazra@4780 126 ni_defaultIndexID);
khazra@4780 127 return defaultIndex;
khazra@4780 128 }
khazra@4780 129
duke@0 130 #ifdef __solaris__
michaelm@3123 131 static int init_tcp_max_buf, init_udp_max_buf;
duke@0 132 static int tcp_max_buf;
duke@0 133 static int udp_max_buf;
coffeys@5135 134 static int useExclBind = 0;
duke@0 135
duke@0 136 /*
duke@0 137 * Get the specified parameter from the specified driver. The value
duke@0 138 * of the parameter is assumed to be an 'int'. If the parameter
michaelm@3123 139 * cannot be obtained return -1
duke@0 140 */
duke@0 141 static int
michaelm@3123 142 getParam(char *driver, char *param)
duke@0 143 {
duke@0 144 struct strioctl stri;
duke@0 145 char buf [64];
duke@0 146 int s;
duke@0 147 int value;
duke@0 148
duke@0 149 s = open (driver, O_RDWR);
duke@0 150 if (s < 0) {
michaelm@3123 151 return -1;
duke@0 152 }
duke@0 153 strncpy (buf, param, sizeof(buf));
duke@0 154 stri.ic_cmd = ND_GET;
duke@0 155 stri.ic_timout = 0;
duke@0 156 stri.ic_dp = buf;
duke@0 157 stri.ic_len = sizeof(buf);
duke@0 158 if (ioctl (s, I_STR, &stri) < 0) {
michaelm@3123 159 value = -1;
duke@0 160 } else {
duke@0 161 value = atoi(buf);
duke@0 162 }
duke@0 163 close (s);
duke@0 164 return value;
duke@0 165 }
michaelm@3123 166
michaelm@3123 167 /*
michaelm@3123 168 * Iterative way to find the max value that SO_SNDBUF or SO_RCVBUF
michaelm@3123 169 * for Solaris versions that do not support the ioctl() in getParam().
michaelm@3123 170 * Ugly, but only called once (for each sotype).
michaelm@3123 171 *
michaelm@3123 172 * As an optimisation, we make a guess using the default values for Solaris
michaelm@3123 173 * assuming they haven't been modified with ndd.
michaelm@3123 174 */
michaelm@3123 175
michaelm@3123 176 #define MAX_TCP_GUESS 1024 * 1024
michaelm@3123 177 #define MAX_UDP_GUESS 2 * 1024 * 1024
michaelm@3123 178
michaelm@3123 179 #define FAIL_IF_NOT_ENOBUFS if (errno != ENOBUFS) return -1
michaelm@3123 180
michaelm@3123 181 static int findMaxBuf(int fd, int opt, int sotype) {
michaelm@3123 182 int a = 0;
michaelm@3123 183 int b = MAXINT;
michaelm@3123 184 int initial_guess;
michaelm@3123 185 int limit = -1;
michaelm@3123 186
michaelm@3123 187 if (sotype == SOCK_DGRAM) {
michaelm@3123 188 initial_guess = MAX_UDP_GUESS;
michaelm@3123 189 } else {
michaelm@3123 190 initial_guess = MAX_TCP_GUESS;
michaelm@3123 191 }
michaelm@3123 192
michaelm@3123 193 if (setsockopt(fd, SOL_SOCKET, opt, &initial_guess, sizeof(int)) == 0) {
michaelm@3123 194 initial_guess++;
michaelm@3123 195 if (setsockopt(fd, SOL_SOCKET, opt, &initial_guess,sizeof(int)) < 0) {
michaelm@3123 196 FAIL_IF_NOT_ENOBUFS;
michaelm@3123 197 return initial_guess - 1;
michaelm@3123 198 }
michaelm@3123 199 a = initial_guess;
michaelm@3123 200 } else {
michaelm@3123 201 FAIL_IF_NOT_ENOBUFS;
michaelm@3123 202 b = initial_guess - 1;
michaelm@3123 203 }
michaelm@3123 204 do {
michaelm@3123 205 int mid = a + (b-a)/2;
michaelm@3123 206 if (setsockopt(fd, SOL_SOCKET, opt, &mid, sizeof(int)) == 0) {
michaelm@3123 207 limit = mid;
michaelm@3123 208 a = mid + 1;
michaelm@3123 209 } else {
michaelm@3123 210 FAIL_IF_NOT_ENOBUFS;
michaelm@3123 211 b = mid - 1;
michaelm@3123 212 }
michaelm@3123 213 } while (b >= a);
michaelm@3123 214
michaelm@3123 215 return limit;
michaelm@3123 216 }
duke@0 217 #endif
duke@0 218
duke@0 219 #ifdef __linux__
duke@0 220 static int kernelV22 = 0;
duke@0 221 static int vinit = 0;
duke@0 222
duke@0 223 int kernelIsV22 () {
duke@0 224 if (!vinit) {
duke@0 225 struct utsname sysinfo;
duke@0 226 if (uname(&sysinfo) == 0) {
duke@0 227 sysinfo.release[3] = '\0';
duke@0 228 if (strcmp(sysinfo.release, "2.2") == 0) {
duke@0 229 kernelV22 = JNI_TRUE;
duke@0 230 }
duke@0 231 }
duke@0 232 vinit = 1;
duke@0 233 }
duke@0 234 return kernelV22;
duke@0 235 }
duke@0 236
duke@0 237 static int kernelV24 = 0;
duke@0 238 static int vinit24 = 0;
duke@0 239
duke@0 240 int kernelIsV24 () {
duke@0 241 if (!vinit24) {
duke@0 242 struct utsname sysinfo;
duke@0 243 if (uname(&sysinfo) == 0) {
duke@0 244 sysinfo.release[3] = '\0';
duke@0 245 if (strcmp(sysinfo.release, "2.4") == 0) {
duke@0 246 kernelV24 = JNI_TRUE;
duke@0 247 }
duke@0 248 }
duke@0 249 vinit24 = 1;
duke@0 250 }
duke@0 251 return kernelV24;
duke@0 252 }
duke@0 253
duke@0 254 int getScopeID (struct sockaddr *him) {
duke@0 255 struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him;
duke@0 256 if (kernelIsV22()) {
duke@0 257 return 0;
duke@0 258 }
duke@0 259 return hext->sin6_scope_id;
duke@0 260 }
duke@0 261
duke@0 262 int cmpScopeID (unsigned int scope, struct sockaddr *him) {
duke@0 263 struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him;
duke@0 264 if (kernelIsV22()) {
duke@0 265 return 1; /* scope is ignored for comparison in 2.2 kernel */
duke@0 266 }
duke@0 267 return hext->sin6_scope_id == scope;
duke@0 268 }
duke@0 269
duke@0 270 #else
duke@0 271
duke@0 272 int getScopeID (struct sockaddr *him) {
duke@0 273 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
duke@0 274 return him6->sin6_scope_id;
duke@0 275 }
duke@0 276
duke@0 277 int cmpScopeID (unsigned int scope, struct sockaddr *him) {
duke@0 278 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
duke@0 279 return him6->sin6_scope_id == scope;
duke@0 280 }
duke@0 281
duke@0 282 #endif
duke@0 283
duke@0 284
duke@0 285 void
duke@0 286 NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
duke@0 287 const char *defaultDetail) {
duke@0 288 char errmsg[255];
duke@0 289 sprintf(errmsg, "errno: %d, error: %s\n", errno, defaultDetail);
duke@0 290 JNU_ThrowByNameWithLastError(env, name, errmsg);
duke@0 291 }
duke@0 292
duke@0 293 void
duke@0 294 NET_ThrowCurrent(JNIEnv *env, char *msg) {
duke@0 295 NET_ThrowNew(env, errno, msg);
duke@0 296 }
duke@0 297
duke@0 298 void
duke@0 299 NET_ThrowNew(JNIEnv *env, int errorNumber, char *msg) {
duke@0 300 char fullMsg[512];
duke@0 301 if (!msg) {
duke@0 302 msg = "no further information";
duke@0 303 }
duke@0 304 switch(errorNumber) {
duke@0 305 case EBADF:
duke@0 306 jio_snprintf(fullMsg, sizeof(fullMsg), "socket closed: %s", msg);
duke@0 307 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);
duke@0 308 break;
duke@0 309 case EINTR:
duke@0 310 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", msg);
duke@0 311 break;
duke@0 312 default:
duke@0 313 errno = errorNumber;
duke@0 314 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", msg);
duke@0 315 break;
duke@0 316 }
duke@0 317 }
duke@0 318
duke@0 319
duke@0 320 jfieldID
duke@0 321 NET_GetFileDescriptorID(JNIEnv *env)
duke@0 322 {
duke@0 323 jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor");
duke@0 324 CHECK_NULL_RETURN(cls, NULL);
duke@0 325 return (*env)->GetFieldID(env, cls, "fd", "I");
duke@0 326 }
duke@0 327
michaelm@4628 328 #if defined(DONT_ENABLE_IPV6)
michaelm@4628 329 jint IPv6_supported()
michaelm@4628 330 {
michaelm@4628 331 return JNI_FALSE;
michaelm@4628 332 }
michaelm@4628 333
michaelm@4628 334 #else /* !DONT_ENABLE_IPV6 */
michaelm@4628 335
duke@0 336 jint IPv6_supported()
duke@0 337 {
duke@0 338 #ifndef AF_INET6
duke@0 339 return JNI_FALSE;
duke@0 340 #endif
duke@0 341
duke@0 342 #ifdef AF_INET6
duke@0 343 int fd;
duke@0 344 void *ipv6_fn;
duke@0 345 SOCKADDR sa;
chegar@453 346 socklen_t sa_len = sizeof(sa);
duke@0 347
duke@0 348 fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0) ;
duke@0 349 if (fd < 0) {
duke@0 350 /*
duke@0 351 * TODO: We really cant tell since it may be an unrelated error
duke@0 352 * for now we will assume that AF_INET6 is not available
duke@0 353 */
duke@0 354 return JNI_FALSE;
duke@0 355 }
duke@0 356
duke@0 357 /*
duke@0 358 * If fd 0 is a socket it means we've been launched from inetd or
duke@0 359 * xinetd. If it's a socket then check the family - if it's an
duke@0 360 * IPv4 socket then we need to disable IPv6.
duke@0 361 */
duke@0 362 if (getsockname(0, (struct sockaddr *)&sa, &sa_len) == 0) {
duke@0 363 struct sockaddr *saP = (struct sockaddr *)&sa;
duke@0 364 if (saP->sa_family != AF_INET6) {
duke@0 365 return JNI_FALSE;
duke@0 366 }
duke@0 367 }
duke@0 368
duke@0 369 /**
duke@0 370 * Linux - check if any interface has an IPv6 address.
duke@0 371 * Don't need to parse the line - we just need an indication.
duke@0 372 */
duke@0 373 #ifdef __linux__
duke@0 374 {
duke@0 375 FILE *fP = fopen("/proc/net/if_inet6", "r");
duke@0 376 char buf[255];
duke@0 377 char *bufP;
duke@0 378
duke@0 379 if (fP == NULL) {
duke@0 380 close(fd);
duke@0 381 return JNI_FALSE;
duke@0 382 }
duke@0 383 bufP = fgets(buf, sizeof(buf), fP);
duke@0 384 fclose(fP);
duke@0 385 if (bufP == NULL) {
duke@0 386 close(fd);
duke@0 387 return JNI_FALSE;
duke@0 388 }
duke@0 389 }
duke@0 390 #endif
duke@0 391
duke@0 392 /**
duke@0 393 * On Solaris 8 it's possible to create INET6 sockets even
duke@0 394 * though IPv6 is not enabled on all interfaces. Thus we
duke@0 395 * query the number of IPv6 addresses to verify that IPv6
duke@0 396 * has been configured on at least one interface.
duke@0 397 *
duke@0 398 * On Linux it doesn't matter - if IPv6 is built-in the
duke@0 399 * kernel then IPv6 addresses will be bound automatically
duke@0 400 * to all interfaces.
duke@0 401 */
duke@0 402 #ifdef __solaris__
duke@0 403
duke@0 404 #ifdef SIOCGLIFNUM
duke@0 405 {
duke@0 406 struct lifnum numifs;
duke@0 407
duke@0 408 numifs.lifn_family = AF_INET6;
duke@0 409 numifs.lifn_flags = 0;
duke@0 410 if (ioctl(fd, SIOCGLIFNUM, (char *)&numifs) < 0) {
duke@0 411 /**
duke@0 412 * SIOCGLIFNUM failed - assume IPv6 not configured
duke@0 413 */
duke@0 414 close(fd);
duke@0 415 return JNI_FALSE;
duke@0 416 }
duke@0 417 /**
duke@0 418 * If no IPv6 addresses then return false. If count > 0
duke@0 419 * it's possible that all IPv6 addresses are "down" but
duke@0 420 * that's okay as they may be brought "up" while the
duke@0 421 * VM is running.
duke@0 422 */
duke@0 423 if (numifs.lifn_count == 0) {
duke@0 424 close(fd);
duke@0 425 return JNI_FALSE;
duke@0 426 }
duke@0 427 }
duke@0 428 #else
duke@0 429 /* SIOCGLIFNUM not defined in build environment ??? */
duke@0 430 close(fd);
duke@0 431 return JNI_FALSE;
duke@0 432 #endif
duke@0 433
duke@0 434 #endif /* __solaris */
duke@0 435
duke@0 436 /*
duke@0 437 * OK we may have the stack available in the kernel,
duke@0 438 * we should also check if the APIs are available.
duke@0 439 */
duke@0 440 ipv6_fn = JVM_FindLibraryEntry(RTLD_DEFAULT, "inet_pton");
duke@0 441 if (ipv6_fn == NULL ) {
duke@0 442 close(fd);
duke@0 443 return JNI_FALSE;
duke@0 444 }
duke@0 445
duke@0 446 /*
duke@0 447 * We've got the library, let's get the pointers to some
duke@0 448 * IPV6 specific functions. We have to do that because, at least
duke@0 449 * on Solaris we may build on a system without IPV6 networking
duke@0 450 * libraries, therefore we can't have a hard link to these
duke@0 451 * functions.
duke@0 452 */
duke@0 453 getaddrinfo_ptr = (getaddrinfo_f)
duke@0 454 JVM_FindLibraryEntry(RTLD_DEFAULT, "getaddrinfo");
duke@0 455
duke@0 456 freeaddrinfo_ptr = (freeaddrinfo_f)
duke@0 457 JVM_FindLibraryEntry(RTLD_DEFAULT, "freeaddrinfo");
duke@0 458
martin@2801 459 gai_strerror_ptr = (gai_strerror_f)
martin@2801 460 JVM_FindLibraryEntry(RTLD_DEFAULT, "gai_strerror");
martin@2801 461
duke@0 462 getnameinfo_ptr = (getnameinfo_f)
duke@0 463 JVM_FindLibraryEntry(RTLD_DEFAULT, "getnameinfo");
duke@0 464
duke@0 465 if (freeaddrinfo_ptr == NULL || getnameinfo_ptr == NULL) {
martin@2801 466 /* We need all 3 of them */
duke@0 467 getaddrinfo_ptr = NULL;
duke@0 468 }
duke@0 469
duke@0 470 close(fd);
duke@0 471 return JNI_TRUE;
chegar@2112 472 #endif /* AF_INET6 */
duke@0 473 }
michaelm@4628 474 #endif /* DONT_ENABLE_IPV6 */
duke@0 475
martin@2801 476 void ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
martin@2801 477 const char* hostname,
martin@2801 478 int gai_error)
martin@2801 479 {
alanb@2827 480 int size;
alanb@2827 481 char *buf;
martin@2801 482 const char *format = "%s: %s";
martin@2801 483 const char *error_string =
martin@2801 484 (gai_strerror_ptr == NULL) ? NULL : (*gai_strerror_ptr)(gai_error);
martin@2801 485 if (error_string == NULL)
martin@2801 486 error_string = "unknown error";
martin@2801 487
alanb@2827 488 size = strlen(format) + strlen(hostname) + strlen(error_string) + 2;
alanb@2827 489 buf = (char *) malloc(size);
martin@2801 490 if (buf) {
alanb@2827 491 jstring s;
martin@2801 492 sprintf(buf, format, hostname, error_string);
alanb@2827 493 s = JNU_NewStringPlatform(env, buf);
martin@2801 494 if (s != NULL) {
martin@2801 495 jobject x = JNU_NewObjectByName(env,
martin@2801 496 "java/net/UnknownHostException",
martin@2801 497 "(Ljava/lang/String;)V", s);
martin@2801 498 if (x != NULL)
martin@2801 499 (*env)->Throw(env, x);
martin@2801 500 }
martin@2801 501 free(buf);
martin@2801 502 }
martin@2801 503 }
martin@2801 504
duke@0 505 void
duke@0 506 NET_AllocSockaddr(struct sockaddr **him, int *len) {
duke@0 507 #ifdef AF_INET6
duke@0 508 if (ipv6_available()) {
duke@0 509 struct sockaddr_in6 *him6 = (struct sockaddr_in6*)malloc(sizeof(struct sockaddr_in6));
duke@0 510 *him = (struct sockaddr*)him6;
duke@0 511 *len = sizeof(struct sockaddr_in6);
duke@0 512 } else
duke@0 513 #endif /* AF_INET6 */
duke@0 514 {
duke@0 515 struct sockaddr_in *him4 = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
duke@0 516 *him = (struct sockaddr*)him4;
duke@0 517 *len = sizeof(struct sockaddr_in);
duke@0 518 }
duke@0 519 }
duke@0 520
duke@0 521 #if defined(__linux__) && defined(AF_INET6)
duke@0 522
duke@0 523
duke@0 524 /* following code creates a list of addresses from the kernel
duke@0 525 * routing table that are routed via the loopback address.
duke@0 526 * We check all destination addresses against this table
duke@0 527 * and override the scope_id field to use the relevant value for "lo"
duke@0 528 * in order to work-around the Linux bug that prevents packets destined
duke@0 529 * for certain local addresses from being sent via a physical interface.
duke@0 530 */
duke@0 531
duke@0 532 struct loopback_route {
duke@0 533 struct in6_addr addr; /* destination address */
duke@0 534 int plen; /* prefix length */
duke@0 535 };
duke@0 536
duke@0 537 static struct loopback_route *loRoutes = 0;
duke@0 538 static int nRoutes = 0; /* number of routes */
duke@0 539 static int loRoutes_size = 16; /* initial size */
duke@0 540 static int lo_scope_id = 0;
duke@0 541
duke@0 542 static void initLoopbackRoutes();
duke@0 543
duke@0 544 void printAddr (struct in6_addr *addr) {
duke@0 545 int i;
duke@0 546 for (i=0; i<16; i++) {
duke@0 547 printf ("%02x", addr->s6_addr[i]);
duke@0 548 }
duke@0 549 printf ("\n");
duke@0 550 }
duke@0 551
duke@0 552 static jboolean needsLoopbackRoute (struct in6_addr* dest_addr) {
duke@0 553 int byte_count;
duke@0 554 int extra_bits, i;
duke@0 555 struct loopback_route *ptr;
duke@0 556
duke@0 557 if (loRoutes == 0) {
duke@0 558 initLoopbackRoutes();
duke@0 559 }
duke@0 560
duke@0 561 for (ptr = loRoutes, i=0; i<nRoutes; i++, ptr++) {
duke@0 562 struct in6_addr *target_addr=&ptr->addr;
duke@0 563 int dest_plen = ptr->plen;
duke@0 564 byte_count = dest_plen >> 3;
duke@0 565 extra_bits = dest_plen & 0x3;
duke@0 566
duke@0 567 if (byte_count > 0) {
duke@0 568 if (memcmp(target_addr, dest_addr, byte_count)) {
duke@0 569 continue; /* no match */
duke@0 570 }
duke@0 571 }
duke@0 572
duke@0 573 if (extra_bits > 0) {
duke@0 574 unsigned char c1 = ((unsigned char *)target_addr)[byte_count];
duke@0 575 unsigned char c2 = ((unsigned char *)&dest_addr)[byte_count];
duke@0 576 unsigned char mask = 0xff << (8 - extra_bits);
duke@0 577 if ((c1 & mask) != (c2 & mask)) {
duke@0 578 continue;
duke@0 579 }
duke@0 580 }
duke@0 581 return JNI_TRUE;
duke@0 582 }
duke@0 583 return JNI_FALSE;
duke@0 584 }
duke@0 585
duke@0 586
duke@0 587 static void initLoopbackRoutes() {
duke@0 588 FILE *f;
duke@0 589 char srcp[8][5];
duke@0 590 char hopp[8][5];
duke@0 591 int dest_plen, src_plen, use, refcnt, metric;
duke@0 592 unsigned long flags;
duke@0 593 char dest_str[40];
duke@0 594 struct in6_addr dest_addr;
duke@0 595 char device[16];
duke@0 596
duke@0 597 if (loRoutes != 0) {
duke@0 598 free (loRoutes);
duke@0 599 }
duke@0 600 loRoutes = calloc (loRoutes_size, sizeof(struct loopback_route));
duke@0 601 if (loRoutes == 0) {
duke@0 602 return;
duke@0 603 }
duke@0 604 /*
duke@0 605 * Scan /proc/net/ipv6_route looking for a matching
duke@0 606 * route.
duke@0 607 */
duke@0 608 if ((f = fopen("/proc/net/ipv6_route", "r")) == NULL) {
duke@0 609 return ;
duke@0 610 }
duke@0 611 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
duke@0 612 "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
duke@0 613 "%4s%4s%4s%4s%4s%4s%4s%4s "
duke@0 614 "%08x %08x %08x %08lx %8s",
duke@0 615 dest_str, &dest_str[5], &dest_str[10], &dest_str[15],
duke@0 616 &dest_str[20], &dest_str[25], &dest_str[30], &dest_str[35],
duke@0 617 &dest_plen,
duke@0 618 srcp[0], srcp[1], srcp[2], srcp[3],
duke@0 619 srcp[4], srcp[5], srcp[6], srcp[7],
duke@0 620 &src_plen,
duke@0 621 hopp[0], hopp[1], hopp[2], hopp[3],
duke@0 622 hopp[4], hopp[5], hopp[6], hopp[7],
duke@0 623 &metric, &use, &refcnt, &flags, device) == 31) {
duke@0 624
duke@0 625 /*
duke@0 626 * Some routes should be ignored
duke@0 627 */
duke@0 628 if ( (dest_plen < 0 || dest_plen > 128) ||
duke@0 629 (src_plen != 0) ||
duke@0 630 (flags & (RTF_POLICY | RTF_FLOW)) ||
duke@0 631 ((flags & RTF_REJECT) && dest_plen == 0) ) {
duke@0 632 continue;
duke@0 633 }
duke@0 634
duke@0 635 /*
duke@0 636 * Convert the destination address
duke@0 637 */
duke@0 638 dest_str[4] = ':';
duke@0 639 dest_str[9] = ':';
duke@0 640 dest_str[14] = ':';
duke@0 641 dest_str[19] = ':';
duke@0 642 dest_str[24] = ':';
duke@0 643 dest_str[29] = ':';
duke@0 644 dest_str[34] = ':';
duke@0 645 dest_str[39] = '\0';
duke@0 646
duke@0 647 if (inet_pton(AF_INET6, dest_str, &dest_addr) < 0) {
duke@0 648 /* not an Ipv6 address */
duke@0 649 continue;
duke@0 650 }
duke@0 651 if (strcmp(device, "lo") != 0) {
duke@0 652 /* Not a loopback route */
duke@0 653 continue;
duke@0 654 } else {
duke@0 655 if (nRoutes == loRoutes_size) {
duke@0 656 loRoutes = realloc (loRoutes, loRoutes_size *
duke@0 657 sizeof (struct loopback_route) * 2);
duke@0 658 if (loRoutes == 0) {
duke@0 659 return ;
duke@0 660 }
duke@0 661 loRoutes_size *= 2;
duke@0 662 }
duke@0 663 memcpy (&loRoutes[nRoutes].addr,&dest_addr,sizeof(struct in6_addr));
duke@0 664 loRoutes[nRoutes].plen = dest_plen;
duke@0 665 nRoutes ++;
duke@0 666 }
duke@0 667 }
duke@0 668
duke@0 669 fclose (f);
duke@0 670 {
duke@0 671 /* now find the scope_id for "lo" */
duke@0 672
chegar@3657 673 char devname[21];
duke@0 674 char addr6p[8][5];
duke@0 675 int plen, scope, dad_status, if_idx;
duke@0 676
duke@0 677 if ((f = fopen("/proc/net/if_inet6", "r")) != NULL) {
duke@0 678 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
duke@0 679 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
duke@0 680 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
duke@0 681 &if_idx, &plen, &scope, &dad_status, devname) == 13) {
duke@0 682
duke@0 683 if (strcmp(devname, "lo") == 0) {
duke@0 684 /*
duke@0 685 * Found - so just return the index
duke@0 686 */
duke@0 687 fclose(f);
duke@0 688 lo_scope_id = if_idx;
duke@0 689 return;
duke@0 690 }
duke@0 691 }
duke@0 692 fclose(f);
duke@0 693 }
duke@0 694 }
duke@0 695 }
duke@0 696
duke@0 697 /*
duke@0 698 * Following is used for binding to local addresses. Equivalent
duke@0 699 * to code above, for bind().
duke@0 700 */
duke@0 701
duke@0 702 struct localinterface {
duke@0 703 int index;
duke@0 704 char localaddr [16];
duke@0 705 };
duke@0 706
duke@0 707 static struct localinterface *localifs = 0;
duke@0 708 static int localifsSize = 0; /* size of array */
duke@0 709 static int nifs = 0; /* number of entries used in array */
duke@0 710
duke@0 711 /* not thread safe: make sure called once from one thread */
duke@0 712
duke@0 713 static void initLocalIfs () {
duke@0 714 FILE *f;
duke@0 715 unsigned char staddr [16];
chegar@3657 716 char ifname [33];
duke@0 717 struct localinterface *lif=0;
duke@0 718 int index, x1, x2, x3;
duke@0 719 unsigned int u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,ua,ub,uc,ud,ue,uf;
duke@0 720
duke@0 721 if ((f = fopen("/proc/net/if_inet6", "r")) == NULL) {
duke@0 722 return ;
duke@0 723 }
duke@0 724 while (fscanf (f, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x "
chegar@3657 725 "%d %x %x %x %32s",&u0,&u1,&u2,&u3,&u4,&u5,&u6,&u7,
duke@0 726 &u8,&u9,&ua,&ub,&uc,&ud,&ue,&uf,
duke@0 727 &index, &x1, &x2, &x3, ifname) == 21) {
duke@0 728 staddr[0] = (unsigned char)u0;
duke@0 729 staddr[1] = (unsigned char)u1;
duke@0 730 staddr[2] = (unsigned char)u2;
duke@0 731 staddr[3] = (unsigned char)u3;
duke@0 732 staddr[4] = (unsigned char)u4;
duke@0 733 staddr[5] = (unsigned char)u5;
duke@0 734 staddr[6] = (unsigned char)u6;
duke@0 735 staddr[7] = (unsigned char)u7;
duke@0 736 staddr[8] = (unsigned char)u8;
duke@0 737 staddr[9] = (unsigned char)u9;
duke@0 738 staddr[10] = (unsigned char)ua;
duke@0 739 staddr[11] = (unsigned char)ub;
duke@0 740 staddr[12] = (unsigned char)uc;
duke@0 741 staddr[13] = (unsigned char)ud;
duke@0 742 staddr[14] = (unsigned char)ue;
duke@0 743 staddr[15] = (unsigned char)uf;
duke@0 744 nifs ++;
duke@0 745 if (nifs > localifsSize) {
duke@0 746 localifs = (struct localinterface *) realloc (
duke@0 747 localifs, sizeof (struct localinterface)* (localifsSize+5));
duke@0 748 if (localifs == 0) {
duke@0 749 nifs = 0;
duke@0 750 fclose (f);
duke@0 751 return;
duke@0 752 }
duke@0 753 lif = localifs + localifsSize;
duke@0 754 localifsSize += 5;
duke@0 755 } else {
duke@0 756 lif ++;
duke@0 757 }
duke@0 758 memcpy (lif->localaddr, staddr, 16);
duke@0 759 lif->index = index;
duke@0 760 }
duke@0 761 fclose (f);
duke@0 762 }
duke@0 763
duke@0 764 /* return the scope_id (interface index) of the
duke@0 765 * interface corresponding to the given address
duke@0 766 * returns 0 if no match found
duke@0 767 */
duke@0 768
duke@0 769 static int getLocalScopeID (char *addr) {
duke@0 770 struct localinterface *lif;
duke@0 771 int i;
duke@0 772 if (localifs == 0) {
duke@0 773 initLocalIfs();
duke@0 774 }
duke@0 775 for (i=0, lif=localifs; i<nifs; i++, lif++) {
duke@0 776 if (memcmp (addr, lif->localaddr, 16) == 0) {
duke@0 777 return lif->index;
duke@0 778 }
duke@0 779 }
duke@0 780 return 0;
duke@0 781 }
duke@0 782
duke@0 783 void initLocalAddrTable () {
duke@0 784 initLoopbackRoutes();
duke@0 785 initLocalIfs();
duke@0 786 }
duke@0 787
duke@0 788 #else
duke@0 789
duke@0 790 void initLocalAddrTable () {}
duke@0 791
duke@0 792 #endif
duke@0 793
coffeys@5135 794 void parseExclusiveBindProperty(JNIEnv *env) {
coffeys@5135 795 #ifdef __solaris__
coffeys@5135 796 jstring s, flagSet;
coffeys@5135 797 jclass iCls;
coffeys@5135 798 jmethodID mid;
coffeys@5135 799
coffeys@5135 800 s = (*env)->NewStringUTF(env, "sun.net.useExclusiveBind");
coffeys@5135 801 CHECK_NULL(s);
coffeys@5135 802 iCls = (*env)->FindClass(env, "java/lang/System");
coffeys@5135 803 CHECK_NULL(iCls);
coffeys@5135 804 mid = (*env)->GetStaticMethodID(env, iCls, "getProperty",
coffeys@5135 805 "(Ljava/lang/String;)Ljava/lang/String;");
coffeys@5135 806 CHECK_NULL(mid);
coffeys@5135 807 flagSet = (*env)->CallStaticObjectMethod(env, iCls, mid, s);
coffeys@5135 808 if (flagSet != NULL) {
coffeys@5135 809 useExclBind = 1;
coffeys@5135 810 }
coffeys@5135 811 #endif
coffeys@5135 812 }
duke@0 813 /* In the case of an IPv4 Inetaddress this method will return an
duke@0 814 * IPv4 mapped address where IPv6 is available and v4MappedAddress is TRUE.
duke@0 815 * Otherwise it will return a sockaddr_in structure for an IPv4 InetAddress.
duke@0 816 */
duke@0 817 JNIEXPORT int JNICALL
duke@0 818 NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him,
duke@0 819 int *len, jboolean v4MappedAddress) {
duke@0 820 jint family;
michaelm@5887 821 family = getInetAddress_family(env, iaObj);
duke@0 822 #ifdef AF_INET6
duke@0 823 /* needs work. 1. family 2. clean up him6 etc deallocate memory */
duke@0 824 if (ipv6_available() && !(family == IPv4 && v4MappedAddress == JNI_FALSE)) {
duke@0 825 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
duke@0 826 jbyte caddr[16];
duke@0 827 jint address;
duke@0 828
duke@0 829
duke@0 830 if (family == IPv4) { /* will convert to IPv4-mapped address */
duke@0 831 memset((char *) caddr, 0, 16);
michaelm@5887 832 address = getInetAddress_addr(env, iaObj);
duke@0 833 if (address == INADDR_ANY) {
duke@0 834 /* we would always prefer IPv6 wildcard address
duke@0 835 caddr[10] = 0xff;
duke@0 836 caddr[11] = 0xff; */
duke@0 837 } else {
duke@0 838 caddr[10] = 0xff;
duke@0 839 caddr[11] = 0xff;
duke@0 840 caddr[12] = ((address >> 24) & 0xff);
duke@0 841 caddr[13] = ((address >> 16) & 0xff);
duke@0 842 caddr[14] = ((address >> 8) & 0xff);
duke@0 843 caddr[15] = (address & 0xff);
duke@0 844 }
duke@0 845 } else {
michaelm@6685 846 getInet6Address_ipaddress(env, iaObj, (char *)caddr);
duke@0 847 }
duke@0 848 memset((char *)him6, 0, sizeof(struct sockaddr_in6));
duke@0 849 him6->sin6_port = htons(port);
duke@0 850 memcpy((void *)&(him6->sin6_addr), caddr, sizeof(struct in6_addr) );
duke@0 851 him6->sin6_family = AF_INET6;
duke@0 852 *len = sizeof(struct sockaddr_in6) ;
duke@0 853
michaelm@4628 854 #if defined(_ALLBSD_SOURCE) && defined(_AF_INET6)
michaelm@4628 855 // XXXBSD: should we do something with scope id here ? see below linux comment
michaelm@4628 856 /* MMM: Come back to this! */
michaelm@4628 857 #endif
michaelm@4628 858
duke@0 859 /*
duke@0 860 * On Linux if we are connecting to a link-local address
duke@0 861 * we need to specify the interface in the scope_id (2.4 kernel only)
duke@0 862 *
duke@0 863 * If the scope was cached the we use the cached value. If not cached but
duke@0 864 * specified in the Inet6Address we use that, but we first check if the
duke@0 865 * address needs to be routed via the loopback interface. In this case,
duke@0 866 * we override the specified value with that of the loopback interface.
duke@0 867 * If no cached value exists and no value was specified by user, then
duke@0 868 * we try to determine a value ffrom the routing table. In all these
duke@0 869 * cases the used value is cached for further use.
duke@0 870 */
duke@0 871 #ifdef __linux__
duke@0 872 if (IN6_IS_ADDR_LINKLOCAL(&(him6->sin6_addr))) {
duke@0 873 int cached_scope_id = 0, scope_id = 0;
duke@0 874 int old_kernel = kernelIsV22();
duke@0 875
duke@0 876 if (ia6_cachedscopeidID && !old_kernel) {
duke@0 877 cached_scope_id = (int)(*env)->GetIntField(env, iaObj, ia6_cachedscopeidID);
duke@0 878 /* if cached value exists then use it. Otherwise, check
duke@0 879 * if scope is set in the address.
duke@0 880 */
duke@0 881 if (!cached_scope_id) {
duke@0 882 if (ia6_scopeidID) {
michaelm@6685 883 scope_id = getInet6Address_scopeid(env, iaObj);
duke@0 884 }
duke@0 885 if (scope_id != 0) {
duke@0 886 /* check user-specified value for loopback case
duke@0 887 * that needs to be overridden
duke@0 888 */
duke@0 889 if (kernelIsV24() && needsLoopbackRoute (&him6->sin6_addr)) {
duke@0 890 cached_scope_id = lo_scope_id;
duke@0 891 (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id);
duke@0 892 }
duke@0 893 } else {
duke@0 894 /*
duke@0 895 * Otherwise consult the IPv6 routing tables to
duke@0 896 * try determine the appropriate interface.
duke@0 897 */
duke@0 898 if (kernelIsV24()) {
duke@0 899 cached_scope_id = getDefaultIPv6Interface( &(him6->sin6_addr) );
duke@0 900 } else {
duke@0 901 cached_scope_id = getLocalScopeID( (char *)&(him6->sin6_addr) );
duke@0 902 if (cached_scope_id == 0) {
duke@0 903 cached_scope_id = getDefaultIPv6Interface( &(him6->sin6_addr) );
duke@0 904 }
duke@0 905 }
duke@0 906 (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id);
duke@0 907 }
duke@0 908 }
duke@0 909 }
duke@0 910
duke@0 911 /*
duke@0 912 * If we have a scope_id use the extended form
duke@0 913 * of sockaddr_in6.
duke@0 914 */
duke@0 915
duke@0 916 if (!old_kernel) {
duke@0 917 struct sockaddr_in6 *him6 =
duke@0 918 (struct sockaddr_in6 *)him;
duke@0 919 him6->sin6_scope_id = cached_scope_id != 0 ?
duke@0 920 cached_scope_id : scope_id;
duke@0 921 *len = sizeof(struct sockaddr_in6);
duke@0 922 }
duke@0 923 }
duke@0 924 #else
duke@0 925 /* handle scope_id for solaris */
duke@0 926
duke@0 927 if (family != IPv4) {
duke@0 928 if (ia6_scopeidID) {
michaelm@6685 929 him6->sin6_scope_id = getInet6Address_scopeid(env, iaObj);
duke@0 930 }
duke@0 931 }
duke@0 932 #endif
duke@0 933 } else
duke@0 934 #endif /* AF_INET6 */
duke@0 935 {
duke@0 936 struct sockaddr_in *him4 = (struct sockaddr_in*)him;
duke@0 937 jint address;
duke@0 938 if (family == IPv6) {
duke@0 939 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable");
duke@0 940 return -1;
duke@0 941 }
duke@0 942 memset((char *) him4, 0, sizeof(struct sockaddr_in));
michaelm@5887 943 address = getInetAddress_addr(env, iaObj);
duke@0 944 him4->sin_port = htons((short) port);
duke@0 945 him4->sin_addr.s_addr = (uint32_t) htonl(address);
duke@0 946 him4->sin_family = AF_INET;
duke@0 947 *len = sizeof(struct sockaddr_in);
duke@0 948 }
duke@0 949 return 0;
duke@0 950 }
duke@0 951
duke@0 952 void
duke@0 953 NET_SetTrafficClass(struct sockaddr *him, int trafficClass) {
duke@0 954 #ifdef AF_INET6
duke@0 955 if (him->sa_family == AF_INET6) {
duke@0 956 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
duke@0 957 him6->sin6_flowinfo = htonl((trafficClass & 0xff) << 20);
duke@0 958 }
duke@0 959 #endif /* AF_INET6 */
duke@0 960 }
duke@0 961
alanb@524 962 JNIEXPORT jint JNICALL
duke@0 963 NET_GetPortFromSockaddr(struct sockaddr *him) {
duke@0 964 #ifdef AF_INET6
duke@0 965 if (him->sa_family == AF_INET6) {
duke@0 966 return ntohs(((struct sockaddr_in6*)him)->sin6_port);
duke@0 967
duke@0 968 } else
duke@0 969 #endif /* AF_INET6 */
duke@0 970 {
duke@0 971 return ntohs(((struct sockaddr_in*)him)->sin_port);
duke@0 972 }
duke@0 973 }
duke@0 974
duke@0 975 int
duke@0 976 NET_IsIPv4Mapped(jbyte* caddr) {
duke@0 977 int i;
duke@0 978 for (i = 0; i < 10; i++) {
duke@0 979 if (caddr[i] != 0x00) {
duke@0 980 return 0; /* false */
duke@0 981 }
duke@0 982 }
duke@0 983
duke@0 984 if (((caddr[10] & 0xff) == 0xff) && ((caddr[11] & 0xff) == 0xff)) {
duke@0 985 return 1; /* true */
duke@0 986 }
duke@0 987 return 0; /* false */
duke@0 988 }
duke@0 989
duke@0 990 int
duke@0 991 NET_IPv4MappedToIPv4(jbyte* caddr) {
duke@0 992 return ((caddr[12] & 0xff) << 24) | ((caddr[13] & 0xff) << 16) | ((caddr[14] & 0xff) << 8)
duke@0 993 | (caddr[15] & 0xff);
duke@0 994 }
duke@0 995
duke@0 996 int
duke@0 997 NET_IsEqual(jbyte* caddr1, jbyte* caddr2) {
duke@0 998 int i;
duke@0 999 for (i = 0; i < 16; i++) {
duke@0 1000 if (caddr1[i] != caddr2[i]) {
duke@0 1001 return 0; /* false */
duke@0 1002 }
duke@0 1003 }
duke@0 1004 return 1;
duke@0 1005 }
duke@0 1006
duke@0 1007 jboolean NET_addrtransAvailable() {
duke@0 1008 return (jboolean)(getaddrinfo_ptr != NULL);
duke@0 1009 }
duke@0 1010
youdwei@5512 1011 int NET_IsZeroAddr(jbyte* caddr) {
youdwei@5512 1012 int i;
youdwei@5512 1013 for (i = 0; i < 16; i++) {
youdwei@5512 1014 if (caddr[i] != 0) {
youdwei@5512 1015 return 0;
youdwei@5512 1016 }
youdwei@5512 1017 }
youdwei@5512 1018 return 1;
youdwei@5512 1019 }
youdwei@5512 1020
duke@0 1021 /*
duke@0 1022 * Map the Java level socket option to the platform specific
duke@0 1023 * level and option name.
duke@0 1024 */
duke@0 1025 int
duke@0 1026 NET_MapSocketOption(jint cmd, int *level, int *optname) {
duke@0 1027 static struct {
duke@0 1028 jint cmd;
duke@0 1029 int level;
duke@0 1030 int optname;
duke@0 1031 } const opts[] = {
duke@0 1032 { java_net_SocketOptions_TCP_NODELAY, IPPROTO_TCP, TCP_NODELAY },
duke@0 1033 { java_net_SocketOptions_SO_OOBINLINE, SOL_SOCKET, SO_OOBINLINE },
duke@0 1034 { java_net_SocketOptions_SO_LINGER, SOL_SOCKET, SO_LINGER },
duke@0 1035 { java_net_SocketOptions_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF },
duke@0 1036 { java_net_SocketOptions_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF },
duke@0 1037 { java_net_SocketOptions_SO_KEEPALIVE, SOL_SOCKET, SO_KEEPALIVE },
duke@0 1038 { java_net_SocketOptions_SO_REUSEADDR, SOL_SOCKET, SO_REUSEADDR },
duke@0 1039 { java_net_SocketOptions_SO_BROADCAST, SOL_SOCKET, SO_BROADCAST },
duke@0 1040 { java_net_SocketOptions_IP_TOS, IPPROTO_IP, IP_TOS },
duke@0 1041 { java_net_SocketOptions_IP_MULTICAST_IF, IPPROTO_IP, IP_MULTICAST_IF },
duke@0 1042 { java_net_SocketOptions_IP_MULTICAST_IF2, IPPROTO_IP, IP_MULTICAST_IF },
duke@0 1043 { java_net_SocketOptions_IP_MULTICAST_LOOP, IPPROTO_IP, IP_MULTICAST_LOOP },
duke@0 1044 };
duke@0 1045
duke@0 1046 int i;
duke@0 1047
duke@0 1048 /*
duke@0 1049 * Different multicast options if IPv6 is enabled
duke@0 1050 */
duke@0 1051 #ifdef AF_INET6
duke@0 1052 if (ipv6_available()) {
duke@0 1053 switch (cmd) {
duke@0 1054 case java_net_SocketOptions_IP_MULTICAST_IF:
duke@0 1055 case java_net_SocketOptions_IP_MULTICAST_IF2:
duke@0 1056 *level = IPPROTO_IPV6;
duke@0 1057 *optname = IPV6_MULTICAST_IF;
duke@0 1058 return 0;
duke@0 1059
duke@0 1060 case java_net_SocketOptions_IP_MULTICAST_LOOP:
duke@0 1061 *level = IPPROTO_IPV6;
duke@0 1062 *optname = IPV6_MULTICAST_LOOP;
duke@0 1063 return 0;
duke@0 1064 }
duke@0 1065 }
duke@0 1066 #endif
duke@0 1067
duke@0 1068 /*
duke@0 1069 * Map the Java level option to the native level
duke@0 1070 */
duke@0 1071 for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
duke@0 1072 if (cmd == opts[i].cmd) {
duke@0 1073 *level = opts[i].level;
duke@0 1074 *optname = opts[i].optname;
duke@0 1075 return 0;
duke@0 1076 }
duke@0 1077 }
duke@0 1078
duke@0 1079 /* not found */
duke@0 1080 return -1;
duke@0 1081 }
duke@0 1082
duke@0 1083 /*
duke@0 1084 * Determine the default interface for an IPv6 address.
duke@0 1085 *
duke@0 1086 * 1. Scans /proc/net/ipv6_route for a matching route
duke@0 1087 * (eg: fe80::/10 or a route for the specific address).
duke@0 1088 * This will tell us the interface to use (eg: "eth0").
duke@0 1089 *
duke@0 1090 * 2. Lookup /proc/net/if_inet6 to map the interface
duke@0 1091 * name to an interface index.
duke@0 1092 *
duke@0 1093 * Returns :-
duke@0 1094 * -1 if error
duke@0 1095 * 0 if no matching interface
duke@0 1096 * >1 interface index to use for the link-local address.
duke@0 1097 */
duke@0 1098 #if defined(__linux__) && defined(AF_INET6)
duke@0 1099 int getDefaultIPv6Interface(struct in6_addr *target_addr) {
duke@0 1100 FILE *f;
duke@0 1101 char srcp[8][5];
duke@0 1102 char hopp[8][5];
duke@0 1103 int dest_plen, src_plen, use, refcnt, metric;
duke@0 1104 unsigned long flags;
duke@0 1105 char dest_str[40];
duke@0 1106 struct in6_addr dest_addr;
duke@0 1107 char device[16];
duke@0 1108 jboolean match = JNI_FALSE;
duke@0 1109
duke@0 1110 /*
duke@0 1111 * Scan /proc/net/ipv6_route looking for a matching
duke@0 1112 * route.
duke@0 1113 */
duke@0 1114 if ((f = fopen("/proc/net/ipv6_route", "r")) == NULL) {
duke@0 1115 return -1;
duke@0 1116 }
duke@0 1117 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
duke@0 1118 "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
duke@0 1119 "%4s%4s%4s%4s%4s%4s%4s%4s "
duke@0 1120 "%08x %08x %08x %08lx %8s",
duke@0 1121 dest_str, &dest_str[5], &dest_str[10], &dest_str[15],
duke@0 1122 &dest_str[20], &dest_str[25], &dest_str[30], &dest_str[35],
duke@0 1123 &dest_plen,
duke@0 1124 srcp[0], srcp[1], srcp[2], srcp[3],
duke@0 1125 srcp[4], srcp[5], srcp[6], srcp[7],
duke@0 1126 &src_plen,
duke@0 1127 hopp[0], hopp[1], hopp[2], hopp[3],
duke@0 1128 hopp[4], hopp[5], hopp[6], hopp[7],
duke@0 1129 &metric, &use, &refcnt, &flags, device) == 31) {
duke@0 1130
duke@0 1131 /*
duke@0 1132 * Some routes should be ignored
duke@0 1133 */
duke@0 1134 if ( (dest_plen < 0 || dest_plen > 128) ||
duke@0 1135 (src_plen != 0) ||
duke@0 1136 (flags & (RTF_POLICY | RTF_FLOW)) ||
duke@0 1137 ((flags & RTF_REJECT) && dest_plen == 0) ) {
duke@0 1138 continue;
duke@0 1139 }
duke@0 1140
duke@0 1141 /*
duke@0 1142 * Convert the destination address
duke@0 1143 */
duke@0 1144 dest_str[4] = ':';
duke@0 1145 dest_str[9] = ':';
duke@0 1146 dest_str[14] = ':';
duke@0 1147 dest_str[19] = ':';
duke@0 1148 dest_str[24] = ':';
duke@0 1149 dest_str[29] = ':';
duke@0 1150 dest_str[34] = ':';
duke@0 1151 dest_str[39] = '\0';
duke@0 1152
duke@0 1153 if (inet_pton(AF_INET6, dest_str, &dest_addr) < 0) {
duke@0 1154 /* not an Ipv6 address */
duke@0 1155 continue;
duke@0 1156 } else {
duke@0 1157 /*
duke@0 1158 * The prefix len (dest_plen) indicates the number of bits we
duke@0 1159 * need to match on.
duke@0 1160 *
duke@0 1161 * dest_plen / 8 => number of bytes to match
duke@0 1162 * dest_plen % 8 => number of additional bits to match
duke@0 1163 *
duke@0 1164 * eg: fe80::/10 => match 1 byte + 2 additional bits in the
duke@0 1165 * the next byte.
duke@0 1166 */
duke@0 1167 int byte_count = dest_plen >> 3;
duke@0 1168 int extra_bits = dest_plen & 0x3;
duke@0 1169
duke@0 1170 if (byte_count > 0) {
duke@0 1171 if (memcmp(target_addr, &dest_addr, byte_count)) {
duke@0 1172 continue; /* no match */
duke@0 1173 }
duke@0 1174 }
duke@0 1175
duke@0 1176 if (extra_bits > 0) {
duke@0 1177 unsigned char c1 = ((unsigned char *)target_addr)[byte_count];
duke@0 1178 unsigned char c2 = ((unsigned char *)&dest_addr)[byte_count];
duke@0 1179 unsigned char mask = 0xff << (8 - extra_bits);
duke@0 1180 if ((c1 & mask) != (c2 & mask)) {
duke@0 1181 continue;
duke@0 1182 }
duke@0 1183 }
duke@0 1184
duke@0 1185 /*
duke@0 1186 * We have a match
duke@0 1187 */
duke@0 1188 match = JNI_TRUE;
duke@0 1189 break;
duke@0 1190 }
duke@0 1191 }
duke@0 1192 fclose(f);
duke@0 1193
duke@0 1194 /*
duke@0 1195 * If there's a match then we lookup the interface
duke@0 1196 * index.
duke@0 1197 */
duke@0 1198 if (match) {
chegar@3657 1199 char devname[21];
duke@0 1200 char addr6p[8][5];
duke@0 1201 int plen, scope, dad_status, if_idx;
duke@0 1202
duke@0 1203 if ((f = fopen("/proc/net/if_inet6", "r")) != NULL) {
duke@0 1204 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
duke@0 1205 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
duke@0 1206 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
duke@0 1207 &if_idx, &plen, &scope, &dad_status, devname) == 13) {
duke@0 1208
duke@0 1209 if (strcmp(devname, device) == 0) {
duke@0 1210 /*
duke@0 1211 * Found - so just return the index
duke@0 1212 */
duke@0 1213 fclose(f);
duke@0 1214 return if_idx;
duke@0 1215 }
duke@0 1216 }
duke@0 1217 fclose(f);
duke@0 1218 } else {
duke@0 1219 /*
duke@0 1220 * Couldn't open /proc/net/if_inet6
duke@0 1221 */
duke@0 1222 return -1;
duke@0 1223 }
duke@0 1224 }
duke@0 1225
duke@0 1226 /*
duke@0 1227 * If we get here it means we didn't there wasn't any
duke@0 1228 * route or we couldn't get the index of the interface.
duke@0 1229 */
duke@0 1230 return 0;
duke@0 1231 }
duke@0 1232 #endif
duke@0 1233
duke@0 1234
duke@0 1235 /*
duke@0 1236 * Wrapper for getsockopt system routine - does any necessary
duke@0 1237 * pre/post processing to deal with OS specific oddies :-
duke@0 1238 *
duke@0 1239 * IP_TOS is a no-op with IPv6 sockets as it's setup when
duke@0 1240 * the connection is established.
duke@0 1241 *
duke@0 1242 * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed
duke@0 1243 * to compensate for an incorrect value returned by the kernel.
duke@0 1244 */
duke@0 1245 int
duke@0 1246 NET_GetSockOpt(int fd, int level, int opt, void *result,
duke@0 1247 int *len)
duke@0 1248 {
duke@0 1249 int rv;
duke@0 1250
duke@0 1251 #ifdef AF_INET6
duke@0 1252 if ((level == IPPROTO_IP) && (opt == IP_TOS)) {
duke@0 1253 if (ipv6_available()) {
duke@0 1254
duke@0 1255 /*
duke@0 1256 * For IPv6 socket option implemented at Java-level
duke@0 1257 * so return -1.
duke@0 1258 */
duke@0 1259 int *tc = (int *)result;
duke@0 1260 *tc = -1;
duke@0 1261 return 0;
duke@0 1262 }
duke@0 1263 }
duke@0 1264 #endif
duke@0 1265
chegar@454 1266 #ifdef __solaris__
chegar@454 1267 rv = getsockopt(fd, level, opt, result, len);
chegar@454 1268 #else
chegar@454 1269 {
chegar@454 1270 socklen_t socklen = *len;
chegar@454 1271 rv = getsockopt(fd, level, opt, result, &socklen);
chegar@454 1272 *len = socklen;
chegar@454 1273 }
chegar@454 1274 #endif
chegar@454 1275
duke@0 1276 if (rv < 0) {
duke@0 1277 return rv;
duke@0 1278 }
duke@0 1279
duke@0 1280 #ifdef __linux__
duke@0 1281 /*
duke@0 1282 * On Linux SO_SNDBUF/SO_RCVBUF aren't symmetric. This
duke@0 1283 * stems from additional socket structures in the send
duke@0 1284 * and receive buffers.
duke@0 1285 */
duke@0 1286 if ((level == SOL_SOCKET) && ((opt == SO_SNDBUF)
duke@0 1287 || (opt == SO_RCVBUF))) {
duke@0 1288 int n = *((int *)result);
duke@0 1289 n /= 2;
duke@0 1290 *((int *)result) = n;
duke@0 1291 }
duke@0 1292 #endif
duke@0 1293
michaelm@4634 1294 /* Workaround for Mac OS treating linger value as
michaelm@4634 1295 * signed integer
michaelm@4634 1296 */
michaelm@4634 1297 #ifdef MACOSX
michaelm@4634 1298 if (level == SOL_SOCKET && opt == SO_LINGER) {
michaelm@4634 1299 struct linger* to_cast = (struct linger*)result;
michaelm@4634 1300 to_cast->l_linger = (unsigned short)to_cast->l_linger;
michaelm@4634 1301 }
michaelm@4634 1302 #endif
duke@0 1303 return rv;
duke@0 1304 }
duke@0 1305
duke@0 1306 /*
duke@0 1307 * Wrapper for setsockopt system routine - performs any
duke@0 1308 * necessary pre/post processing to deal with OS specific
duke@0 1309 * issue :-
duke@0 1310 *
duke@0 1311 * On Solaris need to limit the suggested value for SO_SNDBUF
duke@0 1312 * and SO_RCVBUF to the kernel configured limit
duke@0 1313 *
duke@0 1314 * For IP_TOS socket option need to mask off bits as this
duke@0 1315 * aren't automatically masked by the kernel and results in
duke@0 1316 * an error. In addition IP_TOS is a noop with IPv6 as it
duke@0 1317 * should be setup as connection time.
duke@0 1318 */
duke@0 1319 int
duke@0 1320 NET_SetSockOpt(int fd, int level, int opt, const void *arg,
duke@0 1321 int len)
duke@0 1322 {
duke@0 1323 #ifndef IPTOS_TOS_MASK
duke@0 1324 #define IPTOS_TOS_MASK 0x1e
duke@0 1325 #endif
duke@0 1326 #ifndef IPTOS_PREC_MASK
duke@0 1327 #define IPTOS_PREC_MASK 0xe0
duke@0 1328 #endif
duke@0 1329
michaelm@4628 1330 #if defined(_ALLBSD_SOURCE)
michaelm@4628 1331 #if defined(KIPC_MAXSOCKBUF)
michaelm@4628 1332 int mib[3];
michaelm@4628 1333 size_t rlen;
michaelm@4628 1334 #endif
michaelm@4628 1335
michaelm@4628 1336 int *bufsize;
michaelm@4628 1337
michaelm@4628 1338 #ifdef __APPLE__
michaelm@4628 1339 static int maxsockbuf = -1;
michaelm@4628 1340 #else
michaelm@4628 1341 static long maxsockbuf = -1;
michaelm@4628 1342 #endif
michaelm@4628 1343
michaelm@4628 1344 int addopt;
michaelm@4628 1345 struct linger *ling;
michaelm@4628 1346 #endif
michaelm@4628 1347
duke@0 1348 /*
duke@0 1349 * IPPROTO/IP_TOS :-
khazra@4665 1350 * 1. IPv6 on Solaris/Mac OS: no-op and will be set
khazra@4665 1351 * in flowinfo field when connecting TCP socket,
khazra@4665 1352 * or sending UDP packet.
duke@0 1353 * 2. IPv6 on Linux: By default Linux ignores flowinfo
duke@0 1354 * field so enable IPV6_FLOWINFO_SEND so that flowinfo
duke@0 1355 * will be examined.
duke@0 1356 * 3. IPv4: set socket option based on ToS and Precedence
duke@0 1357 * fields (otherwise get invalid argument)
duke@0 1358 */
duke@0 1359 if (level == IPPROTO_IP && opt == IP_TOS) {
duke@0 1360 int *iptos;
duke@0 1361
khazra@4665 1362 #if defined(AF_INET6) && (defined(__solaris__) || defined(MACOSX))
duke@0 1363 if (ipv6_available()) {
duke@0 1364 return 0;
duke@0 1365 }
duke@0 1366 #endif
duke@0 1367
duke@0 1368 #if defined(AF_INET6) && defined(__linux__)
duke@0 1369 if (ipv6_available()) {
duke@0 1370 int optval = 1;
duke@0 1371 return setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
duke@0 1372 (void *)&optval, sizeof(optval));
duke@0 1373 }
duke@0 1374 #endif
duke@0 1375
duke@0 1376 iptos = (int *)arg;
duke@0 1377 *iptos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
duke@0 1378 }
duke@0 1379
duke@0 1380 /*
alanb@2827 1381 * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris we may need to clamp
alanb@2827 1382 * the value when it exceeds the system limit.
duke@0 1383 */
duke@0 1384 #ifdef __solaris__
duke@0 1385 if (level == SOL_SOCKET) {
duke@0 1386 if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
michaelm@3123 1387 int sotype=0, arglen;
duke@0 1388 int *bufsize, maxbuf;
alanb@2827 1389 int ret;
alanb@2827 1390
alanb@2827 1391 /* Attempt with the original size */
alanb@2827 1392 ret = setsockopt(fd, level, opt, arg, len);
alanb@2827 1393 if ((ret == 0) || (ret == -1 && errno != ENOBUFS))
alanb@2827 1394 return ret;
alanb@2827 1395
alanb@2827 1396 /* Exceeded system limit so clamp and retry */
duke@0 1397
duke@0 1398 arglen = sizeof(sotype);
duke@0 1399 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype,
duke@0 1400 &arglen) < 0) {
duke@0 1401 return -1;
duke@0 1402 }
duke@0 1403
michaelm@3123 1404 /*
michaelm@3123 1405 * We try to get tcp_maxbuf (and udp_max_buf) using
michaelm@3123 1406 * an ioctl() that isn't available on all versions of Solaris.
michaelm@3123 1407 * If that fails, we use the search algorithm in findMaxBuf()
michaelm@3123 1408 */
michaelm@3123 1409 if (!init_tcp_max_buf && sotype == SOCK_STREAM) {
michaelm@3123 1410 tcp_max_buf = getParam("/dev/tcp", "tcp_max_buf");
michaelm@3123 1411 if (tcp_max_buf == -1) {
michaelm@3123 1412 tcp_max_buf = findMaxBuf(fd, opt, SOCK_STREAM);
michaelm@3123 1413 if (tcp_max_buf == -1) {
michaelm@3123 1414 return -1;
michaelm@3123 1415 }
michaelm@3123 1416 }
michaelm@3123 1417 init_tcp_max_buf = 1;
michaelm@3123 1418 } else if (!init_udp_max_buf && sotype == SOCK_DGRAM) {
michaelm@3123 1419 udp_max_buf = getParam("/dev/udp", "udp_max_buf");
michaelm@3123 1420 if (udp_max_buf == -1) {
michaelm@3123 1421 udp_max_buf = findMaxBuf(fd, opt, SOCK_DGRAM);
michaelm@3123 1422 if (udp_max_buf == -1) {
michaelm@3123 1423 return -1;
michaelm@3123 1424 }
michaelm@3123 1425 }
michaelm@3123 1426 init_udp_max_buf = 1;
michaelm@3123 1427 }
michaelm@3123 1428
duke@0 1429 maxbuf = (sotype == SOCK_STREAM) ? tcp_max_buf : udp_max_buf;
duke@0 1430 bufsize = (int *)arg;
duke@0 1431 if (*bufsize > maxbuf) {
duke@0 1432 *bufsize = maxbuf;
duke@0 1433 }
duke@0 1434 }
duke@0 1435 }
duke@0 1436 #endif
duke@0 1437
duke@0 1438 /*
duke@0 1439 * On Linux the receive buffer is used for both socket
duke@0 1440 * structures and the the packet payload. The implication
duke@0 1441 * is that if SO_RCVBUF is too small then small packets
duke@0 1442 * must be discard.
duke@0 1443 */
duke@0 1444 #ifdef __linux__
duke@0 1445 if (level == SOL_SOCKET && opt == SO_RCVBUF) {
duke@0 1446 int *bufsize = (int *)arg;
duke@0 1447 if (*bufsize < 1024) {
duke@0 1448 *bufsize = 1024;
duke@0 1449 }
duke@0 1450 }
duke@0 1451 #endif
duke@0 1452
michaelm@4628 1453 #if defined(_ALLBSD_SOURCE)
michaelm@4628 1454 /*
michaelm@4628 1455 * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On FreeBSD need to
michaelm@4628 1456 * ensure that value is <= kern.ipc.maxsockbuf as otherwise we get
michaelm@4628 1457 * an ENOBUFS error.
michaelm@4628 1458 */
michaelm@4628 1459 if (level == SOL_SOCKET) {
michaelm@4628 1460 if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
michaelm@4628 1461 #ifdef KIPC_MAXSOCKBUF
michaelm@4628 1462 if (maxsockbuf == -1) {
michaelm@4628 1463 mib[0] = CTL_KERN;
michaelm@4628 1464 mib[1] = KERN_IPC;
michaelm@4628 1465 mib[2] = KIPC_MAXSOCKBUF;
michaelm@4628 1466 rlen = sizeof(maxsockbuf);
michaelm@4628 1467 if (sysctl(mib, 3, &maxsockbuf, &rlen, NULL, 0) == -1)
michaelm@4628 1468 maxsockbuf = 1024;
michaelm@4628 1469
michaelm@4628 1470 #if 1
michaelm@4628 1471 /* XXXBSD: This is a hack to workaround mb_max/mb_max_adj
michaelm@4628 1472 problem. It should be removed when kern.ipc.maxsockbuf
michaelm@4628 1473 will be real value. */
michaelm@4628 1474 maxsockbuf = (maxsockbuf/5)*4;
michaelm@4628 1475 #endif
michaelm@4628 1476 }
michaelm@4628 1477 #elif defined(__OpenBSD__)
michaelm@4628 1478 maxsockbuf = SB_MAX;
michaelm@4628 1479 #else
michaelm@4628 1480 maxsockbuf = 64 * 1024; /* XXX: NetBSD */
michaelm@4628 1481 #endif
michaelm@4628 1482
michaelm@4628 1483 bufsize = (int *)arg;
michaelm@4628 1484 if (*bufsize > maxsockbuf) {
michaelm@4628 1485 *bufsize = maxsockbuf;
michaelm@4628 1486 }
michaelm@4628 1487
michaelm@4628 1488 if (opt == SO_RCVBUF && *bufsize < 1024) {
michaelm@4628 1489 *bufsize = 1024;
michaelm@4628 1490 }
michaelm@4628 1491
michaelm@4628 1492 }
michaelm@4628 1493 }
michaelm@4628 1494
michaelm@4628 1495 /*
michaelm@4628 1496 * On Solaris, SO_REUSEADDR will allow multiple datagram
michaelm@4628 1497 * sockets to bind to the same port. The network jck tests
michaelm@4628 1498 * for this "feature", so we need to emulate it by turning on
michaelm@4628 1499 * SO_REUSEPORT as well for that combination.
michaelm@4628 1500 */
michaelm@4628 1501 if (level == SOL_SOCKET && opt == SO_REUSEADDR) {
michaelm@4628 1502 int sotype;
michaelm@4628 1503 socklen_t arglen;
michaelm@4628 1504
michaelm@4628 1505 arglen = sizeof(sotype);
michaelm@4628 1506 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype, &arglen) < 0) {
michaelm@4628 1507 return -1;
michaelm@4628 1508 }
michaelm@4628 1509
michaelm@4628 1510 if (sotype == SOCK_DGRAM) {
michaelm@4628 1511 addopt = SO_REUSEPORT;
michaelm@4628 1512 setsockopt(fd, level, addopt, arg, len);
michaelm@4628 1513 }
michaelm@4628 1514 }
michaelm@4628 1515
michaelm@4628 1516 #endif
michaelm@4628 1517
duke@0 1518 return setsockopt(fd, level, opt, arg, len);
duke@0 1519 }
duke@0 1520
duke@0 1521 /*
duke@0 1522 * Wrapper for bind system call - performs any necessary pre/post
duke@0 1523 * processing to deal with OS specific issues :-
duke@0 1524 *
duke@0 1525 * Linux allows a socket to bind to 127.0.0.255 which must be
duke@0 1526 * caught.
duke@0 1527 *
coffeys@5135 1528 * On Solaris with IPv6 enabled we must use an exclusive
duke@0 1529 * bind to guaranteed a unique port number across the IPv4 and
duke@0 1530 * IPv6 port spaces.
duke@0 1531 *
duke@0 1532 */
duke@0 1533 int
duke@0 1534 NET_Bind(int fd, struct sockaddr *him, int len)
duke@0 1535 {
duke@0 1536 #if defined(__solaris__) && defined(AF_INET6)
duke@0 1537 int level = -1;
duke@0 1538 int exclbind = -1;
duke@0 1539 #endif
duke@0 1540 int rv;
duke@0 1541
duke@0 1542 #ifdef __linux__
duke@0 1543 /*
duke@0 1544 * ## get bugId for this issue - goes back to 1.2.2 port ##
duke@0 1545 * ## When IPv6 is enabled this will be an IPv4-mapped
duke@0 1546 * ## with family set to AF_INET6
duke@0 1547 */
duke@0 1548 if (him->sa_family == AF_INET) {
duke@0 1549 struct sockaddr_in *sa = (struct sockaddr_in *)him;
duke@0 1550 if ((ntohl(sa->sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
duke@0 1551 errno = EADDRNOTAVAIL;
duke@0 1552 return -1;
duke@0 1553 }
duke@0 1554 }
duke@0 1555 #endif
duke@0 1556
duke@0 1557 #if defined(__solaris__) && defined(AF_INET6)
duke@0 1558 /*
coffeys@5135 1559 * Solaris has seperate IPv4 and IPv6 port spaces so we
duke@0 1560 * use an exclusive bind when SO_REUSEADDR is not used to
duke@0 1561 * give the illusion of a unified port space.
coffeys@5135 1562 * This also avoids problems with IPv6 sockets connecting
duke@0 1563 * to IPv4 mapped addresses whereby the socket conversion
duke@0 1564 * results in a late bind that fails because the
duke@0 1565 * corresponding IPv4 port is in use.
duke@0 1566 */
duke@0 1567 if (ipv6_available()) {
duke@0 1568 int arg, len;
duke@0 1569
duke@0 1570 len = sizeof(arg);
coffeys@5135 1571 if (useExclBind || getsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
coffeys@5135 1572 (char *)&arg, &len) == 0) {
coffeys@5135 1573 if (useExclBind || arg == 0) {
duke@0 1574 /*
coffeys@5135 1575 * SO_REUSEADDR is disabled or sun.net.useExclusiveBind
coffeys@5135 1576 * property is true so enable TCP_EXCLBIND or
duke@0 1577 * UDP_EXCLBIND
duke@0 1578 */
duke@0 1579 len = sizeof(arg);
duke@0 1580 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg,
duke@0 1581 &len) == 0) {
duke@0 1582 if (arg == SOCK_STREAM) {
duke@0 1583 level = IPPROTO_TCP;
duke@0 1584 exclbind = TCP_EXCLBIND;
duke@0 1585 } else {
duke@0 1586 level = IPPROTO_UDP;
duke@0 1587 exclbind = UDP_EXCLBIND;
duke@0 1588 }
duke@0 1589 }
duke@0 1590
duke@0 1591 arg = 1;
duke@0 1592 setsockopt(fd, level, exclbind, (char *)&arg,
duke@0 1593 sizeof(arg));
duke@0 1594 }
duke@0 1595 }
duke@0 1596 }
duke@0 1597
duke@0 1598 #endif
duke@0 1599
duke@0 1600 rv = bind(fd, him, len);
duke@0 1601
duke@0 1602 #if defined(__solaris__) && defined(AF_INET6)
duke@0 1603 if (rv < 0) {
duke@0 1604 int en = errno;
duke@0 1605 /* Restore *_EXCLBIND if the bind fails */
duke@0 1606 if (exclbind != -1) {
duke@0 1607 int arg = 0;
duke@0 1608 setsockopt(fd, level, exclbind, (char *)&arg,
duke@0 1609 sizeof(arg));
duke@0 1610 }
duke@0 1611 errno = en;
duke@0 1612 }
duke@0 1613 #endif
duke@0 1614
duke@0 1615 return rv;
duke@0 1616 }
duke@0 1617
duke@0 1618 /**
duke@0 1619 * Wrapper for select/poll with timeout on a single file descriptor.
duke@0 1620 *
duke@0 1621 * flags (defined in net_util_md.h can be any combination of
duke@0 1622 * NET_WAIT_READ, NET_WAIT_WRITE & NET_WAIT_CONNECT.
duke@0 1623 *
duke@0 1624 * The function will return when either the socket is ready for one
duke@0 1625 * of the specified operation or the timeout expired.
duke@0 1626 *
duke@0 1627 * It returns the time left from the timeout (possibly 0), or -1 if it expired.
duke@0 1628 */
duke@0 1629
duke@0 1630 jint
duke@0 1631 NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout)
duke@0 1632 {
duke@0 1633 jlong prevTime = JVM_CurrentTimeMillis(env, 0);
duke@0 1634 jint read_rv;
duke@0 1635
duke@0 1636 while (1) {
duke@0 1637 jlong newTime;
duke@0 1638 #ifndef USE_SELECT
duke@0 1639 {
duke@0 1640 struct pollfd pfd;
duke@0 1641 pfd.fd = fd;
duke@0 1642 pfd.events = 0;
duke@0 1643 if (flags & NET_WAIT_READ)
duke@0 1644 pfd.events |= POLLIN;
duke@0 1645 if (flags & NET_WAIT_WRITE)
duke@0 1646 pfd.events |= POLLOUT;
duke@0 1647 if (flags & NET_WAIT_CONNECT)
duke@0 1648 pfd.events |= POLLOUT;
duke@0 1649
duke@0 1650 errno = 0;
duke@0 1651 read_rv = NET_Poll(&pfd, 1, timeout);
duke@0 1652 }
duke@0 1653 #else
duke@0 1654 {
duke@0 1655 fd_set rd, wr, ex;
duke@0 1656 struct timeval t;
duke@0 1657
duke@0 1658 t.tv_sec = timeout / 1000;
duke@0 1659 t.tv_usec = (timeout % 1000) * 1000;
duke@0 1660
duke@0 1661 FD_ZERO(&rd);
duke@0 1662 FD_ZERO(&wr);
duke@0 1663 FD_ZERO(&ex);
duke@0 1664 if (flags & NET_WAIT_READ) {
duke@0 1665 FD_SET(fd, &rd);
duke@0 1666 }
duke@0 1667 if (flags & NET_WAIT_WRITE) {
duke@0 1668 FD_SET(fd, &wr);
duke@0 1669 }
duke@0 1670 if (flags & NET_WAIT_CONNECT) {
duke@0 1671 FD_SET(fd, &wr);
duke@0 1672 FD_SET(fd, &ex);
duke@0 1673 }
duke@0 1674
duke@0 1675 errno = 0;
duke@0 1676 read_rv = NET_Select(fd+1, &rd, &wr, &ex, &t);
duke@0 1677 }
duke@0 1678 #endif
duke@0 1679
duke@0 1680 newTime = JVM_CurrentTimeMillis(env, 0);
duke@0 1681 timeout -= (newTime - prevTime);
duke@0 1682 if (timeout <= 0) {
duke@0 1683 return read_rv > 0 ? 0 : -1;
duke@0 1684 }
duke@0 1685 newTime = prevTime;
duke@0 1686
duke@0 1687 if (read_rv > 0) {
duke@0 1688 break;
duke@0 1689 }
duke@0 1690
duke@0 1691
duke@0 1692 } /* while */
duke@0 1693
duke@0 1694 return timeout;
duke@0 1695 }