annotate src/solaris/native/java/net/net_util_md.c @ 594:14f50aee4989

6754988: Update copyright year Summary: Update for files that have been modified starting July 2008 Reviewed-by: ohair, tbell
author xdono
date Thu, 02 Oct 2008 19:58:32 -0700
parents 343253d05123
children 8df0ffac7f4d
rev   line source
duke@0 1 /*
xdono@594 2 * Copyright 1997-2008 Sun Microsystems, Inc. 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
duke@0 7 * published by the Free Software Foundation. Sun designates this
duke@0 8 * particular file as subject to the "Classpath" exception as provided
duke@0 9 * by Sun 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 *
duke@0 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@0 22 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@0 23 * have any 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>
duke@0 36
duke@0 37 #ifdef __solaris__
duke@0 38 #include <sys/sockio.h>
duke@0 39 #include <stropts.h>
duke@0 40 #include <inet/nd.h>
duke@0 41 #endif
duke@0 42
duke@0 43 #ifdef __linux__
duke@0 44 #include <arpa/inet.h>
duke@0 45 #include <net/route.h>
duke@0 46 #include <sys/utsname.h>
duke@0 47
duke@0 48 #ifndef IPV6_FLOWINFO_SEND
duke@0 49 #define IPV6_FLOWINFO_SEND 33
duke@0 50 #endif
duke@0 51
duke@0 52 #endif
duke@0 53
duke@0 54 #include "jni_util.h"
duke@0 55 #include "jvm.h"
duke@0 56 #include "net_util.h"
duke@0 57
duke@0 58 #include "java_net_SocketOptions.h"
duke@0 59
duke@0 60 /* needed from libsocket on Solaris 8 */
duke@0 61
duke@0 62 getaddrinfo_f getaddrinfo_ptr = NULL;
duke@0 63 freeaddrinfo_f freeaddrinfo_ptr = NULL;
duke@0 64 getnameinfo_f getnameinfo_ptr = NULL;
duke@0 65
duke@0 66 /*
duke@0 67 * EXCLBIND socket options only on Solaris 8 & 9.
duke@0 68 */
duke@0 69 #if defined(__solaris__) && !defined(TCP_EXCLBIND)
duke@0 70 #define TCP_EXCLBIND 0x21
duke@0 71 #endif
duke@0 72 #if defined(__solaris__) && !defined(UDP_EXCLBIND)
duke@0 73 #define UDP_EXCLBIND 0x0101
duke@0 74 #endif
duke@0 75
duke@0 76 #ifdef __solaris__
duke@0 77 static int init_max_buf;
duke@0 78 static int tcp_max_buf;
duke@0 79 static int udp_max_buf;
duke@0 80
duke@0 81 /*
duke@0 82 * Get the specified parameter from the specified driver. The value
duke@0 83 * of the parameter is assumed to be an 'int'. If the parameter
duke@0 84 * cannot be obtained return the specified default value.
duke@0 85 */
duke@0 86 static int
duke@0 87 getParam(char *driver, char *param, int dflt)
duke@0 88 {
duke@0 89 struct strioctl stri;
duke@0 90 char buf [64];
duke@0 91 int s;
duke@0 92 int value;
duke@0 93
duke@0 94 s = open (driver, O_RDWR);
duke@0 95 if (s < 0) {
duke@0 96 return dflt;
duke@0 97 }
duke@0 98 strncpy (buf, param, sizeof(buf));
duke@0 99 stri.ic_cmd = ND_GET;
duke@0 100 stri.ic_timout = 0;
duke@0 101 stri.ic_dp = buf;
duke@0 102 stri.ic_len = sizeof(buf);
duke@0 103 if (ioctl (s, I_STR, &stri) < 0) {
duke@0 104 value = dflt;
duke@0 105 } else {
duke@0 106 value = atoi(buf);
duke@0 107 }
duke@0 108 close (s);
duke@0 109 return value;
duke@0 110 }
duke@0 111 #endif
duke@0 112
duke@0 113 #ifdef __linux__
duke@0 114 static int kernelV22 = 0;
duke@0 115 static int vinit = 0;
duke@0 116
duke@0 117 int kernelIsV22 () {
duke@0 118 if (!vinit) {
duke@0 119 struct utsname sysinfo;
duke@0 120 if (uname(&sysinfo) == 0) {
duke@0 121 sysinfo.release[3] = '\0';
duke@0 122 if (strcmp(sysinfo.release, "2.2") == 0) {
duke@0 123 kernelV22 = JNI_TRUE;
duke@0 124 }
duke@0 125 }
duke@0 126 vinit = 1;
duke@0 127 }
duke@0 128 return kernelV22;
duke@0 129 }
duke@0 130
duke@0 131 static int kernelV24 = 0;
duke@0 132 static int vinit24 = 0;
duke@0 133
duke@0 134 int kernelIsV24 () {
duke@0 135 if (!vinit24) {
duke@0 136 struct utsname sysinfo;
duke@0 137 if (uname(&sysinfo) == 0) {
duke@0 138 sysinfo.release[3] = '\0';
duke@0 139 if (strcmp(sysinfo.release, "2.4") == 0) {
duke@0 140 kernelV24 = JNI_TRUE;
duke@0 141 }
duke@0 142 }
duke@0 143 vinit24 = 1;
duke@0 144 }
duke@0 145 return kernelV24;
duke@0 146 }
duke@0 147
duke@0 148 int getScopeID (struct sockaddr *him) {
duke@0 149 struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him;
duke@0 150 if (kernelIsV22()) {
duke@0 151 return 0;
duke@0 152 }
duke@0 153 return hext->sin6_scope_id;
duke@0 154 }
duke@0 155
duke@0 156 int cmpScopeID (unsigned int scope, struct sockaddr *him) {
duke@0 157 struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him;
duke@0 158 if (kernelIsV22()) {
duke@0 159 return 1; /* scope is ignored for comparison in 2.2 kernel */
duke@0 160 }
duke@0 161 return hext->sin6_scope_id == scope;
duke@0 162 }
duke@0 163
duke@0 164 #else
duke@0 165
duke@0 166 int getScopeID (struct sockaddr *him) {
duke@0 167 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
duke@0 168 return him6->sin6_scope_id;
duke@0 169 }
duke@0 170
duke@0 171 int cmpScopeID (unsigned int scope, struct sockaddr *him) {
duke@0 172 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
duke@0 173 return him6->sin6_scope_id == scope;
duke@0 174 }
duke@0 175
duke@0 176 #endif
duke@0 177
duke@0 178
duke@0 179 void
duke@0 180 NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
duke@0 181 const char *defaultDetail) {
duke@0 182 char errmsg[255];
duke@0 183 sprintf(errmsg, "errno: %d, error: %s\n", errno, defaultDetail);
duke@0 184 JNU_ThrowByNameWithLastError(env, name, errmsg);
duke@0 185 }
duke@0 186
duke@0 187 void
duke@0 188 NET_ThrowCurrent(JNIEnv *env, char *msg) {
duke@0 189 NET_ThrowNew(env, errno, msg);
duke@0 190 }
duke@0 191
duke@0 192 void
duke@0 193 NET_ThrowNew(JNIEnv *env, int errorNumber, char *msg) {
duke@0 194 char fullMsg[512];
duke@0 195 if (!msg) {
duke@0 196 msg = "no further information";
duke@0 197 }
duke@0 198 switch(errorNumber) {
duke@0 199 case EBADF:
duke@0 200 jio_snprintf(fullMsg, sizeof(fullMsg), "socket closed: %s", msg);
duke@0 201 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);
duke@0 202 break;
duke@0 203 case EINTR:
duke@0 204 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", msg);
duke@0 205 break;
duke@0 206 default:
duke@0 207 errno = errorNumber;
duke@0 208 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", msg);
duke@0 209 break;
duke@0 210 }
duke@0 211 }
duke@0 212
duke@0 213
duke@0 214 jfieldID
duke@0 215 NET_GetFileDescriptorID(JNIEnv *env)
duke@0 216 {
duke@0 217 jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor");
duke@0 218 CHECK_NULL_RETURN(cls, NULL);
duke@0 219 return (*env)->GetFieldID(env, cls, "fd", "I");
duke@0 220 }
duke@0 221
duke@0 222 jint IPv6_supported()
duke@0 223 {
duke@0 224 #ifndef AF_INET6
duke@0 225 return JNI_FALSE;
duke@0 226 #endif
duke@0 227
duke@0 228 #ifdef AF_INET6
duke@0 229 int fd;
duke@0 230 void *ipv6_fn;
duke@0 231 SOCKADDR sa;
chegar@453 232 socklen_t sa_len = sizeof(sa);
duke@0 233
duke@0 234 fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0) ;
duke@0 235 if (fd < 0) {
duke@0 236 /*
duke@0 237 * TODO: We really cant tell since it may be an unrelated error
duke@0 238 * for now we will assume that AF_INET6 is not available
duke@0 239 */
duke@0 240 return JNI_FALSE;
duke@0 241 }
duke@0 242
duke@0 243 /*
duke@0 244 * If fd 0 is a socket it means we've been launched from inetd or
duke@0 245 * xinetd. If it's a socket then check the family - if it's an
duke@0 246 * IPv4 socket then we need to disable IPv6.
duke@0 247 */
duke@0 248 if (getsockname(0, (struct sockaddr *)&sa, &sa_len) == 0) {
duke@0 249 struct sockaddr *saP = (struct sockaddr *)&sa;
duke@0 250 if (saP->sa_family != AF_INET6) {
duke@0 251 return JNI_FALSE;
duke@0 252 }
duke@0 253 }
duke@0 254
duke@0 255 /**
duke@0 256 * Linux - check if any interface has an IPv6 address.
duke@0 257 * Don't need to parse the line - we just need an indication.
duke@0 258 */
duke@0 259 #ifdef __linux__
duke@0 260 {
duke@0 261 FILE *fP = fopen("/proc/net/if_inet6", "r");
duke@0 262 char buf[255];
duke@0 263 char *bufP;
duke@0 264
duke@0 265 if (fP == NULL) {
duke@0 266 close(fd);
duke@0 267 return JNI_FALSE;
duke@0 268 }
duke@0 269 bufP = fgets(buf, sizeof(buf), fP);
duke@0 270 fclose(fP);
duke@0 271 if (bufP == NULL) {
duke@0 272 close(fd);
duke@0 273 return JNI_FALSE;
duke@0 274 }
duke@0 275 }
duke@0 276 #endif
duke@0 277
duke@0 278 /**
duke@0 279 * On Solaris 8 it's possible to create INET6 sockets even
duke@0 280 * though IPv6 is not enabled on all interfaces. Thus we
duke@0 281 * query the number of IPv6 addresses to verify that IPv6
duke@0 282 * has been configured on at least one interface.
duke@0 283 *
duke@0 284 * On Linux it doesn't matter - if IPv6 is built-in the
duke@0 285 * kernel then IPv6 addresses will be bound automatically
duke@0 286 * to all interfaces.
duke@0 287 */
duke@0 288 #ifdef __solaris__
duke@0 289
duke@0 290 #ifdef SIOCGLIFNUM
duke@0 291 {
duke@0 292 struct lifnum numifs;
duke@0 293
duke@0 294 numifs.lifn_family = AF_INET6;
duke@0 295 numifs.lifn_flags = 0;
duke@0 296 if (ioctl(fd, SIOCGLIFNUM, (char *)&numifs) < 0) {
duke@0 297 /**
duke@0 298 * SIOCGLIFNUM failed - assume IPv6 not configured
duke@0 299 */
duke@0 300 close(fd);
duke@0 301 return JNI_FALSE;
duke@0 302 }
duke@0 303 /**
duke@0 304 * If no IPv6 addresses then return false. If count > 0
duke@0 305 * it's possible that all IPv6 addresses are "down" but
duke@0 306 * that's okay as they may be brought "up" while the
duke@0 307 * VM is running.
duke@0 308 */
duke@0 309 if (numifs.lifn_count == 0) {
duke@0 310 close(fd);
duke@0 311 return JNI_FALSE;
duke@0 312 }
duke@0 313 }
duke@0 314 #else
duke@0 315 /* SIOCGLIFNUM not defined in build environment ??? */
duke@0 316 close(fd);
duke@0 317 return JNI_FALSE;
duke@0 318 #endif
duke@0 319
duke@0 320 #endif /* __solaris */
duke@0 321
duke@0 322 #endif /* AF_INET6 */
duke@0 323
duke@0 324 /*
duke@0 325 * OK we may have the stack available in the kernel,
duke@0 326 * we should also check if the APIs are available.
duke@0 327 */
duke@0 328 ipv6_fn = JVM_FindLibraryEntry(RTLD_DEFAULT, "inet_pton");
duke@0 329 if (ipv6_fn == NULL ) {
duke@0 330 close(fd);
duke@0 331 return JNI_FALSE;
duke@0 332 }
duke@0 333
duke@0 334 /*
duke@0 335 * We've got the library, let's get the pointers to some
duke@0 336 * IPV6 specific functions. We have to do that because, at least
duke@0 337 * on Solaris we may build on a system without IPV6 networking
duke@0 338 * libraries, therefore we can't have a hard link to these
duke@0 339 * functions.
duke@0 340 */
duke@0 341 getaddrinfo_ptr = (getaddrinfo_f)
duke@0 342 JVM_FindLibraryEntry(RTLD_DEFAULT, "getaddrinfo");
duke@0 343
duke@0 344 freeaddrinfo_ptr = (freeaddrinfo_f)
duke@0 345 JVM_FindLibraryEntry(RTLD_DEFAULT, "freeaddrinfo");
duke@0 346
duke@0 347 getnameinfo_ptr = (getnameinfo_f)
duke@0 348 JVM_FindLibraryEntry(RTLD_DEFAULT, "getnameinfo");
duke@0 349
duke@0 350 if (freeaddrinfo_ptr == NULL || getnameinfo_ptr == NULL) {
duke@0 351 /* Wee need all 3 of them */
duke@0 352 getaddrinfo_ptr = NULL;
duke@0 353 }
duke@0 354
duke@0 355 close(fd);
duke@0 356 return JNI_TRUE;
duke@0 357 }
duke@0 358
duke@0 359 void
duke@0 360 NET_AllocSockaddr(struct sockaddr **him, int *len) {
duke@0 361 #ifdef AF_INET6
duke@0 362 if (ipv6_available()) {
duke@0 363 struct sockaddr_in6 *him6 = (struct sockaddr_in6*)malloc(sizeof(struct sockaddr_in6));
duke@0 364 *him = (struct sockaddr*)him6;
duke@0 365 *len = sizeof(struct sockaddr_in6);
duke@0 366 } else
duke@0 367 #endif /* AF_INET6 */
duke@0 368 {
duke@0 369 struct sockaddr_in *him4 = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
duke@0 370 *him = (struct sockaddr*)him4;
duke@0 371 *len = sizeof(struct sockaddr_in);
duke@0 372 }
duke@0 373 }
duke@0 374
duke@0 375 #if defined(__linux__) && defined(AF_INET6)
duke@0 376
duke@0 377
duke@0 378 /* following code creates a list of addresses from the kernel
duke@0 379 * routing table that are routed via the loopback address.
duke@0 380 * We check all destination addresses against this table
duke@0 381 * and override the scope_id field to use the relevant value for "lo"
duke@0 382 * in order to work-around the Linux bug that prevents packets destined
duke@0 383 * for certain local addresses from being sent via a physical interface.
duke@0 384 */
duke@0 385
duke@0 386 struct loopback_route {
duke@0 387 struct in6_addr addr; /* destination address */
duke@0 388 int plen; /* prefix length */
duke@0 389 };
duke@0 390
duke@0 391 static struct loopback_route *loRoutes = 0;
duke@0 392 static int nRoutes = 0; /* number of routes */
duke@0 393 static int loRoutes_size = 16; /* initial size */
duke@0 394 static int lo_scope_id = 0;
duke@0 395
duke@0 396 static void initLoopbackRoutes();
duke@0 397
duke@0 398 void printAddr (struct in6_addr *addr) {
duke@0 399 int i;
duke@0 400 for (i=0; i<16; i++) {
duke@0 401 printf ("%02x", addr->s6_addr[i]);
duke@0 402 }
duke@0 403 printf ("\n");
duke@0 404 }
duke@0 405
duke@0 406 static jboolean needsLoopbackRoute (struct in6_addr* dest_addr) {
duke@0 407 int byte_count;
duke@0 408 int extra_bits, i;
duke@0 409 struct loopback_route *ptr;
duke@0 410
duke@0 411 if (loRoutes == 0) {
duke@0 412 initLoopbackRoutes();
duke@0 413 }
duke@0 414
duke@0 415 for (ptr = loRoutes, i=0; i<nRoutes; i++, ptr++) {
duke@0 416 struct in6_addr *target_addr=&ptr->addr;
duke@0 417 int dest_plen = ptr->plen;
duke@0 418 byte_count = dest_plen >> 3;
duke@0 419 extra_bits = dest_plen & 0x3;
duke@0 420
duke@0 421 if (byte_count > 0) {
duke@0 422 if (memcmp(target_addr, dest_addr, byte_count)) {
duke@0 423 continue; /* no match */
duke@0 424 }
duke@0 425 }
duke@0 426
duke@0 427 if (extra_bits > 0) {
duke@0 428 unsigned char c1 = ((unsigned char *)target_addr)[byte_count];
duke@0 429 unsigned char c2 = ((unsigned char *)&dest_addr)[byte_count];
duke@0 430 unsigned char mask = 0xff << (8 - extra_bits);
duke@0 431 if ((c1 & mask) != (c2 & mask)) {
duke@0 432 continue;
duke@0 433 }
duke@0 434 }
duke@0 435 return JNI_TRUE;
duke@0 436 }
duke@0 437 return JNI_FALSE;
duke@0 438 }
duke@0 439
duke@0 440
duke@0 441 static void initLoopbackRoutes() {
duke@0 442 FILE *f;
duke@0 443 char srcp[8][5];
duke@0 444 char hopp[8][5];
duke@0 445 int dest_plen, src_plen, use, refcnt, metric;
duke@0 446 unsigned long flags;
duke@0 447 char dest_str[40];
duke@0 448 struct in6_addr dest_addr;
duke@0 449 char device[16];
duke@0 450
duke@0 451 if (loRoutes != 0) {
duke@0 452 free (loRoutes);
duke@0 453 }
duke@0 454 loRoutes = calloc (loRoutes_size, sizeof(struct loopback_route));
duke@0 455 if (loRoutes == 0) {
duke@0 456 return;
duke@0 457 }
duke@0 458 /*
duke@0 459 * Scan /proc/net/ipv6_route looking for a matching
duke@0 460 * route.
duke@0 461 */
duke@0 462 if ((f = fopen("/proc/net/ipv6_route", "r")) == NULL) {
duke@0 463 return ;
duke@0 464 }
duke@0 465 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
duke@0 466 "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
duke@0 467 "%4s%4s%4s%4s%4s%4s%4s%4s "
duke@0 468 "%08x %08x %08x %08lx %8s",
duke@0 469 dest_str, &dest_str[5], &dest_str[10], &dest_str[15],
duke@0 470 &dest_str[20], &dest_str[25], &dest_str[30], &dest_str[35],
duke@0 471 &dest_plen,
duke@0 472 srcp[0], srcp[1], srcp[2], srcp[3],
duke@0 473 srcp[4], srcp[5], srcp[6], srcp[7],
duke@0 474 &src_plen,
duke@0 475 hopp[0], hopp[1], hopp[2], hopp[3],
duke@0 476 hopp[4], hopp[5], hopp[6], hopp[7],
duke@0 477 &metric, &use, &refcnt, &flags, device) == 31) {
duke@0 478
duke@0 479 /*
duke@0 480 * Some routes should be ignored
duke@0 481 */
duke@0 482 if ( (dest_plen < 0 || dest_plen > 128) ||
duke@0 483 (src_plen != 0) ||
duke@0 484 (flags & (RTF_POLICY | RTF_FLOW)) ||
duke@0 485 ((flags & RTF_REJECT) && dest_plen == 0) ) {
duke@0 486 continue;
duke@0 487 }
duke@0 488
duke@0 489 /*
duke@0 490 * Convert the destination address
duke@0 491 */
duke@0 492 dest_str[4] = ':';
duke@0 493 dest_str[9] = ':';
duke@0 494 dest_str[14] = ':';
duke@0 495 dest_str[19] = ':';
duke@0 496 dest_str[24] = ':';
duke@0 497 dest_str[29] = ':';
duke@0 498 dest_str[34] = ':';
duke@0 499 dest_str[39] = '\0';
duke@0 500
duke@0 501 if (inet_pton(AF_INET6, dest_str, &dest_addr) < 0) {
duke@0 502 /* not an Ipv6 address */
duke@0 503 continue;
duke@0 504 }
duke@0 505 if (strcmp(device, "lo") != 0) {
duke@0 506 /* Not a loopback route */
duke@0 507 continue;
duke@0 508 } else {
duke@0 509 if (nRoutes == loRoutes_size) {
duke@0 510 loRoutes = realloc (loRoutes, loRoutes_size *
duke@0 511 sizeof (struct loopback_route) * 2);
duke@0 512 if (loRoutes == 0) {
duke@0 513 return ;
duke@0 514 }
duke@0 515 loRoutes_size *= 2;
duke@0 516 }
duke@0 517 memcpy (&loRoutes[nRoutes].addr,&dest_addr,sizeof(struct in6_addr));
duke@0 518 loRoutes[nRoutes].plen = dest_plen;
duke@0 519 nRoutes ++;
duke@0 520 }
duke@0 521 }
duke@0 522
duke@0 523 fclose (f);
duke@0 524 {
duke@0 525 /* now find the scope_id for "lo" */
duke@0 526
chegar@453 527 char devname[20];
duke@0 528 char addr6p[8][5];
duke@0 529 int plen, scope, dad_status, if_idx;
duke@0 530
duke@0 531 if ((f = fopen("/proc/net/if_inet6", "r")) != NULL) {
duke@0 532 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
duke@0 533 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
duke@0 534 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
duke@0 535 &if_idx, &plen, &scope, &dad_status, devname) == 13) {
duke@0 536
duke@0 537 if (strcmp(devname, "lo") == 0) {
duke@0 538 /*
duke@0 539 * Found - so just return the index
duke@0 540 */
duke@0 541 fclose(f);
duke@0 542 lo_scope_id = if_idx;
duke@0 543 return;
duke@0 544 }
duke@0 545 }
duke@0 546 fclose(f);
duke@0 547 }
duke@0 548 }
duke@0 549 }
duke@0 550
duke@0 551 /*
duke@0 552 * Following is used for binding to local addresses. Equivalent
duke@0 553 * to code above, for bind().
duke@0 554 */
duke@0 555
duke@0 556 struct localinterface {
duke@0 557 int index;
duke@0 558 char localaddr [16];
duke@0 559 };
duke@0 560
duke@0 561 static struct localinterface *localifs = 0;
duke@0 562 static int localifsSize = 0; /* size of array */
duke@0 563 static int nifs = 0; /* number of entries used in array */
duke@0 564
duke@0 565 /* not thread safe: make sure called once from one thread */
duke@0 566
duke@0 567 static void initLocalIfs () {
duke@0 568 FILE *f;
duke@0 569 unsigned char staddr [16];
duke@0 570 char ifname [32];
duke@0 571 struct localinterface *lif=0;
duke@0 572 int index, x1, x2, x3;
duke@0 573 unsigned int u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,ua,ub,uc,ud,ue,uf;
duke@0 574
duke@0 575 if ((f = fopen("/proc/net/if_inet6", "r")) == NULL) {
duke@0 576 return ;
duke@0 577 }
duke@0 578 while (fscanf (f, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x "
duke@0 579 "%d %x %x %x %s",&u0,&u1,&u2,&u3,&u4,&u5,&u6,&u7,
duke@0 580 &u8,&u9,&ua,&ub,&uc,&ud,&ue,&uf,
duke@0 581 &index, &x1, &x2, &x3, ifname) == 21) {
duke@0 582 staddr[0] = (unsigned char)u0;
duke@0 583 staddr[1] = (unsigned char)u1;
duke@0 584 staddr[2] = (unsigned char)u2;
duke@0 585 staddr[3] = (unsigned char)u3;
duke@0 586 staddr[4] = (unsigned char)u4;
duke@0 587 staddr[5] = (unsigned char)u5;
duke@0 588 staddr[6] = (unsigned char)u6;
duke@0 589 staddr[7] = (unsigned char)u7;
duke@0 590 staddr[8] = (unsigned char)u8;
duke@0 591 staddr[9] = (unsigned char)u9;
duke@0 592 staddr[10] = (unsigned char)ua;
duke@0 593 staddr[11] = (unsigned char)ub;
duke@0 594 staddr[12] = (unsigned char)uc;
duke@0 595 staddr[13] = (unsigned char)ud;
duke@0 596 staddr[14] = (unsigned char)ue;
duke@0 597 staddr[15] = (unsigned char)uf;
duke@0 598 nifs ++;
duke@0 599 if (nifs > localifsSize) {
duke@0 600 localifs = (struct localinterface *) realloc (
duke@0 601 localifs, sizeof (struct localinterface)* (localifsSize+5));
duke@0 602 if (localifs == 0) {
duke@0 603 nifs = 0;
duke@0 604 fclose (f);
duke@0 605 return;
duke@0 606 }
duke@0 607 lif = localifs + localifsSize;
duke@0 608 localifsSize += 5;
duke@0 609 } else {
duke@0 610 lif ++;
duke@0 611 }
duke@0 612 memcpy (lif->localaddr, staddr, 16);
duke@0 613 lif->index = index;
duke@0 614 }
duke@0 615 fclose (f);
duke@0 616 }
duke@0 617
duke@0 618 /* return the scope_id (interface index) of the
duke@0 619 * interface corresponding to the given address
duke@0 620 * returns 0 if no match found
duke@0 621 */
duke@0 622
duke@0 623 static int getLocalScopeID (char *addr) {
duke@0 624 struct localinterface *lif;
duke@0 625 int i;
duke@0 626 if (localifs == 0) {
duke@0 627 initLocalIfs();
duke@0 628 }
duke@0 629 for (i=0, lif=localifs; i<nifs; i++, lif++) {
duke@0 630 if (memcmp (addr, lif->localaddr, 16) == 0) {
duke@0 631 return lif->index;
duke@0 632 }
duke@0 633 }
duke@0 634 return 0;
duke@0 635 }
duke@0 636
duke@0 637 void initLocalAddrTable () {
duke@0 638 initLoopbackRoutes();
duke@0 639 initLocalIfs();
duke@0 640 }
duke@0 641
duke@0 642 #else
duke@0 643
duke@0 644 void initLocalAddrTable () {}
duke@0 645
duke@0 646 #endif
duke@0 647
duke@0 648 /* In the case of an IPv4 Inetaddress this method will return an
duke@0 649 * IPv4 mapped address where IPv6 is available and v4MappedAddress is TRUE.
duke@0 650 * Otherwise it will return a sockaddr_in structure for an IPv4 InetAddress.
duke@0 651 */
duke@0 652 JNIEXPORT int JNICALL
duke@0 653 NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him,
duke@0 654 int *len, jboolean v4MappedAddress) {
duke@0 655 jint family;
duke@0 656 family = (*env)->GetIntField(env, iaObj, ia_familyID);
duke@0 657 #ifdef AF_INET6
duke@0 658 /* needs work. 1. family 2. clean up him6 etc deallocate memory */
duke@0 659 if (ipv6_available() && !(family == IPv4 && v4MappedAddress == JNI_FALSE)) {
duke@0 660 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
duke@0 661 jbyteArray ipaddress;
duke@0 662 jbyte caddr[16];
duke@0 663 jint address;
duke@0 664
duke@0 665
duke@0 666 if (family == IPv4) { /* will convert to IPv4-mapped address */
duke@0 667 memset((char *) caddr, 0, 16);
duke@0 668 address = (*env)->GetIntField(env, iaObj, ia_addressID);
duke@0 669 if (address == INADDR_ANY) {
duke@0 670 /* we would always prefer IPv6 wildcard address
duke@0 671 caddr[10] = 0xff;
duke@0 672 caddr[11] = 0xff; */
duke@0 673 } else {
duke@0 674 caddr[10] = 0xff;
duke@0 675 caddr[11] = 0xff;
duke@0 676 caddr[12] = ((address >> 24) & 0xff);
duke@0 677 caddr[13] = ((address >> 16) & 0xff);
duke@0 678 caddr[14] = ((address >> 8) & 0xff);
duke@0 679 caddr[15] = (address & 0xff);
duke@0 680 }
duke@0 681 } else {
duke@0 682 ipaddress = (*env)->GetObjectField(env, iaObj, ia6_ipaddressID);
duke@0 683 (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddr);
duke@0 684 }
duke@0 685 memset((char *)him6, 0, sizeof(struct sockaddr_in6));
duke@0 686 him6->sin6_port = htons(port);
duke@0 687 memcpy((void *)&(him6->sin6_addr), caddr, sizeof(struct in6_addr) );
duke@0 688 him6->sin6_family = AF_INET6;
duke@0 689 *len = sizeof(struct sockaddr_in6) ;
duke@0 690
duke@0 691 /*
duke@0 692 * On Linux if we are connecting to a link-local address
duke@0 693 * we need to specify the interface in the scope_id (2.4 kernel only)
duke@0 694 *
duke@0 695 * If the scope was cached the we use the cached value. If not cached but
duke@0 696 * specified in the Inet6Address we use that, but we first check if the
duke@0 697 * address needs to be routed via the loopback interface. In this case,
duke@0 698 * we override the specified value with that of the loopback interface.
duke@0 699 * If no cached value exists and no value was specified by user, then
duke@0 700 * we try to determine a value ffrom the routing table. In all these
duke@0 701 * cases the used value is cached for further use.
duke@0 702 */
duke@0 703 #ifdef __linux__
duke@0 704 if (IN6_IS_ADDR_LINKLOCAL(&(him6->sin6_addr))) {
duke@0 705 int cached_scope_id = 0, scope_id = 0;
duke@0 706 int old_kernel = kernelIsV22();
duke@0 707
duke@0 708 if (ia6_cachedscopeidID && !old_kernel) {
duke@0 709 cached_scope_id = (int)(*env)->GetIntField(env, iaObj, ia6_cachedscopeidID);
duke@0 710 /* if cached value exists then use it. Otherwise, check
duke@0 711 * if scope is set in the address.
duke@0 712 */
duke@0 713 if (!cached_scope_id) {
duke@0 714 if (ia6_scopeidID) {
duke@0 715 scope_id = (int)(*env)->GetIntField(env,iaObj,ia6_scopeidID);
duke@0 716 }
duke@0 717 if (scope_id != 0) {
duke@0 718 /* check user-specified value for loopback case
duke@0 719 * that needs to be overridden
duke@0 720 */
duke@0 721 if (kernelIsV24() && needsLoopbackRoute (&him6->sin6_addr)) {
duke@0 722 cached_scope_id = lo_scope_id;
duke@0 723 (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id);
duke@0 724 }
duke@0 725 } else {
duke@0 726 /*
duke@0 727 * Otherwise consult the IPv6 routing tables to
duke@0 728 * try determine the appropriate interface.
duke@0 729 */
duke@0 730 if (kernelIsV24()) {
duke@0 731 cached_scope_id = getDefaultIPv6Interface( &(him6->sin6_addr) );
duke@0 732 } else {
duke@0 733 cached_scope_id = getLocalScopeID( (char *)&(him6->sin6_addr) );
duke@0 734 if (cached_scope_id == 0) {
duke@0 735 cached_scope_id = getDefaultIPv6Interface( &(him6->sin6_addr) );
duke@0 736 }
duke@0 737 }
duke@0 738 (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id);
duke@0 739 }
duke@0 740 }
duke@0 741 }
duke@0 742
duke@0 743 /*
duke@0 744 * If we have a scope_id use the extended form
duke@0 745 * of sockaddr_in6.
duke@0 746 */
duke@0 747
duke@0 748 if (!old_kernel) {
duke@0 749 struct sockaddr_in6 *him6 =
duke@0 750 (struct sockaddr_in6 *)him;
duke@0 751 him6->sin6_scope_id = cached_scope_id != 0 ?
duke@0 752 cached_scope_id : scope_id;
duke@0 753 *len = sizeof(struct sockaddr_in6);
duke@0 754 }
duke@0 755 }
duke@0 756 #else
duke@0 757 /* handle scope_id for solaris */
duke@0 758
duke@0 759 if (family != IPv4) {
duke@0 760 if (ia6_scopeidID) {
duke@0 761 him6->sin6_scope_id = (int)(*env)->GetIntField(env, iaObj, ia6_scopeidID);
duke@0 762 }
duke@0 763 }
duke@0 764 #endif
duke@0 765 } else
duke@0 766 #endif /* AF_INET6 */
duke@0 767 {
duke@0 768 struct sockaddr_in *him4 = (struct sockaddr_in*)him;
duke@0 769 jint address;
duke@0 770 if (family == IPv6) {
duke@0 771 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable");
duke@0 772 return -1;
duke@0 773 }
duke@0 774 memset((char *) him4, 0, sizeof(struct sockaddr_in));
duke@0 775 address = (*env)->GetIntField(env, iaObj, ia_addressID);
duke@0 776 him4->sin_port = htons((short) port);
duke@0 777 him4->sin_addr.s_addr = (uint32_t) htonl(address);
duke@0 778 him4->sin_family = AF_INET;
duke@0 779 *len = sizeof(struct sockaddr_in);
duke@0 780 }
duke@0 781 return 0;
duke@0 782 }
duke@0 783
duke@0 784 void
duke@0 785 NET_SetTrafficClass(struct sockaddr *him, int trafficClass) {
duke@0 786 #ifdef AF_INET6
duke@0 787 if (him->sa_family == AF_INET6) {
duke@0 788 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
duke@0 789 him6->sin6_flowinfo = htonl((trafficClass & 0xff) << 20);
duke@0 790 }
duke@0 791 #endif /* AF_INET6 */
duke@0 792 }
duke@0 793
alanb@524 794 JNIEXPORT jint JNICALL
duke@0 795 NET_GetPortFromSockaddr(struct sockaddr *him) {
duke@0 796 #ifdef AF_INET6
duke@0 797 if (him->sa_family == AF_INET6) {
duke@0 798 return ntohs(((struct sockaddr_in6*)him)->sin6_port);
duke@0 799
duke@0 800 } else
duke@0 801 #endif /* AF_INET6 */
duke@0 802 {
duke@0 803 return ntohs(((struct sockaddr_in*)him)->sin_port);
duke@0 804 }
duke@0 805 }
duke@0 806
duke@0 807 int
duke@0 808 NET_IsIPv4Mapped(jbyte* caddr) {
duke@0 809 int i;
duke@0 810 for (i = 0; i < 10; i++) {
duke@0 811 if (caddr[i] != 0x00) {
duke@0 812 return 0; /* false */
duke@0 813 }
duke@0 814 }
duke@0 815
duke@0 816 if (((caddr[10] & 0xff) == 0xff) && ((caddr[11] & 0xff) == 0xff)) {
duke@0 817 return 1; /* true */
duke@0 818 }
duke@0 819 return 0; /* false */
duke@0 820 }
duke@0 821
duke@0 822 int
duke@0 823 NET_IPv4MappedToIPv4(jbyte* caddr) {
duke@0 824 return ((caddr[12] & 0xff) << 24) | ((caddr[13] & 0xff) << 16) | ((caddr[14] & 0xff) << 8)
duke@0 825 | (caddr[15] & 0xff);
duke@0 826 }
duke@0 827
duke@0 828 int
duke@0 829 NET_IsEqual(jbyte* caddr1, jbyte* caddr2) {
duke@0 830 int i;
duke@0 831 for (i = 0; i < 16; i++) {
duke@0 832 if (caddr1[i] != caddr2[i]) {
duke@0 833 return 0; /* false */
duke@0 834 }
duke@0 835 }
duke@0 836 return 1;
duke@0 837 }
duke@0 838
duke@0 839 jboolean NET_addrtransAvailable() {
duke@0 840 return (jboolean)(getaddrinfo_ptr != NULL);
duke@0 841 }
duke@0 842
duke@0 843 /*
duke@0 844 * Map the Java level socket option to the platform specific
duke@0 845 * level and option name.
duke@0 846 */
duke@0 847 int
duke@0 848 NET_MapSocketOption(jint cmd, int *level, int *optname) {
duke@0 849 static struct {
duke@0 850 jint cmd;
duke@0 851 int level;
duke@0 852 int optname;
duke@0 853 } const opts[] = {
duke@0 854 { java_net_SocketOptions_TCP_NODELAY, IPPROTO_TCP, TCP_NODELAY },
duke@0 855 { java_net_SocketOptions_SO_OOBINLINE, SOL_SOCKET, SO_OOBINLINE },
duke@0 856 { java_net_SocketOptions_SO_LINGER, SOL_SOCKET, SO_LINGER },
duke@0 857 { java_net_SocketOptions_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF },
duke@0 858 { java_net_SocketOptions_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF },
duke@0 859 { java_net_SocketOptions_SO_KEEPALIVE, SOL_SOCKET, SO_KEEPALIVE },
duke@0 860 { java_net_SocketOptions_SO_REUSEADDR, SOL_SOCKET, SO_REUSEADDR },
duke@0 861 { java_net_SocketOptions_SO_BROADCAST, SOL_SOCKET, SO_BROADCAST },
duke@0 862 { java_net_SocketOptions_IP_TOS, IPPROTO_IP, IP_TOS },
duke@0 863 { java_net_SocketOptions_IP_MULTICAST_IF, IPPROTO_IP, IP_MULTICAST_IF },
duke@0 864 { java_net_SocketOptions_IP_MULTICAST_IF2, IPPROTO_IP, IP_MULTICAST_IF },
duke@0 865 { java_net_SocketOptions_IP_MULTICAST_LOOP, IPPROTO_IP, IP_MULTICAST_LOOP },
duke@0 866 };
duke@0 867
duke@0 868 int i;
duke@0 869
duke@0 870 /*
duke@0 871 * Different multicast options if IPv6 is enabled
duke@0 872 */
duke@0 873 #ifdef AF_INET6
duke@0 874 if (ipv6_available()) {
duke@0 875 switch (cmd) {
duke@0 876 case java_net_SocketOptions_IP_MULTICAST_IF:
duke@0 877 case java_net_SocketOptions_IP_MULTICAST_IF2:
duke@0 878 *level = IPPROTO_IPV6;
duke@0 879 *optname = IPV6_MULTICAST_IF;
duke@0 880 return 0;
duke@0 881
duke@0 882 case java_net_SocketOptions_IP_MULTICAST_LOOP:
duke@0 883 *level = IPPROTO_IPV6;
duke@0 884 *optname = IPV6_MULTICAST_LOOP;
duke@0 885 return 0;
duke@0 886 }
duke@0 887 }
duke@0 888 #endif
duke@0 889
duke@0 890 /*
duke@0 891 * Map the Java level option to the native level
duke@0 892 */
duke@0 893 for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
duke@0 894 if (cmd == opts[i].cmd) {
duke@0 895 *level = opts[i].level;
duke@0 896 *optname = opts[i].optname;
duke@0 897 return 0;
duke@0 898 }
duke@0 899 }
duke@0 900
duke@0 901 /* not found */
duke@0 902 return -1;
duke@0 903 }
duke@0 904
duke@0 905 /*
duke@0 906 * Determine the default interface for an IPv6 address.
duke@0 907 *
duke@0 908 * 1. Scans /proc/net/ipv6_route for a matching route
duke@0 909 * (eg: fe80::/10 or a route for the specific address).
duke@0 910 * This will tell us the interface to use (eg: "eth0").
duke@0 911 *
duke@0 912 * 2. Lookup /proc/net/if_inet6 to map the interface
duke@0 913 * name to an interface index.
duke@0 914 *
duke@0 915 * Returns :-
duke@0 916 * -1 if error
duke@0 917 * 0 if no matching interface
duke@0 918 * >1 interface index to use for the link-local address.
duke@0 919 */
duke@0 920 #if defined(__linux__) && defined(AF_INET6)
duke@0 921 int getDefaultIPv6Interface(struct in6_addr *target_addr) {
duke@0 922 FILE *f;
duke@0 923 char srcp[8][5];
duke@0 924 char hopp[8][5];
duke@0 925 int dest_plen, src_plen, use, refcnt, metric;
duke@0 926 unsigned long flags;
duke@0 927 char dest_str[40];
duke@0 928 struct in6_addr dest_addr;
duke@0 929 char device[16];
duke@0 930 jboolean match = JNI_FALSE;
duke@0 931
duke@0 932 /*
duke@0 933 * Scan /proc/net/ipv6_route looking for a matching
duke@0 934 * route.
duke@0 935 */
duke@0 936 if ((f = fopen("/proc/net/ipv6_route", "r")) == NULL) {
duke@0 937 return -1;
duke@0 938 }
duke@0 939 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
duke@0 940 "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
duke@0 941 "%4s%4s%4s%4s%4s%4s%4s%4s "
duke@0 942 "%08x %08x %08x %08lx %8s",
duke@0 943 dest_str, &dest_str[5], &dest_str[10], &dest_str[15],
duke@0 944 &dest_str[20], &dest_str[25], &dest_str[30], &dest_str[35],
duke@0 945 &dest_plen,
duke@0 946 srcp[0], srcp[1], srcp[2], srcp[3],
duke@0 947 srcp[4], srcp[5], srcp[6], srcp[7],
duke@0 948 &src_plen,
duke@0 949 hopp[0], hopp[1], hopp[2], hopp[3],
duke@0 950 hopp[4], hopp[5], hopp[6], hopp[7],
duke@0 951 &metric, &use, &refcnt, &flags, device) == 31) {
duke@0 952
duke@0 953 /*
duke@0 954 * Some routes should be ignored
duke@0 955 */
duke@0 956 if ( (dest_plen < 0 || dest_plen > 128) ||
duke@0 957 (src_plen != 0) ||
duke@0 958 (flags & (RTF_POLICY | RTF_FLOW)) ||
duke@0 959 ((flags & RTF_REJECT) && dest_plen == 0) ) {
duke@0 960 continue;
duke@0 961 }
duke@0 962
duke@0 963 /*
duke@0 964 * Convert the destination address
duke@0 965 */
duke@0 966 dest_str[4] = ':';
duke@0 967 dest_str[9] = ':';
duke@0 968 dest_str[14] = ':';
duke@0 969 dest_str[19] = ':';
duke@0 970 dest_str[24] = ':';
duke@0 971 dest_str[29] = ':';
duke@0 972 dest_str[34] = ':';
duke@0 973 dest_str[39] = '\0';
duke@0 974
duke@0 975 if (inet_pton(AF_INET6, dest_str, &dest_addr) < 0) {
duke@0 976 /* not an Ipv6 address */
duke@0 977 continue;
duke@0 978 } else {
duke@0 979 /*
duke@0 980 * The prefix len (dest_plen) indicates the number of bits we
duke@0 981 * need to match on.
duke@0 982 *
duke@0 983 * dest_plen / 8 => number of bytes to match
duke@0 984 * dest_plen % 8 => number of additional bits to match
duke@0 985 *
duke@0 986 * eg: fe80::/10 => match 1 byte + 2 additional bits in the
duke@0 987 * the next byte.
duke@0 988 */
duke@0 989 int byte_count = dest_plen >> 3;
duke@0 990 int extra_bits = dest_plen & 0x3;
duke@0 991
duke@0 992 if (byte_count > 0) {
duke@0 993 if (memcmp(target_addr, &dest_addr, byte_count)) {
duke@0 994 continue; /* no match */
duke@0 995 }
duke@0 996 }
duke@0 997
duke@0 998 if (extra_bits > 0) {
duke@0 999 unsigned char c1 = ((unsigned char *)target_addr)[byte_count];
duke@0 1000 unsigned char c2 = ((unsigned char *)&dest_addr)[byte_count];
duke@0 1001 unsigned char mask = 0xff << (8 - extra_bits);
duke@0 1002 if ((c1 & mask) != (c2 & mask)) {
duke@0 1003 continue;
duke@0 1004 }
duke@0 1005 }
duke@0 1006
duke@0 1007 /*
duke@0 1008 * We have a match
duke@0 1009 */
duke@0 1010 match = JNI_TRUE;
duke@0 1011 break;
duke@0 1012 }
duke@0 1013 }
duke@0 1014 fclose(f);
duke@0 1015
duke@0 1016 /*
duke@0 1017 * If there's a match then we lookup the interface
duke@0 1018 * index.
duke@0 1019 */
duke@0 1020 if (match) {
chegar@453 1021 char devname[20];
duke@0 1022 char addr6p[8][5];
duke@0 1023 int plen, scope, dad_status, if_idx;
duke@0 1024
duke@0 1025 if ((f = fopen("/proc/net/if_inet6", "r")) != NULL) {
duke@0 1026 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
duke@0 1027 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
duke@0 1028 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
duke@0 1029 &if_idx, &plen, &scope, &dad_status, devname) == 13) {
duke@0 1030
duke@0 1031 if (strcmp(devname, device) == 0) {
duke@0 1032 /*
duke@0 1033 * Found - so just return the index
duke@0 1034 */
duke@0 1035 fclose(f);
duke@0 1036 return if_idx;
duke@0 1037 }
duke@0 1038 }
duke@0 1039 fclose(f);
duke@0 1040 } else {
duke@0 1041 /*
duke@0 1042 * Couldn't open /proc/net/if_inet6
duke@0 1043 */
duke@0 1044 return -1;
duke@0 1045 }
duke@0 1046 }
duke@0 1047
duke@0 1048 /*
duke@0 1049 * If we get here it means we didn't there wasn't any
duke@0 1050 * route or we couldn't get the index of the interface.
duke@0 1051 */
duke@0 1052 return 0;
duke@0 1053 }
duke@0 1054 #endif
duke@0 1055
duke@0 1056
duke@0 1057 /*
duke@0 1058 * Wrapper for getsockopt system routine - does any necessary
duke@0 1059 * pre/post processing to deal with OS specific oddies :-
duke@0 1060 *
duke@0 1061 * IP_TOS is a no-op with IPv6 sockets as it's setup when
duke@0 1062 * the connection is established.
duke@0 1063 *
duke@0 1064 * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed
duke@0 1065 * to compensate for an incorrect value returned by the kernel.
duke@0 1066 */
duke@0 1067 int
duke@0 1068 NET_GetSockOpt(int fd, int level, int opt, void *result,
duke@0 1069 int *len)
duke@0 1070 {
duke@0 1071 int rv;
duke@0 1072
duke@0 1073 #ifdef AF_INET6
duke@0 1074 if ((level == IPPROTO_IP) && (opt == IP_TOS)) {
duke@0 1075 if (ipv6_available()) {
duke@0 1076
duke@0 1077 /*
duke@0 1078 * For IPv6 socket option implemented at Java-level
duke@0 1079 * so return -1.
duke@0 1080 */
duke@0 1081 int *tc = (int *)result;
duke@0 1082 *tc = -1;
duke@0 1083 return 0;
duke@0 1084 }
duke@0 1085 }
duke@0 1086 #endif
duke@0 1087
chegar@454 1088 #ifdef __solaris__
chegar@454 1089 rv = getsockopt(fd, level, opt, result, len);
chegar@454 1090 #else
chegar@454 1091 {
chegar@454 1092 socklen_t socklen = *len;
chegar@454 1093 rv = getsockopt(fd, level, opt, result, &socklen);
chegar@454 1094 *len = socklen;
chegar@454 1095 }
chegar@454 1096 #endif
chegar@454 1097
duke@0 1098 if (rv < 0) {
duke@0 1099 return rv;
duke@0 1100 }
duke@0 1101
duke@0 1102 #ifdef __linux__
duke@0 1103 /*
duke@0 1104 * On Linux SO_SNDBUF/SO_RCVBUF aren't symmetric. This
duke@0 1105 * stems from additional socket structures in the send
duke@0 1106 * and receive buffers.
duke@0 1107 */
duke@0 1108 if ((level == SOL_SOCKET) && ((opt == SO_SNDBUF)
duke@0 1109 || (opt == SO_RCVBUF))) {
duke@0 1110 int n = *((int *)result);
duke@0 1111 n /= 2;
duke@0 1112 *((int *)result) = n;
duke@0 1113 }
duke@0 1114 #endif
duke@0 1115
duke@0 1116 return rv;
duke@0 1117 }
duke@0 1118
duke@0 1119
duke@0 1120 /*
duke@0 1121 * Wrapper for setsockopt system routine - performs any
duke@0 1122 * necessary pre/post processing to deal with OS specific
duke@0 1123 * issue :-
duke@0 1124 *
duke@0 1125 * On Solaris need to limit the suggested value for SO_SNDBUF
duke@0 1126 * and SO_RCVBUF to the kernel configured limit
duke@0 1127 *
duke@0 1128 * For IP_TOS socket option need to mask off bits as this
duke@0 1129 * aren't automatically masked by the kernel and results in
duke@0 1130 * an error. In addition IP_TOS is a noop with IPv6 as it
duke@0 1131 * should be setup as connection time.
duke@0 1132 */
duke@0 1133 int
duke@0 1134 NET_SetSockOpt(int fd, int level, int opt, const void *arg,
duke@0 1135 int len)
duke@0 1136 {
duke@0 1137 #ifndef IPTOS_TOS_MASK
duke@0 1138 #define IPTOS_TOS_MASK 0x1e
duke@0 1139 #endif
duke@0 1140 #ifndef IPTOS_PREC_MASK
duke@0 1141 #define IPTOS_PREC_MASK 0xe0
duke@0 1142 #endif
duke@0 1143
duke@0 1144 /*
duke@0 1145 * IPPROTO/IP_TOS :-
duke@0 1146 * 1. IPv6 on Solaris: no-op and will be set in flowinfo
duke@0 1147 * field when connecting TCP socket, or sending
duke@0 1148 * UDP packet.
duke@0 1149 * 2. IPv6 on Linux: By default Linux ignores flowinfo
duke@0 1150 * field so enable IPV6_FLOWINFO_SEND so that flowinfo
duke@0 1151 * will be examined.
duke@0 1152 * 3. IPv4: set socket option based on ToS and Precedence
duke@0 1153 * fields (otherwise get invalid argument)
duke@0 1154 */
duke@0 1155 if (level == IPPROTO_IP && opt == IP_TOS) {
duke@0 1156 int *iptos;
duke@0 1157
duke@0 1158 #if defined(AF_INET6) && defined(__solaris__)
duke@0 1159 if (ipv6_available()) {
duke@0 1160 return 0;
duke@0 1161 }
duke@0 1162 #endif
duke@0 1163
duke@0 1164 #if defined(AF_INET6) && defined(__linux__)
duke@0 1165 if (ipv6_available()) {
duke@0 1166 int optval = 1;
duke@0 1167 return setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
duke@0 1168 (void *)&optval, sizeof(optval));
duke@0 1169 }
duke@0 1170 #endif
duke@0 1171
duke@0 1172 iptos = (int *)arg;
duke@0 1173 *iptos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
duke@0 1174 }
duke@0 1175
duke@0 1176 /*
duke@0 1177 * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris need to
duke@0 1178 * ensure that value is <= max_buf as otherwise we get
duke@0 1179 * an invalid argument.
duke@0 1180 */
duke@0 1181 #ifdef __solaris__
duke@0 1182 if (level == SOL_SOCKET) {
duke@0 1183 if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
duke@0 1184 int sotype, arglen;
duke@0 1185 int *bufsize, maxbuf;
duke@0 1186
duke@0 1187 if (!init_max_buf) {
duke@0 1188 tcp_max_buf = getParam("/dev/tcp", "tcp_max_buf", 64*1024);
duke@0 1189 udp_max_buf = getParam("/dev/udp", "udp_max_buf", 64*1024);
duke@0 1190 init_max_buf = 1;
duke@0 1191 }
duke@0 1192
duke@0 1193 arglen = sizeof(sotype);
duke@0 1194 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype,
duke@0 1195 &arglen) < 0) {
duke@0 1196 return -1;
duke@0 1197 }
duke@0 1198
duke@0 1199 maxbuf = (sotype == SOCK_STREAM) ? tcp_max_buf : udp_max_buf;
duke@0 1200 bufsize = (int *)arg;
duke@0 1201 if (*bufsize > maxbuf) {
duke@0 1202 *bufsize = maxbuf;
duke@0 1203 }
duke@0 1204 }
duke@0 1205 }
duke@0 1206 #endif
duke@0 1207
duke@0 1208 /*
duke@0 1209 * On Linux the receive buffer is used for both socket
duke@0 1210 * structures and the the packet payload. The implication
duke@0 1211 * is that if SO_RCVBUF is too small then small packets
duke@0 1212 * must be discard.
duke@0 1213 */
duke@0 1214 #ifdef __linux__
duke@0 1215 if (level == SOL_SOCKET && opt == SO_RCVBUF) {
duke@0 1216 int *bufsize = (int *)arg;
duke@0 1217 if (*bufsize < 1024) {
duke@0 1218 *bufsize = 1024;
duke@0 1219 }
duke@0 1220 }
duke@0 1221 #endif
duke@0 1222
duke@0 1223 return setsockopt(fd, level, opt, arg, len);
duke@0 1224 }
duke@0 1225
duke@0 1226 /*
duke@0 1227 * Wrapper for bind system call - performs any necessary pre/post
duke@0 1228 * processing to deal with OS specific issues :-
duke@0 1229 *
duke@0 1230 * Linux allows a socket to bind to 127.0.0.255 which must be
duke@0 1231 * caught.
duke@0 1232 *
duke@0 1233 * On Solaris 8/9 with IPv6 enabled we must use an exclusive
duke@0 1234 * bind to guaranteed a unique port number across the IPv4 and
duke@0 1235 * IPv6 port spaces.
duke@0 1236 *
duke@0 1237 */
duke@0 1238 int
duke@0 1239 NET_Bind(int fd, struct sockaddr *him, int len)
duke@0 1240 {
duke@0 1241 #if defined(__solaris__) && defined(AF_INET6)
duke@0 1242 int level = -1;
duke@0 1243 int exclbind = -1;
duke@0 1244 #endif
duke@0 1245 int rv;
duke@0 1246
duke@0 1247 #ifdef __linux__
duke@0 1248 /*
duke@0 1249 * ## get bugId for this issue - goes back to 1.2.2 port ##
duke@0 1250 * ## When IPv6 is enabled this will be an IPv4-mapped
duke@0 1251 * ## with family set to AF_INET6
duke@0 1252 */
duke@0 1253 if (him->sa_family == AF_INET) {
duke@0 1254 struct sockaddr_in *sa = (struct sockaddr_in *)him;
duke@0 1255 if ((ntohl(sa->sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
duke@0 1256 errno = EADDRNOTAVAIL;
duke@0 1257 return -1;
duke@0 1258 }
duke@0 1259 }
duke@0 1260 #endif
duke@0 1261
duke@0 1262 #if defined(__solaris__) && defined(AF_INET6)
duke@0 1263 /*
duke@0 1264 * Solaris 8/9 have seperate IPv4 and IPv6 port spaces so we
duke@0 1265 * use an exclusive bind when SO_REUSEADDR is not used to
duke@0 1266 * give the illusion of a unified port space.
duke@0 1267 * This also avoid problems with IPv6 sockets connecting
duke@0 1268 * to IPv4 mapped addresses whereby the socket conversion
duke@0 1269 * results in a late bind that fails because the
duke@0 1270 * corresponding IPv4 port is in use.
duke@0 1271 */
duke@0 1272 if (ipv6_available()) {
duke@0 1273 int arg, len;
duke@0 1274
duke@0 1275 len = sizeof(arg);
duke@0 1276 if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&arg,
duke@0 1277 &len) == 0) {
duke@0 1278 if (arg == 0) {
duke@0 1279 /*
duke@0 1280 * SO_REUSEADDR is disabled so enable TCP_EXCLBIND or
duke@0 1281 * UDP_EXCLBIND
duke@0 1282 */
duke@0 1283 len = sizeof(arg);
duke@0 1284 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg,
duke@0 1285 &len) == 0) {
duke@0 1286 if (arg == SOCK_STREAM) {
duke@0 1287 level = IPPROTO_TCP;
duke@0 1288 exclbind = TCP_EXCLBIND;
duke@0 1289 } else {
duke@0 1290 level = IPPROTO_UDP;
duke@0 1291 exclbind = UDP_EXCLBIND;
duke@0 1292 }
duke@0 1293 }
duke@0 1294
duke@0 1295 arg = 1;
duke@0 1296 setsockopt(fd, level, exclbind, (char *)&arg,
duke@0 1297 sizeof(arg));
duke@0 1298 }
duke@0 1299 }
duke@0 1300 }
duke@0 1301
duke@0 1302 #endif
duke@0 1303
duke@0 1304 rv = bind(fd, him, len);
duke@0 1305
duke@0 1306 #if defined(__solaris__) && defined(AF_INET6)
duke@0 1307 if (rv < 0) {
duke@0 1308 int en = errno;
duke@0 1309 /* Restore *_EXCLBIND if the bind fails */
duke@0 1310 if (exclbind != -1) {
duke@0 1311 int arg = 0;
duke@0 1312 setsockopt(fd, level, exclbind, (char *)&arg,
duke@0 1313 sizeof(arg));
duke@0 1314 }
duke@0 1315 errno = en;
duke@0 1316 }
duke@0 1317 #endif
duke@0 1318
duke@0 1319 return rv;
duke@0 1320 }
duke@0 1321
duke@0 1322 /**
duke@0 1323 * Wrapper for select/poll with timeout on a single file descriptor.
duke@0 1324 *
duke@0 1325 * flags (defined in net_util_md.h can be any combination of
duke@0 1326 * NET_WAIT_READ, NET_WAIT_WRITE & NET_WAIT_CONNECT.
duke@0 1327 *
duke@0 1328 * The function will return when either the socket is ready for one
duke@0 1329 * of the specified operation or the timeout expired.
duke@0 1330 *
duke@0 1331 * It returns the time left from the timeout (possibly 0), or -1 if it expired.
duke@0 1332 */
duke@0 1333
duke@0 1334 jint
duke@0 1335 NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout)
duke@0 1336 {
duke@0 1337 jlong prevTime = JVM_CurrentTimeMillis(env, 0);
duke@0 1338 jint read_rv;
duke@0 1339
duke@0 1340 while (1) {
duke@0 1341 jlong newTime;
duke@0 1342 #ifndef USE_SELECT
duke@0 1343 {
duke@0 1344 struct pollfd pfd;
duke@0 1345 pfd.fd = fd;
duke@0 1346 pfd.events = 0;
duke@0 1347 if (flags & NET_WAIT_READ)
duke@0 1348 pfd.events |= POLLIN;
duke@0 1349 if (flags & NET_WAIT_WRITE)
duke@0 1350 pfd.events |= POLLOUT;
duke@0 1351 if (flags & NET_WAIT_CONNECT)
duke@0 1352 pfd.events |= POLLOUT;
duke@0 1353
duke@0 1354 errno = 0;
duke@0 1355 read_rv = NET_Poll(&pfd, 1, timeout);
duke@0 1356 }
duke@0 1357 #else
duke@0 1358 {
duke@0 1359 fd_set rd, wr, ex;
duke@0 1360 struct timeval t;
duke@0 1361
duke@0 1362 t.tv_sec = timeout / 1000;
duke@0 1363 t.tv_usec = (timeout % 1000) * 1000;
duke@0 1364
duke@0 1365 FD_ZERO(&rd);
duke@0 1366 FD_ZERO(&wr);
duke@0 1367 FD_ZERO(&ex);
duke@0 1368 if (flags & NET_WAIT_READ) {
duke@0 1369 FD_SET(fd, &rd);
duke@0 1370 }
duke@0 1371 if (flags & NET_WAIT_WRITE) {
duke@0 1372 FD_SET(fd, &wr);
duke@0 1373 }
duke@0 1374 if (flags & NET_WAIT_CONNECT) {
duke@0 1375 FD_SET(fd, &wr);
duke@0 1376 FD_SET(fd, &ex);
duke@0 1377 }
duke@0 1378
duke@0 1379 errno = 0;
duke@0 1380 read_rv = NET_Select(fd+1, &rd, &wr, &ex, &t);
duke@0 1381 }
duke@0 1382 #endif
duke@0 1383
duke@0 1384 newTime = JVM_CurrentTimeMillis(env, 0);
duke@0 1385 timeout -= (newTime - prevTime);
duke@0 1386 if (timeout <= 0) {
duke@0 1387 return read_rv > 0 ? 0 : -1;
duke@0 1388 }
duke@0 1389 newTime = prevTime;
duke@0 1390
duke@0 1391 if (read_rv > 0) {
duke@0 1392 break;
duke@0 1393 }
duke@0 1394
duke@0 1395
duke@0 1396 } /* while */
duke@0 1397
duke@0 1398 return timeout;
duke@0 1399 }