1 /*
   2  * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 #include <winsock2.h>
  27 #include <ws2tcpip.h>
  28 
  29 #include "net_util.h"
  30 #include "jni.h"
  31 
  32 #ifndef IPTOS_TOS_MASK
  33 #define IPTOS_TOS_MASK 0x1e
  34 #endif
  35 #ifndef IPTOS_PREC_MASK
  36 #define IPTOS_PREC_MASK 0xe0
  37 #endif
  38 
  39 /* true if SO_RCVTIMEO is supported */
  40 jboolean isRcvTimeoutSupported = JNI_TRUE;
  41 
  42 LPFN_GETADDRINFO getaddrinfo_ptr = NULL;
  43 LPFN_FREEADDRINFO freaddrinfo_ptr = NULL;
  44 LPFN_GETNAMEINFO getnameinfo_ptr = NULL;
  45 
  46 /*
  47  * Table of Windows Sockets errors, the specific exception we
  48  * throw for the error, and the error text.
  49  *
  50  * Note that this table excludes OS dependent errors.
  51  *
  52  * Latest list of Windows Sockets errors can be found at :-
  53  * http://msdn.microsoft.com/library/psdk/winsock/errors_3wc2.htm
  54  */
  55 static struct {
  56     int errCode;
  57     const char *exc;
  58     const char *errString;
  59 } const winsock_errors[] = {
  60     { WSAEACCES,                0,      "Permission denied" },
  61     { WSAEADDRINUSE,            "BindException",        "Address already in use" },
  62     { WSAEADDRNOTAVAIL,         "BindException",        "Cannot assign requested address" },
  63     { WSAEAFNOSUPPORT,          0,      "Address family not supported by protocol family" },
  64     { WSAEALREADY,              0,      "Operation already in progress" },
  65     { WSAECONNABORTED,          0,      "Software caused connection abort" },
  66     { WSAECONNREFUSED,          "ConnectException",     "Connection refused" },
  67     { WSAECONNRESET,            0,      "Connection reset by peer" },
  68     { WSAEDESTADDRREQ,          0,      "Destination address required" },
  69     { WSAEFAULT,                0,      "Bad address" },
  70     { WSAEHOSTDOWN,             0,      "Host is down" },
  71     { WSAEHOSTUNREACH,          "NoRouteToHostException",       "No route to host" },
  72     { WSAEINPROGRESS,           0,      "Operation now in progress" },
  73     { WSAEINTR,                 0,      "Interrupted function call" },
  74     { WSAEINVAL,                0,      "Invalid argument" },
  75     { WSAEISCONN,               0,      "Socket is already connected" },
  76     { WSAEMFILE,                0,      "Too many open files" },
  77     { WSAEMSGSIZE,              0,      "The message is larger than the maximum supported by the underlying transport" },
  78     { WSAENETDOWN,              0,      "Network is down" },
  79     { WSAENETRESET,             0,      "Network dropped connection on reset" },
  80     { WSAENETUNREACH,           0,      "Network is unreachable" },
  81     { WSAENOBUFS,               0,      "No buffer space available (maximum connections reached?)" },
  82     { WSAENOPROTOOPT,           0,      "Bad protocol option" },
  83     { WSAENOTCONN,              0,      "Socket is not connected" },
  84     { WSAENOTSOCK,              0,      "Socket operation on nonsocket" },
  85     { WSAEOPNOTSUPP,            0,      "Operation not supported" },
  86     { WSAEPFNOSUPPORT,          0,      "Protocol family not supported" },
  87     { WSAEPROCLIM,              0,      "Too many processes" },
  88     { WSAEPROTONOSUPPORT,       0,      "Protocol not supported" },
  89     { WSAEPROTOTYPE,            0,      "Protocol wrong type for socket" },
  90     { WSAESHUTDOWN,             0,      "Cannot send after socket shutdown" },
  91     { WSAESOCKTNOSUPPORT,       0,      "Socket type not supported" },
  92     { WSAETIMEDOUT,             "ConnectException",     "Connection timed out" },
  93     { WSATYPE_NOT_FOUND,        0,      "Class type not found" },
  94     { WSAEWOULDBLOCK,           0,      "Resource temporarily unavailable" },
  95     { WSAHOST_NOT_FOUND,        0,      "Host not found" },
  96     { WSA_NOT_ENOUGH_MEMORY,    0,      "Insufficient memory available" },
  97     { WSANOTINITIALISED,        0,      "Successful WSAStartup not yet performed" },
  98     { WSANO_DATA,               0,      "Valid name, no data record of requested type" },
  99     { WSANO_RECOVERY,           0,      "This is a nonrecoverable error" },
 100     { WSASYSNOTREADY,           0,      "Network subsystem is unavailable" },
 101     { WSATRY_AGAIN,             0,      "Nonauthoritative host not found" },
 102     { WSAVERNOTSUPPORTED,       0,      "Winsock.dll version out of range" },
 103     { WSAEDISCON,               0,      "Graceful shutdown in progress" },
 104     { WSA_OPERATION_ABORTED,    0,      "Overlapped operation aborted" },
 105 };
 106 
 107 /*
 108  * Initialize Windows Sockets API support
 109  */
 110 BOOL WINAPI
 111 DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved)
 112 {
 113     WSADATA wsadata;
 114 
 115     switch (reason) {
 116         case DLL_PROCESS_ATTACH:
 117             if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0) {
 118                 return FALSE;
 119             }
 120             break;
 121 
 122         case DLL_PROCESS_DETACH:
 123             WSACleanup();
 124             break;
 125 
 126         default:
 127             break;
 128     }
 129     return TRUE;
 130 }
 131 
 132 void initLocalAddrTable () {}
 133 
 134 /*
 135  * Since winsock doesn't have the equivalent of strerror(errno)
 136  * use table to lookup error text for the error.
 137  */
 138 JNIEXPORT void JNICALL
 139 NET_ThrowNew(JNIEnv *env, int errorNum, char *msg)
 140 {
 141     int i;
 142     int table_size = sizeof(winsock_errors) /
 143                      sizeof(winsock_errors[0]);
 144     char exc[256];
 145     char fullMsg[256];
 146     char *excP = NULL;
 147 
 148     /*
 149      * If exception already throw then don't overwrite it.
 150      */
 151     if ((*env)->ExceptionOccurred(env)) {
 152         return;
 153     }
 154 
 155     /*
 156      * Default message text if not provided
 157      */
 158     if (!msg) {
 159         msg = "no further information";
 160     }
 161 
 162     /*
 163      * Check table for known winsock errors
 164      */
 165     i=0;
 166     while (i < table_size) {
 167         if (errorNum == winsock_errors[i].errCode) {
 168             break;
 169         }
 170         i++;
 171     }
 172 
 173     /*
 174      * If found get pick the specific exception and error
 175      * message corresponding to this error.
 176      */
 177     if (i < table_size) {
 178         excP = (char *)winsock_errors[i].exc;
 179         jio_snprintf(fullMsg, sizeof(fullMsg), "%s: %s",
 180                      (char *)winsock_errors[i].errString, msg);
 181     } else {
 182         jio_snprintf(fullMsg, sizeof(fullMsg),
 183                      "Unrecognized Windows Sockets error: %d: %s",
 184                      errorNum, msg);
 185 
 186     }
 187 
 188     /*
 189      * Throw SocketException if no specific exception for this
 190      * error.
 191      */
 192     if (excP == NULL) {
 193         excP = "SocketException";
 194     }
 195     sprintf(exc, "%s%s", JNU_JAVANETPKG, excP);
 196     JNU_ThrowByName(env, exc, fullMsg);
 197 }
 198 
 199 void
 200 NET_ThrowCurrent(JNIEnv *env, char *msg)
 201 {
 202     NET_ThrowNew(env, WSAGetLastError(), msg);
 203 }
 204 
 205 void
 206 NET_ThrowSocketException(JNIEnv *env, char* msg)
 207 {
 208     static jclass cls = NULL;
 209     if (cls == NULL) {
 210         cls = (*env)->FindClass(env, "java/net/SocketException");
 211         CHECK_NULL(cls);
 212         cls = (*env)->NewGlobalRef(env, cls);
 213         CHECK_NULL(cls);
 214     }
 215     (*env)->ThrowNew(env, cls, msg);
 216 }
 217 
 218 void
 219 NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
 220                    const char *defaultDetail) {
 221     char errmsg[255];
 222     sprintf(errmsg, "errno: %d, error: %s\n", WSAGetLastError(), defaultDetail);
 223     JNU_ThrowByNameWithLastError(env, name, errmsg);
 224 }
 225 
 226 jfieldID
 227 NET_GetFileDescriptorID(JNIEnv *env)
 228 {
 229     jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor");
 230     CHECK_NULL_RETURN(cls, NULL);
 231     return (*env)->GetFieldID(env, cls, "fd", "I");
 232 }
 233 
 234 jint  IPv6_supported()
 235 {
 236     HMODULE lib;
 237     int fd = socket(AF_INET6, SOCK_STREAM, 0) ;
 238     if (fd < 0) {
 239         return JNI_FALSE;
 240     }
 241     closesocket (fd);
 242 
 243     if ((lib = LoadLibrary ("ws2_32.dll")) == NULL) {
 244         return JNI_FALSE;
 245     }
 246     if ((getaddrinfo_ptr = (LPFN_GETADDRINFO)GetProcAddress (lib, "getaddrinfo")) == NULL) {
 247         FreeLibrary (lib);
 248         return JNI_FALSE;
 249     }
 250     if ((freeaddrinfo_ptr = (LPFN_FREEADDRINFO)GetProcAddress (lib, "freeaddrinfo")) == NULL) {
 251         FreeLibrary (lib);
 252         return JNI_FALSE;
 253     }
 254     if ((getnameinfo_ptr = (LPFN_GETNAMEINFO)GetProcAddress (lib, "getnameinfo")) == NULL) {
 255         FreeLibrary (lib);
 256         return JNI_FALSE;
 257     }
 258     FreeLibrary(lib);
 259 
 260     return JNI_TRUE;
 261 }
 262 
 263 jboolean NET_addrtransAvailable() {
 264     return (jboolean)(getaddrinfo_ptr != NULL);
 265 }
 266 
 267 
 268 /*
 269  * Return the default TOS value
 270  */
 271 int NET_GetDefaultTOS() {
 272     static int default_tos = -1;
 273     OSVERSIONINFO ver;
 274     HKEY hKey;
 275     LONG ret;
 276 
 277     /*
 278      * If default ToS already determined then return it
 279      */
 280     if (default_tos >= 0) {
 281         return default_tos;
 282     }
 283 
 284     /*
 285      * Assume default is "normal service"
 286      */
 287     default_tos = 0;
 288 
 289     /*
 290      * Which OS is this?
 291      */
 292     ver.dwOSVersionInfoSize = sizeof(ver);
 293     GetVersionEx(&ver);
 294 
 295     /*
 296      * If 2000 or greater then no default ToS in registry
 297      */
 298     if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
 299         if (ver.dwMajorVersion >= 5) {
 300             return default_tos;
 301         }
 302     }
 303 
 304     /*
 305      * Query the registry to see if a Default ToS has been set.
 306      * Different registry entry for NT vs 95/98/ME.
 307      */
 308     if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
 309         ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
 310                            "SYSTEM\\CurrentControlSet\\Services\\Tcp\\Parameters",
 311                            0, KEY_READ, (PHKEY)&hKey);
 312     } else {
 313         ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
 314                            "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP\\Parameters",
 315                            0, KEY_READ, (PHKEY)&hKey);
 316     }
 317     if (ret == ERROR_SUCCESS) {
 318         DWORD dwLen;
 319         DWORD dwDefaultTOS;
 320         ULONG ulType;
 321         dwLen = sizeof(dwDefaultTOS);
 322 
 323         ret = RegQueryValueEx(hKey, "DefaultTOS",  NULL, &ulType,
 324                              (LPBYTE)&dwDefaultTOS, &dwLen);
 325         RegCloseKey(hKey);
 326         if (ret == ERROR_SUCCESS) {
 327             default_tos = (int)dwDefaultTOS;
 328         }
 329     }
 330     return default_tos;
 331 }
 332 
 333 /* call NET_MapSocketOptionV6 for the IPv6 fd only
 334  * and NET_MapSocketOption for the IPv4 fd
 335  */
 336 JNIEXPORT int JNICALL
 337 NET_MapSocketOptionV6(jint cmd, int *level, int *optname) {
 338 
 339     switch (cmd) {
 340         case java_net_SocketOptions_IP_MULTICAST_IF:
 341         case java_net_SocketOptions_IP_MULTICAST_IF2:
 342             *level = IPPROTO_IPV6;
 343             *optname = IPV6_MULTICAST_IF;
 344             return 0;
 345 
 346         case java_net_SocketOptions_IP_MULTICAST_LOOP:
 347             *level = IPPROTO_IPV6;
 348             *optname = IPV6_MULTICAST_LOOP;
 349             return 0;
 350     }
 351     return NET_MapSocketOption (cmd, level, optname);
 352 }
 353 
 354 /*
 355  * Map the Java level socket option to the platform specific
 356  * level and option name.
 357  */
 358 
 359 JNIEXPORT int JNICALL
 360 NET_MapSocketOption(jint cmd, int *level, int *optname) {
 361 
 362     typedef struct {
 363         jint cmd;
 364         int level;
 365         int optname;
 366     } sockopts;
 367 
 368     static sockopts opts[] = {
 369         { java_net_SocketOptions_TCP_NODELAY,   IPPROTO_TCP,    TCP_NODELAY },
 370         { java_net_SocketOptions_SO_OOBINLINE,  SOL_SOCKET,     SO_OOBINLINE },
 371         { java_net_SocketOptions_SO_LINGER,     SOL_SOCKET,     SO_LINGER },
 372         { java_net_SocketOptions_SO_SNDBUF,     SOL_SOCKET,     SO_SNDBUF },
 373         { java_net_SocketOptions_SO_RCVBUF,     SOL_SOCKET,     SO_RCVBUF },
 374         { java_net_SocketOptions_SO_KEEPALIVE,  SOL_SOCKET,     SO_KEEPALIVE },
 375         { java_net_SocketOptions_SO_REUSEADDR,  SOL_SOCKET,     SO_REUSEADDR },
 376         { java_net_SocketOptions_SO_BROADCAST,  SOL_SOCKET,     SO_BROADCAST },
 377         { java_net_SocketOptions_IP_MULTICAST_IF,   IPPROTO_IP, IP_MULTICAST_IF },
 378         { java_net_SocketOptions_IP_MULTICAST_LOOP, IPPROTO_IP, IP_MULTICAST_LOOP },
 379         { java_net_SocketOptions_IP_TOS,            IPPROTO_IP, IP_TOS },
 380 
 381     };
 382 
 383 
 384     int i;
 385 
 386     /*
 387      * Map the Java level option to the native level
 388      */
 389     for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
 390         if (cmd == opts[i].cmd) {
 391             *level = opts[i].level;
 392             *optname = opts[i].optname;
 393             return 0;
 394         }
 395     }
 396 
 397     /* not found */
 398     return -1;
 399 }
 400 
 401 
 402 /*
 403  * Wrapper for setsockopt dealing with Windows specific issues :-
 404  *
 405  * IP_TOS and IP_MULTICAST_LOOP can't be set on some Windows
 406  * editions.
 407  *
 408  * The value for the type-of-service (TOS) needs to be masked
 409  * to get consistent behaviour with other operating systems.
 410  */
 411 JNIEXPORT int JNICALL
 412 NET_SetSockOpt(int s, int level, int optname, const void *optval,
 413                int optlen)
 414 {
 415     int rv;
 416 
 417     if (level == IPPROTO_IP && optname == IP_TOS) {
 418         int *tos = (int *)optval;
 419         *tos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
 420     }
 421 
 422     rv = setsockopt(s, level, optname, optval, optlen);
 423 
 424     if (rv == SOCKET_ERROR) {
 425         /*
 426          * IP_TOS & IP_MULTICAST_LOOP can't be set on some versions
 427          * of Windows.
 428          */
 429         if ((WSAGetLastError() == WSAENOPROTOOPT) &&
 430             (level == IPPROTO_IP) &&
 431             (optname == IP_TOS || optname == IP_MULTICAST_LOOP)) {
 432             rv = 0;
 433         }
 434 
 435         /*
 436          * IP_TOS can't be set on unbound UDP sockets.
 437          */
 438         if ((WSAGetLastError() == WSAEINVAL) &&
 439             (level == IPPROTO_IP) &&
 440             (optname == IP_TOS)) {
 441             rv = 0;
 442         }
 443     }
 444 
 445     return rv;
 446 }
 447 
 448 /*
 449  * Wrapper for setsockopt dealing with Windows specific issues :-
 450  *
 451  * IP_TOS is not supported on some versions of Windows so
 452  * instead return the default value for the OS.
 453  */
 454 JNIEXPORT int JNICALL
 455 NET_GetSockOpt(int s, int level, int optname, void *optval,
 456                int *optlen)
 457 {
 458     int rv;
 459 
 460     rv = getsockopt(s, level, optname, optval, optlen);
 461 
 462 
 463     /*
 464      * IPPROTO_IP/IP_TOS is not supported on some Windows
 465      * editions so return the default type-of-service
 466      * value.
 467      */
 468     if (rv == SOCKET_ERROR) {
 469 
 470         if (WSAGetLastError() == WSAENOPROTOOPT &&
 471             level == IPPROTO_IP && optname == IP_TOS) {
 472 
 473             int *tos;
 474             tos = (int *)optval;
 475             *tos = NET_GetDefaultTOS();
 476 
 477             rv = 0;
 478         }
 479     }
 480 
 481     return rv;
 482 }
 483 
 484 /*
 485  * Wrapper for bind winsock call - transparent converts an
 486  * error related to binding to a port that has exclusive access
 487  * into an error indicating the port is in use (facilitates
 488  * better error reporting).
 489  */
 490 JNIEXPORT int JNICALL
 491 NET_Bind(int s, struct sockaddr *him, int len)
 492 {
 493     int rv = bind(s, him, len);
 494 
 495     if (rv == SOCKET_ERROR) {
 496         /*
 497          * If bind fails with WSAEACCES it means that a privileged
 498          * process has done an exclusive bind (NT SP4/2000/XP only).
 499          */
 500         if (WSAGetLastError() == WSAEACCES) {
 501             WSASetLastError(WSAEADDRINUSE);
 502         }
 503     }
 504 
 505     return rv;
 506 }
 507 
 508 JNIEXPORT int JNICALL
 509 NET_SocketClose(int fd) {
 510     struct linger l;
 511     int ret;
 512     int len = sizeof (l);
 513     if (getsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&l, &len) == 0) {
 514         if (l.l_onoff == 0) {
 515             WSASendDisconnect(fd, NULL);
 516         }
 517     }
 518     ret = closesocket (fd);
 519     return ret;
 520 }
 521 
 522 JNIEXPORT int JNICALL
 523 NET_Timeout(int fd, long timeout) {
 524     int ret;
 525     fd_set tbl;
 526     struct timeval t;
 527     t.tv_sec = timeout / 1000;
 528     t.tv_usec = (timeout % 1000) * 1000;
 529     FD_ZERO(&tbl);
 530     FD_SET(fd, &tbl);
 531     ret = select (fd + 1, &tbl, 0, 0, &t);
 532     return ret;
 533 }
 534 
 535 
 536 /*
 537  * differs from NET_Timeout() as follows:
 538  *
 539  * If timeout = -1, it blocks forever.
 540  *
 541  * returns 1 or 2 depending if only one or both sockets
 542  * fire at same time.
 543  *
 544  * *fdret is (one of) the active fds. If both sockets
 545  * fire at same time, *fdret = fd always.
 546  */
 547 JNIEXPORT int JNICALL
 548 NET_Timeout2(int fd, int fd1, long timeout, int *fdret) {
 549     int ret;
 550     fd_set tbl;
 551     struct timeval t, *tP = &t;
 552     if (timeout == -1) {
 553         tP = 0;
 554     } else {
 555         t.tv_sec = timeout / 1000;
 556         t.tv_usec = (timeout % 1000) * 1000;
 557     }
 558     FD_ZERO(&tbl);
 559     FD_SET(fd, &tbl);
 560     FD_SET(fd1, &tbl);
 561     ret = select (0, &tbl, 0, 0, tP);
 562     switch (ret) {
 563     case 0:
 564         return 0; /* timeout */
 565     case 1:
 566         if (FD_ISSET (fd, &tbl)) {
 567             *fdret= fd;
 568         } else {
 569             *fdret= fd1;
 570         }
 571         return 1;
 572     case 2:
 573         *fdret= fd;
 574         return 2;
 575     }
 576     return -1;
 577 }
 578 
 579 
 580 void dumpAddr (char *str, void *addr) {
 581     struct SOCKADDR_IN6 *a = (struct SOCKADDR_IN6 *)addr;
 582     int family = a->sin6_family;
 583     printf ("%s\n", str);
 584     if (family == AF_INET) {
 585         struct sockaddr_in *him = (struct sockaddr_in *)addr;
 586         printf ("AF_INET: port %d: %x\n", ntohs(him->sin_port),
 587                                           ntohl(him->sin_addr.s_addr));
 588     } else {
 589         int i;
 590         struct in6_addr *in = &a->sin6_addr;
 591         printf ("AF_INET6 ");
 592         printf ("port %d ", ntohs (a->sin6_port));
 593         printf ("flow %d ", a->sin6_flowinfo);
 594         printf ("addr ");
 595         for (i=0; i<7; i++) {
 596             printf ("%04x:", ntohs(in->s6_words[i]));
 597         }
 598         printf ("%04x", ntohs(in->s6_words[7]));
 599         printf (" scope %d\n", a->sin6_scope_id);
 600     }
 601 }
 602 
 603 /* Macro, which cleans-up the iv6bind structure,
 604  * closes the two sockets (if open),
 605  * and returns SOCKET_ERROR. Used in NET_BindV6 only.
 606  */
 607 
 608 #define CLOSE_SOCKETS_AND_RETURN {      \
 609     if (fd != -1) {                     \
 610         closesocket (fd);               \
 611         fd = -1;                        \
 612     }                                   \
 613     if (ofd != -1) {                    \
 614         closesocket (ofd);              \
 615         ofd = -1;                       \
 616     }                                   \
 617     if (close_fd != -1) {               \
 618         closesocket (close_fd);         \
 619         close_fd = -1;                  \
 620     }                                   \
 621     if (close_ofd != -1) {              \
 622         closesocket (close_ofd);        \
 623         close_ofd = -1;                 \
 624     }                                   \
 625     b->ipv4_fd = b->ipv6_fd = -1;       \
 626     return SOCKET_ERROR;                \
 627 }
 628 
 629 /*
 630  * if ipv6 is available, call NET_BindV6 to bind to the required address/port.
 631  * Because the same port number may need to be reserved in both v4 and v6 space,
 632  * this may require socket(s) to be re-opened. Therefore, all of this information
 633  * is passed in and returned through the ipv6bind structure.
 634  *
 635  * If the request is to bind to a specific address, then this (by definition) means
 636  * only bind in either v4 or v6, and this is just the same as normal. ie. a single
 637  * call to bind() will suffice. The other socket is closed in this case.
 638  *
 639  * The more complicated case is when the requested address is ::0 or 0.0.0.0.
 640  *
 641  * Two further cases:
 642  * 2. If the reqeusted port is 0 (ie. any port) then we try to bind in v4 space
 643  *    first with a wild-card port argument. We then try to bind in v6 space
 644  *    using the returned port number. If this fails, we repeat the process
 645  *    until a free port common to both spaces becomes available.
 646  *
 647  * 3. If the requested port is a specific port, then we just try to get that
 648  *    port in both spaces, and if it is not free in both, then the bind fails.
 649  *
 650  * On failure, sockets are closed and an error returned with CLOSE_SOCKETS_AND_RETURN
 651  */
 652 
 653 JNIEXPORT int JNICALL
 654 NET_BindV6(struct ipv6bind* b) {
 655     int fd=-1, ofd=-1, rv, len;
 656     /* need to defer close until new sockets created */
 657     int close_fd=-1, close_ofd=-1;
 658     SOCKETADDRESS oaddr; /* other address to bind */
 659     int family = b->addr->him.sa_family;
 660     int ofamily;
 661     u_short port; /* requested port parameter */
 662     u_short bound_port;
 663 
 664     if (family == AF_INET && (b->addr->him4.sin_addr.s_addr != INADDR_ANY)) {
 665         /* bind to v4 only */
 666         int ret;
 667         ret = NET_Bind (b->ipv4_fd, (struct sockaddr *)b->addr,
 668                                 sizeof (struct sockaddr_in));
 669         if (ret == SOCKET_ERROR) {
 670             CLOSE_SOCKETS_AND_RETURN;
 671         }
 672         closesocket (b->ipv6_fd);
 673         b->ipv6_fd = -1;
 674         return 0;
 675     }
 676     if (family == AF_INET6 && (!IN6_IS_ADDR_ANY(&b->addr->him6.sin6_addr))) {
 677         /* bind to v6 only */
 678         int ret;
 679         ret = NET_Bind (b->ipv6_fd, (struct sockaddr *)b->addr,
 680                                 sizeof (struct SOCKADDR_IN6));
 681         if (ret == SOCKET_ERROR) {
 682             CLOSE_SOCKETS_AND_RETURN;
 683         }
 684         closesocket (b->ipv4_fd);
 685         b->ipv4_fd = -1;
 686         return 0;
 687     }
 688 
 689     /* We need to bind on both stacks, with the same port number */
 690 
 691     memset (&oaddr, 0, sizeof(oaddr));
 692     if (family == AF_INET) {
 693         ofamily = AF_INET6;
 694         fd = b->ipv4_fd;
 695         ofd = b->ipv6_fd;
 696         port = (u_short)GET_PORT (b->addr);
 697         IN6ADDR_SETANY (&oaddr.him6);
 698         oaddr.him6.sin6_port = port;
 699     } else {
 700         ofamily = AF_INET;
 701         ofd = b->ipv4_fd;
 702         fd = b->ipv6_fd;
 703         port = (u_short)GET_PORT (b->addr);
 704         oaddr.him4.sin_family = AF_INET;
 705         oaddr.him4.sin_port = port;
 706         oaddr.him4.sin_addr.s_addr = INADDR_ANY;
 707     }
 708 
 709     rv = NET_Bind (fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr));
 710     if (rv == SOCKET_ERROR) {
 711         CLOSE_SOCKETS_AND_RETURN;
 712     }
 713 
 714     /* get the port and set it in the other address */
 715     len = SOCKETADDRESS_LEN(b->addr);
 716     if (getsockname(fd, (struct sockaddr *)b->addr, &len) == -1) {
 717         CLOSE_SOCKETS_AND_RETURN;
 718     }
 719     bound_port = GET_PORT (b->addr);
 720     SET_PORT (&oaddr, bound_port);
 721     if ((rv=NET_Bind (ofd, (struct sockaddr *) &oaddr,
 722                                 SOCKETADDRESS_LEN (&oaddr))) == SOCKET_ERROR) {
 723         int retries;
 724         int sotype, arglen=sizeof(sotype);
 725 
 726         /* no retries unless, the request was for any free port */
 727 
 728         if (port != 0) {
 729             CLOSE_SOCKETS_AND_RETURN;
 730         }
 731 
 732         getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype, &arglen);
 733 
 734 #define SOCK_RETRIES 50
 735         /* 50 is an arbitrary limit, just to ensure that this
 736          * cannot be an endless loop. Would expect socket creation to
 737          * succeed sooner.
 738          */
 739         for (retries = 0; retries < SOCK_RETRIES; retries ++) {
 740             int len;
 741             close_fd = fd; fd = -1;
 742             close_ofd = ofd; ofd = -1;
 743             b->ipv4_fd = SOCKET_ERROR;
 744             b->ipv6_fd = SOCKET_ERROR;
 745 
 746             /* create two new sockets */
 747             fd = socket (family, sotype, 0);
 748             if (fd == SOCKET_ERROR) {
 749                 CLOSE_SOCKETS_AND_RETURN;
 750             }
 751             ofd = socket (ofamily, sotype, 0);
 752             if (ofd == SOCKET_ERROR) {
 753                 CLOSE_SOCKETS_AND_RETURN;
 754             }
 755 
 756             /* bind random port on first socket */
 757             SET_PORT (&oaddr, 0);
 758             rv = NET_Bind (ofd, (struct sockaddr *)&oaddr, SOCKETADDRESS_LEN(&oaddr));
 759             if (rv == SOCKET_ERROR) {
 760                 CLOSE_SOCKETS_AND_RETURN;
 761             }
 762             /* close the original pair of sockets before continuing */
 763             closesocket (close_fd);
 764             closesocket (close_ofd);
 765             close_fd = close_ofd = -1;
 766 
 767             /* bind new port on second socket */
 768             len = SOCKETADDRESS_LEN(&oaddr);
 769             if (getsockname(ofd, (struct sockaddr *)&oaddr, &len) == -1) {
 770                 CLOSE_SOCKETS_AND_RETURN;
 771             }
 772             bound_port = GET_PORT (&oaddr);
 773             SET_PORT (b->addr, bound_port);
 774             rv = NET_Bind (fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr));
 775 
 776             if (rv != SOCKET_ERROR) {
 777                 if (family == AF_INET) {
 778                     b->ipv4_fd = fd;
 779                     b->ipv6_fd = ofd;
 780                 } else {
 781                     b->ipv4_fd = ofd;
 782                     b->ipv6_fd = fd;
 783                 }
 784                 return 0;
 785             }
 786         }
 787         CLOSE_SOCKETS_AND_RETURN;
 788     }
 789     return 0;
 790 }
 791 
 792 /*
 793  * Determine the default interface for an IPv6 address.
 794  *
 795  * Returns :-
 796  *      0 if error
 797  *      > 0 interface index to use
 798  */
 799 jint getDefaultIPv6Interface(JNIEnv *env, struct SOCKADDR_IN6 *target_addr)
 800 {
 801     int ret;
 802     DWORD b;
 803     struct sockaddr_in6 route;
 804     SOCKET fd = socket(AF_INET6, SOCK_STREAM, 0);
 805     if (fd < 0) {
 806         return 0;
 807     }
 808 
 809     ret = WSAIoctl(fd, SIO_ROUTING_INTERFACE_QUERY,
 810                     (void *)target_addr, sizeof(struct sockaddr_in6),
 811                     (void *)&route, sizeof(struct sockaddr_in6),
 812                     &b, 0, 0);
 813     if (ret < 0) {
 814         // error
 815         closesocket(fd);
 816         return 0;
 817     } else {
 818         closesocket(fd);
 819         return route.sin6_scope_id;
 820     }
 821 }
 822 
 823 /* If address types is IPv6, then IPv6 must be available. Otherwise
 824  * no address can be generated. In the case of an IPv4 Inetaddress this
 825  * method will return an IPv4 mapped address where IPv6 is available and
 826  * v4MappedAddress is TRUE. Otherwise it will return a sockaddr_in
 827  * structure for an IPv4 InetAddress.
 828 */
 829 JNIEXPORT int JNICALL
 830 NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him,
 831                           int *len, jboolean v4MappedAddress) {
 832     jint family, iafam;
 833     iafam = (*env)->GetIntField(env, iaObj, ia_familyID);
 834     family = (iafam == IPv4)? AF_INET : AF_INET6;
 835     if (ipv6_available() && !(family == AF_INET && v4MappedAddress == JNI_FALSE)) {
 836         struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
 837         jbyteArray ipaddress;
 838         jbyte caddr[16];
 839         jint address, scopeid = 0;
 840         jint cached_scope_id = 0;
 841 
 842         if (family == AF_INET) { /* will convert to IPv4-mapped address */
 843             memset((char *) caddr, 0, 16);
 844             address = (*env)->GetIntField(env, iaObj, ia_addressID);
 845             if (address == INADDR_ANY) {
 846                 /* we would always prefer IPv6 wildcard address
 847                 caddr[10] = 0xff;
 848                 caddr[11] = 0xff; */
 849             } else {
 850                 caddr[10] = 0xff;
 851                 caddr[11] = 0xff;
 852                 caddr[12] = ((address >> 24) & 0xff);
 853                 caddr[13] = ((address >> 16) & 0xff);
 854                 caddr[14] = ((address >> 8) & 0xff);
 855                 caddr[15] = (address & 0xff);
 856             }
 857         } else {
 858             ipaddress = (*env)->GetObjectField(env, iaObj, ia6_ipaddressID);
 859             scopeid = (jint)(*env)->GetIntField(env, iaObj, ia6_scopeidID);
 860             cached_scope_id = (jint)(*env)->GetIntField(env, iaObj, ia6_cachedscopeidID);
 861             (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddr);
 862         }
 863 
 864         memset((char *)him6, 0, sizeof(struct SOCKADDR_IN6));
 865         him6->sin6_port = (u_short) htons((u_short)port);
 866         memcpy((void *)&(him6->sin6_addr), caddr, sizeof(struct in6_addr) );
 867         him6->sin6_family = AF_INET6;
 868         if ((family == AF_INET6) && IN6_IS_ADDR_LINKLOCAL( &(him6->sin6_addr) )
 869             && (!scopeid && !cached_scope_id)) {
 870             cached_scope_id = getDefaultIPv6Interface(env, him6);
 871             (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id);
 872         }
 873         him6->sin6_scope_id = scopeid != 0 ? scopeid : cached_scope_id;
 874         *len = sizeof(struct SOCKADDR_IN6) ;
 875     } else {
 876         struct sockaddr_in *him4 = (struct sockaddr_in*)him;
 877         jint address;
 878         if (family != AF_INET) {
 879           JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable");
 880           return -1;
 881         }
 882         memset((char *) him4, 0, sizeof(struct sockaddr_in));
 883         address = (int)(*env)->GetIntField(env, iaObj, ia_addressID);
 884         him4->sin_port = htons((short) port);
 885         him4->sin_addr.s_addr = (u_long) htonl(address);
 886         him4->sin_family = AF_INET;
 887         *len = sizeof(struct sockaddr_in);
 888     }
 889     return 0;
 890 }
 891 
 892 JNIEXPORT jint JNICALL
 893 NET_GetPortFromSockaddr(struct sockaddr *him) {
 894     if (him->sa_family == AF_INET6) {
 895         return ntohs(((struct sockaddr_in6*)him)->sin6_port);
 896     } else {
 897         return ntohs(((struct sockaddr_in*)him)->sin_port);
 898     }
 899 }
 900 
 901 int
 902 NET_IsIPv4Mapped(jbyte* caddr) {
 903     int i;
 904     for (i = 0; i < 10; i++) {
 905         if (caddr[i] != 0x00) {
 906             return 0; /* false */
 907         }
 908     }
 909 
 910     if (((caddr[10] & 0xff) == 0xff) && ((caddr[11] & 0xff) == 0xff)) {
 911         return 1; /* true */
 912     }
 913     return 0; /* false */
 914 }
 915 
 916 int
 917 NET_IPv4MappedToIPv4(jbyte* caddr) {
 918     return ((caddr[12] & 0xff) << 24) | ((caddr[13] & 0xff) << 16) | ((caddr[14] & 0xff) << 8)
 919         | (caddr[15] & 0xff);
 920 }
 921 
 922 int
 923 NET_IsEqual(jbyte* caddr1, jbyte* caddr2) {
 924     int i;
 925     for (i = 0; i < 16; i++) {
 926         if (caddr1[i] != caddr2[i]) {
 927             return 0; /* false */
 928         }
 929     }
 930     return 1;
 931 }
 932 
 933 int getScopeID (struct sockaddr *him) {
 934     struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
 935     return him6->sin6_scope_id;
 936 }
 937 
 938 int cmpScopeID (unsigned int scope, struct sockaddr *him) {
 939     struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
 940     return him6->sin6_scope_id == scope;
 941 }
 942 
 943 /**
 944  * Wrapper for select/poll with timeout on a single file descriptor.
 945  *
 946  * flags (defined in net_util_md.h can be any combination of
 947  * NET_WAIT_READ, NET_WAIT_WRITE & NET_WAIT_CONNECT.
 948  *
 949  * The function will return when either the socket is ready for one
 950  * of the specified operation or the timeout expired.
 951  *
 952  * It returns the time left from the timeout, or -1 if it expired.
 953  */
 954 
 955 jint
 956 NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout)
 957 {
 958     jlong prevTime = JVM_CurrentTimeMillis(env, 0);
 959     jint read_rv;
 960 
 961     while (1) {
 962         jlong newTime;
 963         fd_set rd, wr, ex;
 964         struct timeval t;
 965 
 966         t.tv_sec = timeout / 1000;
 967         t.tv_usec = (timeout % 1000) * 1000;
 968 
 969         FD_ZERO(&rd);
 970         FD_ZERO(&wr);
 971         FD_ZERO(&ex);
 972         if (flags & NET_WAIT_READ) {
 973           FD_SET(fd, &rd);
 974         }
 975         if (flags & NET_WAIT_WRITE) {
 976           FD_SET(fd, &wr);
 977         }
 978         if (flags & NET_WAIT_CONNECT) {
 979           FD_SET(fd, &wr);
 980           FD_SET(fd, &ex);
 981         }
 982 
 983         errno = 0;
 984         read_rv = select(fd+1, &rd, &wr, &ex, &t);
 985 
 986         newTime = JVM_CurrentTimeMillis(env, 0);
 987         timeout -= (jint)(newTime - prevTime);
 988         if (timeout <= 0) {
 989           return read_rv > 0 ? 0 : -1;
 990         }
 991         newTime = prevTime;
 992 
 993         if (read_rv > 0) {
 994           break;
 995         }
 996 
 997 
 998       } /* while */
 999 
1000     return timeout;
1001 }
1002 
1003 int NET_Socket (int domain, int type, int protocol) {
1004     int sock;
1005     sock = socket (domain, type, protocol);
1006     if (sock != INVALID_SOCKET) {
1007         SetHandleInformation((HANDLE)(uintptr_t)sock, HANDLE_FLAG_INHERIT, FALSE);
1008     }
1009     return sock;
1010 }
--- EOF ---