1 /*
   2  * Copyright 2000-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 <stdlib.h>
  27 #include <windows.h>
  28 #include <winsock2.h>           /* needed for htonl */
  29 #include <iprtrmib.h>
  30 #include <assert.h>
  31 
  32 #include "java_net_NetworkInterface.h"
  33 #include "jni_util.h"
  34 
  35 #include "NetworkInterface.h"
  36 
  37 /*
  38  * Windows implementation of the java.net.NetworkInterface native methods.
  39  * This module provides the implementations of getAll, getByName, getByIndex,
  40  * and getByAddress.
  41  *
  42  * Interfaces and addresses are enumerated using the IP helper routines
  43  * GetIfTable, GetIfAddrTable resp. These routines are available on Windows
  44  * 98, NT SP+4, 2000, and XP. They are also available on Windows 95 if
  45  * IE is upgraded to 5.x.
  46  *
  47  * Windows does not have any standard for device names so we are forced
  48  * to use our own convention which is based on the normal Unix naming
  49  * convention ("lo" for the loopback, eth0, eth1, .. for ethernet devices,
  50  * tr0, tr1, .. for token ring, and so on). This convention gives us
  51  * consistency across multiple Windows editions and also consistency with
  52  * Solaris/Linux device names. Note that we always enumerate in index
  53  * order and this ensures consistent device number across invocations.
  54  */
  55 
  56 
  57 /* IP helper library routines */
  58 int (PASCAL FAR *GetIpAddrTable_fn)();
  59 int (PASCAL FAR *GetIfTable_fn)();
  60 int (PASCAL FAR *GetFriendlyIfIndex_fn)();
  61 int (PASCAL FAR *GetAdaptersAddresses_fn)();
  62 int (PASCAL FAR *GetAdaptersInfo_fn)();
  63 int (PASCAL FAR *GetNumberOfInterfaces_fn)();
  64 
  65 /* Enumeration routines */
  66 typedef int (*EnumerateNetInterfaces)(JNIEnv *, netif **);
  67 typedef int(*EnumerateNetAddresses)(JNIEnv *, netif *, netaddr **);
  68 
  69 static EnumerateNetInterfaces enumInterfaces_fn;
  70 static EnumerateNetAddresses enumAddresses_fn;
  71 
  72 /* Windows 9x routines are external (not needed on 64-bit) */
  73 #ifndef _WIN64
  74 extern int enumInterfaces_win9x(JNIEnv *, netif **);
  75 extern int enumAddresses_win9x(JNIEnv *, netif *, netaddr **);
  76 extern int init_win9x(void);
  77 #endif
  78 
  79 
  80 /* Windows 95/98/ME running */
  81 static jboolean isW9x;
  82 
  83 /* Windows version supports */
  84 static jboolean os_supports_ipv6;
  85 
  86 /* various JNI ids */
  87 
  88 jclass ni_class;            /* NetworkInterface */
  89 
  90 jmethodID ni_ctrID;          /* NetworkInterface() */
  91 
  92 jfieldID ni_indexID;        /* NetworkInterface.index */
  93 jfieldID ni_addrsID;        /* NetworkInterface.addrs */
  94 jfieldID ni_bindsID;        /* NetworkInterface.bindings */
  95 jfieldID ni_nameID;         /* NetworkInterface.name */
  96 jfieldID ni_displayNameID;  /* NetworkInterface.displayName */
  97 jfieldID ni_childsID;       /* NetworkInterface.childs */
  98 
  99 jclass ni_ibcls;            /* InterfaceAddress */
 100 jmethodID ni_ibctrID;       /* InterfaceAddress() */
 101 jfieldID ni_ibaddressID;        /* InterfaceAddress.address */
 102 jfieldID ni_ibbroadcastID;      /* InterfaceAddress.broadcast */
 103 jfieldID ni_ibmaskID;           /* InterfaceAddress.maskLength */
 104 
 105 /*
 106  * Support routines to free netif and netaddr lists
 107  */
 108 void free_netif(netif *netifP) {
 109     netif *curr = netifP;
 110     while (curr != NULL) {
 111         if (curr->name != NULL)
 112             free(curr->name);
 113         if (curr->displayName != NULL)
 114             free(curr->displayName);
 115         if (curr->addrs != NULL)
 116             free_netaddr (curr->addrs);
 117         netifP = netifP->next;
 118         free(curr);
 119         curr = netifP;
 120     }
 121 }
 122 
 123 void free_netaddr(netaddr *netaddrP) {
 124     netaddr *curr = netaddrP;
 125     while (curr != NULL) {
 126         netaddrP = netaddrP->next;
 127         free(curr);
 128         curr = netaddrP;
 129     }
 130 }
 131 
 132 /*
 133  * Returns the interface structure from the table with the matching index.
 134  */
 135 MIB_IFROW *getIF(jint index) {
 136     MIB_IFTABLE *tableP;
 137     MIB_IFROW *ifrowP, *ret = NULL;
 138     ULONG size;
 139     DWORD i, count;
 140     jint ifindex;
 141 
 142     /*
 143      * Ask the IP Helper library to enumerate the adapters
 144      */
 145     size = sizeof(MIB_IFTABLE);
 146     tableP = (MIB_IFTABLE *)malloc(size);
 147     count = (*GetIfTable_fn)(tableP, &size, TRUE);
 148     if (count == ERROR_INSUFFICIENT_BUFFER || count == ERROR_BUFFER_OVERFLOW) {
 149         tableP = (MIB_IFTABLE *)realloc(tableP, size);
 150         count = (*GetIfTable_fn)(tableP, &size, TRUE);
 151     }
 152 
 153     if (count != NO_ERROR) {
 154         if (tableP != NULL)
 155             free(tableP);
 156         return NULL;
 157     }
 158 
 159     if (tableP != NULL) {
 160       ifrowP = tableP->table;
 161       for (i=0; i<tableP->dwNumEntries; i++) {
 162         /*
 163          * Warning the real index is obtained by GetFriendlyIfIndex()
 164          */
 165         ifindex = (*GetFriendlyIfIndex_fn)(ifrowP->dwIndex);
 166         if (ifindex == index) {
 167           /*
 168            * Create a copy of the entry so that we can free the table.
 169            */
 170           ret = (MIB_IFROW *) malloc(sizeof(MIB_IFROW));
 171           memcpy(ret, ifrowP, sizeof(MIB_IFROW));
 172           break;
 173         }
 174 
 175         /* onto the next interface */
 176         ifrowP++;
 177       }
 178       free(tableP);
 179     }
 180     return ret;
 181 }
 182 
 183 /*
 184  * Enumerate network interfaces using IP Helper Library routine GetIfTable.
 185  * We use GetIfTable rather than other IP helper routines because it's
 186  * available on 98 & NT SP4+.
 187  *
 188  * Returns the number of interfaces found or -1 if error. If no error
 189  * occurs then netifPP be returned as list of netif structures or NULL
 190  * if no interfaces are found.
 191  */
 192 int enumInterfaces_win(JNIEnv *env, netif **netifPP)
 193 {
 194     MIB_IFTABLE *tableP;
 195     MIB_IFROW *ifrowP;
 196     ULONG size;
 197     DWORD ret;
 198     int count;
 199     netif *netifP;
 200     DWORD i;
 201     int lo=0, eth=0, tr=0, fddi=0, ppp=0, sl=0, net=0;
 202 
 203     /*
 204      * Ask the IP Helper library to enumerate the adapters
 205      */
 206     size = sizeof(MIB_IFTABLE);
 207     tableP = (MIB_IFTABLE *)malloc(size);
 208     ret = (*GetIfTable_fn)(tableP, &size, TRUE);
 209     if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW) {
 210         tableP = (MIB_IFTABLE *)realloc(tableP, size);
 211         ret = (*GetIfTable_fn)(tableP, &size, TRUE);
 212     }
 213 
 214     if (ret != NO_ERROR) {
 215         if (tableP != NULL)
 216             free(tableP);
 217 
 218 #ifndef _WIN64
 219         if (isW9x && ret == ERROR_NOT_SUPPORTED) {
 220             /*
 221              * If ERROR_NOT_SUPPORTED is returned on Windows 98 it means that
 222              * IE5.0 has been installed. In this case we revert to the Windows 95
 223              * approach and avoid using the IP Helper Library.
 224              * See: http://support.microsoft.com/support/kb/articles/q234/5/73.asp
 225              */
 226             enumInterfaces_fn = enumInterfaces_win9x;
 227             enumAddresses_fn = enumAddresses_win9x;
 228             init_win9x();
 229 
 230             return (*enumInterfaces_fn)(env, netifPP);
 231         }
 232 #endif
 233 
 234         JNU_ThrowByName(env, "java/lang/Error",
 235                 "IP Helper Library GetIfTable function failed");
 236 
 237         return -1;
 238     }
 239 
 240     /*
 241      * Iterate through the list of adapters
 242      */
 243     count = 0;
 244     netifP = NULL;
 245 
 246     ifrowP = tableP->table;
 247     for (i=0; i<tableP->dwNumEntries; i++) {
 248         char dev_name[8];
 249         netif *curr;
 250 
 251         /*
 252          * Generate a name for the device as Windows doesn't have any
 253          * real concept of a device name.
 254          */
 255         switch (ifrowP->dwType) {
 256             case MIB_IF_TYPE_ETHERNET:
 257                 sprintf(dev_name, "eth%d", eth++);
 258                 break;
 259 
 260             case MIB_IF_TYPE_TOKENRING:
 261                 sprintf(dev_name, "tr%d", tr++);
 262                 break;
 263 
 264             case MIB_IF_TYPE_FDDI:
 265                 sprintf(dev_name, "fddi%d", fddi++);
 266                 break;
 267 
 268             case MIB_IF_TYPE_LOOPBACK:
 269                 /* There should only be only IPv4 loopback address */
 270                 if (lo > 0) {
 271                     continue;
 272                 }
 273                 strcpy(dev_name, "lo");
 274                 lo++;
 275                 break;
 276 
 277             case MIB_IF_TYPE_PPP:
 278                 sprintf(dev_name, "ppp%d", ppp++);
 279                 break;
 280 
 281             case MIB_IF_TYPE_SLIP:
 282                 sprintf(dev_name, "sl%d", sl++);
 283                 break;
 284 
 285             default:
 286                 sprintf(dev_name, "net%d", net++);
 287         }
 288 
 289         /*
 290          * Allocate a netif structure and space for the name and
 291          * display name (description in this case).
 292          */
 293         curr = (netif *)calloc(1, sizeof(netif));
 294         if (curr != NULL) {
 295             curr->name = (char *)malloc(strlen(dev_name) + 1);
 296             curr->displayName = (char *)malloc(ifrowP->dwDescrLen + 1);
 297 
 298             if (curr->name == NULL || curr->displayName == NULL) {
 299                 if (curr->name) free(curr->name);
 300                 if (curr->displayName) free(curr->displayName);
 301                 curr = NULL;
 302             }
 303         }
 304         if (curr == NULL) {
 305             JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
 306             free_netif(netifP);
 307             free(tableP);
 308             return -1;
 309         }
 310 
 311         /*
 312          * Populate the interface. Note that we need to convert the
 313          * index into its "friendly" value as otherwise we will expose
 314          * 32-bit numbers as index values.
 315          */
 316         strcpy(curr->name, dev_name);
 317         strncpy(curr->displayName, ifrowP->bDescr, ifrowP->dwDescrLen);
 318         curr->displayName[ifrowP->dwDescrLen] = '\0';
 319         curr->dwIndex = ifrowP->dwIndex;
 320         curr->ifType = ifrowP->dwType;
 321         curr->index = (*GetFriendlyIfIndex_fn)(ifrowP->dwIndex);
 322 
 323         /*
 324          * Put the interface at tail of list as GetIfTable(,,TRUE) is
 325          * returning the interfaces in index order.
 326          */
 327         count++;
 328         if (netifP == NULL) {
 329             netifP = curr;
 330         } else {
 331             netif *tail = netifP;
 332             while (tail->next != NULL) {
 333                 tail = tail->next;
 334             }
 335             tail->next = curr;
 336         }
 337 
 338         /* onto the next interface */
 339         ifrowP++;
 340     }
 341 
 342     /*
 343      * Free the interface table and return the interface list
 344      */
 345     if (tableP) {
 346         free(tableP);
 347     }
 348     *netifPP = netifP;
 349     return count;
 350 }
 351 
 352 /*
 353  * Enumerate the IP addresses on an interface using the IP helper library
 354  * routine GetIfAddrTable and matching based on the index name. There are
 355  * more efficient routines but we use GetIfAddrTable because it's avaliable
 356  * on 98 and NT.
 357  *
 358  * Returns the count of addresses, or -1 if error. If no error occurs then
 359  * netaddrPP will return a list of netaddr structures with the IP addresses.
 360  */
 361 int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP)
 362 {
 363     MIB_IPADDRTABLE *tableP;
 364     ULONG size;
 365     DWORD ret;
 366     DWORD i;
 367     netaddr *netaddrP;
 368     int count = 0;
 369     unsigned long mask;
 370 
 371     /*
 372      * Use GetIpAddrTable to enumerate the IP Addresses
 373      */
 374     size = sizeof(MIB_IPADDRTABLE);
 375     tableP = (MIB_IPADDRTABLE *)malloc(size);
 376 
 377     ret = (*GetIpAddrTable_fn)(&tableP, &size, FALSE);
 378     if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW) {
 379         tableP = (MIB_IPADDRTABLE *)realloc(tableP, size);
 380         ret = (*GetIpAddrTable_fn)(tableP, &size, FALSE);
 381     }
 382     if (ret != NO_ERROR) {
 383         if (tableP) {
 384             free(tableP);
 385         }
 386         JNU_ThrowByName(env, "java/lang/Error",
 387                 "IP Helper Library GetIpAddrTable function failed");
 388         return -1;
 389     }
 390 
 391     /*
 392      * Iterate through the table to find the addresses with the
 393      * matching dwIndex. Ignore 0.0.0.0 addresses.
 394      */
 395     count = 0;
 396     netaddrP = NULL;
 397 
 398     i = 0;
 399     while (i<tableP->dwNumEntries) {
 400         if (tableP->table[i].dwIndex == netifP->dwIndex &&
 401             tableP->table[i].dwAddr != 0) {
 402 
 403             netaddr *curr = (netaddr *)malloc(sizeof(netaddr));
 404             if (curr == NULL) {
 405                 JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
 406                 free_netaddr(netaddrP);
 407                 free(tableP);
 408                 return -1;
 409             }
 410 
 411             curr->addr.him4.sin_family = AF_INET;
 412             curr->addr.him4.sin_addr.s_addr = tableP->table[i].dwAddr;
 413             /*
 414              * Get netmask / broadcast address
 415              */
 416             switch (netifP->ifType) {
 417             case MIB_IF_TYPE_ETHERNET:
 418             case MIB_IF_TYPE_TOKENRING:
 419             case MIB_IF_TYPE_FDDI:
 420             case MIB_IF_TYPE_LOOPBACK:
 421               /**
 422                * Contrary to what it seems to indicate, dwBCastAddr doesn't
 423                * contain the broadcast address but 0 or 1 depending on whether
 424                * the broadcast address should set the bits of the host part
 425                * to 0 or 1.
 426                * Yes, I know it's stupid, but what can I say, it's MSFTs API.
 427                */
 428               curr->brdcast.him4.sin_family = AF_INET;
 429               if (tableP->table[i].dwBCastAddr == 1)
 430                 curr->brdcast.him4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask) | (0xffffffff ^ tableP->table[i].dwMask);
 431               else
 432                 curr->brdcast.him4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask);
 433               mask = ntohl(tableP->table[i].dwMask);
 434               curr->mask = 0;
 435               while (mask) {
 436                 mask <<= 1;
 437                 curr->mask++;
 438               }
 439               break;
 440             case MIB_IF_TYPE_PPP:
 441             case MIB_IF_TYPE_SLIP:
 442             default:
 443               /**
 444                * these don't have broadcast/subnet
 445                */
 446               curr->mask = -1;
 447                 break;
 448             }
 449 
 450             curr->next = netaddrP;
 451             netaddrP = curr;
 452             count++;
 453         }
 454         i++;
 455     }
 456 
 457     *netaddrPP = netaddrP;
 458     free(tableP);
 459     return count;
 460 }
 461 
 462 /*
 463  * Class:     java_net_NetworkInterface
 464  * Method:    init
 465  * Signature: ()V
 466  */
 467 JNIEXPORT void JNICALL
 468 Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls)
 469 {
 470     OSVERSIONINFO ver;
 471     HANDLE h;
 472 
 473     /*
 474      * First check if this is a Windows 9x machine.
 475      */
 476     ver.dwOSVersionInfoSize = sizeof(ver);
 477     GetVersionEx(&ver);
 478     if (ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && ver.dwMajorVersion == 4) {
 479         isW9x = JNI_TRUE;
 480     }
 481 
 482     /*
 483      * Try to load the IP Helper Library and obtain the entry points we
 484      * require. This will succeed on 98, NT SP4+, 2000 & XP. It will
 485      * fail on Windows 95 (if IE hasn't been updated) and old versions
 486      * of NT (IP helper library only appeared at SP4). If it fails on
 487      * Windows 9x we will use the registry approach, otherwise if it
 488      * fails we throw an Error indicating that we have an incompatible
 489      * IP helper library.
 490      */
 491     h = LoadLibrary("iphlpapi.dll");
 492     if (h != NULL) {
 493         GetIpAddrTable_fn =
 494             (int (PASCAL FAR *)())GetProcAddress(h, "GetIpAddrTable");
 495         GetIfTable_fn =
 496             (int (PASCAL FAR *)())GetProcAddress(h, "GetIfTable");
 497         GetFriendlyIfIndex_fn =
 498             (int (PASCAL FAR *)())GetProcAddress(h, "GetFriendlyIfIndex");
 499         GetNumberOfInterfaces_fn =
 500             (int (PASCAL FAR *)())GetProcAddress(h, "GetNumberOfInterfaces");
 501         GetAdaptersAddresses_fn =
 502             (int (PASCAL FAR *)())GetProcAddress(h, "GetAdaptersAddresses");
 503         GetAdaptersInfo_fn =
 504             (int (PASCAL FAR *)())GetProcAddress(h, "GetAdaptersInfo");
 505     }
 506 
 507     /* IPv6 is supported on Windows versions if the following APIs avail */
 508 
 509     os_supports_ipv6 = (GetAdaptersAddresses_fn != NULL) &&
 510                        (GetNumberOfInterfaces_fn != NULL) &&
 511                        (GetAdaptersInfo_fn != NULL);
 512 
 513     if (GetIpAddrTable_fn == NULL ||
 514         GetIfTable_fn == NULL ||
 515         GetFriendlyIfIndex_fn == NULL) {
 516 
 517 #ifndef _WIN64
 518         if (isW9x) {
 519             /* Use Windows 9x registry approach which requires initialization */
 520             enumInterfaces_fn = enumInterfaces_win9x;
 521             enumAddresses_fn = enumAddresses_win9x;
 522             init_win9x();
 523         } else
 524 #endif
 525         {
 526             JNU_ThrowByName(env, "java/lang/Error",
 527                 "Incompatible IP helper library (iphlpapi.dll)");
 528             return;
 529         }
 530     } else {
 531         enumInterfaces_fn = enumInterfaces_win;
 532         enumAddresses_fn = enumAddresses_win;
 533     }
 534 
 535     /*
 536      * Get the various JNI ids that we require
 537      */
 538     if (ni_ibmaskID == NULL) {
 539         ni_class = (*env)->NewGlobalRef(env, cls);
 540         ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;");
 541         ni_displayNameID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;");
 542         ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
 543         ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;");
 544         ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;");
 545         ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;");
 546         ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
 547 
 548         init(env);
 549 
 550         ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
 551         ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
 552         ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
 553         ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;");
 554         ni_ibbroadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;");
 555         ni_ibmaskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
 556     }
 557 }
 558 
 559 /*
 560  * Create a NetworkInterface object, populate the name and index, and
 561  * populate the InetAddress array based on the IP addresses for this
 562  * interface.
 563  */
 564 jobject createNetworkInterface(JNIEnv *env, netif *ifs, int netaddrCount, netaddr *netaddrP)
 565 {
 566     jobject netifObj;
 567     jobject name, displayName;
 568     jobjectArray addrArr, bindsArr, childArr;
 569     netaddr *addrs;
 570     jint addr_index;
 571     jint bind_index;
 572 
 573     /*
 574      * Create a NetworkInterface object and populate it
 575      */
 576     netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);
 577     name = (*env)->NewStringUTF(env, ifs->name);
 578     if (ifs->dNameIsUnicode) {
 579         displayName = (*env)->NewString(env, (PWCHAR)ifs->displayName, wcslen ((PWCHAR)ifs->displayName));
 580     } else {
 581         displayName = (*env)->NewStringUTF(env, ifs->displayName);
 582     }
 583     if (netifObj == NULL || name == NULL || displayName == NULL) {
 584         return NULL;
 585     }
 586     (*env)->SetObjectField(env, netifObj, ni_nameID, name);
 587     (*env)->SetObjectField(env, netifObj, ni_displayNameID, displayName);
 588     (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
 589 
 590     /*
 591      * Get the IP addresses for this interface if necessary
 592      * Note that 0 is a valid number of addresses.
 593      */
 594     if (netaddrCount < 0) {
 595         netaddrCount = (*enumAddresses_fn)(env, ifs, &netaddrP);
 596         if ((*env)->ExceptionOccurred(env)) {
 597             free_netaddr(netaddrP);
 598             return NULL;
 599         }
 600     }
 601     addrArr = (*env)->NewObjectArray(env, netaddrCount, ia_class, NULL);
 602     if (addrArr == NULL) {
 603         free_netaddr(netaddrP);
 604         return NULL;
 605     }
 606 
 607     bindsArr = (*env)->NewObjectArray(env, netaddrCount, ni_ibcls, NULL);
 608     if (bindsArr == NULL) {
 609       free_netaddr(netaddrP);
 610       return NULL;
 611     }
 612     addrs = netaddrP;
 613     addr_index = 0;
 614     bind_index = 0;
 615     while (addrs != NULL) {
 616         jobject iaObj, ia2Obj;
 617         jobject ibObj = NULL;
 618         if (addrs->addr.him.sa_family == AF_INET) {
 619             iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 620             if (iaObj == NULL) {
 621                 free_netaddr(netaddrP);
 622                 return NULL;
 623             }
 624             /* default ctor will set family to AF_INET */
 625 
 626             (*env)->SetIntField(env, iaObj, ia_addressID, ntohl(addrs->addr.him4.sin_addr.s_addr));
 627             if (addrs->mask != -1) {
 628               ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
 629               if (ibObj == NULL) {
 630                 free_netaddr(netaddrP);
 631                 return NULL;
 632               }
 633               (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
 634               ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 635               if (ia2Obj == NULL) {
 636                 free_netaddr(netaddrP);
 637                 return NULL;
 638               }
 639               (*env)->SetIntField(env, ia2Obj, ia_addressID,
 640                                   ntohl(addrs->brdcast.him4.sin_addr.s_addr));
 641               (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj);
 642               (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
 643               (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
 644             }
 645         } else /* AF_INET6 */ {
 646             int scope;
 647             iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
 648             if (iaObj) {
 649                 jbyteArray ipaddress = (*env)->NewByteArray(env, 16);
 650                 if (ipaddress == NULL) {
 651                     return NULL;
 652                 }
 653                 (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
 654                     (jbyte *)&(addrs->addr.him6.sin6_addr.s6_addr));
 655                 scope = addrs->addr.him6.sin6_scope_id;
 656                 if (scope != 0) { /* zero is default value, no need to set */
 657                     (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
 658                     (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
 659                     (*env)->SetObjectField(env, iaObj, ia6_scopeifnameID, netifObj);
 660                 }
 661                 (*env)->SetObjectField(env, iaObj, ia6_ipaddressID, ipaddress);
 662                 ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
 663                 if (ibObj == NULL) {
 664                   free_netaddr(netaddrP);
 665                   return NULL;
 666                 }
 667                 (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
 668                 (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
 669                 (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
 670             }
 671         }
 672         (*env)->SetObjectArrayElement(env, addrArr, addr_index, iaObj);
 673         addrs = addrs->next;
 674         addr_index++;
 675     }
 676     (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
 677     (*env)->SetObjectField(env, netifObj, ni_bindsID, bindsArr);
 678 
 679     free_netaddr(netaddrP);
 680 
 681     /*
 682      * Windows doesn't have virtual interfaces, so child array
 683      * is always empty.
 684      */
 685     childArr = (*env)->NewObjectArray(env, 0, ni_class, NULL);
 686     if (childArr == NULL) {
 687       return NULL;
 688     }
 689     (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
 690 
 691     /* return the NetworkInterface */
 692     return netifObj;
 693 }
 694 
 695 /*
 696  * Class:     java_net_NetworkInterface
 697  * Method:    getByName0
 698  * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
 699  */
 700 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0
 701     (JNIEnv *env, jclass cls, jstring name)
 702 {
 703     netif *ifList, *curr;
 704     jboolean isCopy;
 705     const char *name_utf;
 706     jobject netifObj = NULL;
 707 
 708     if (os_supports_ipv6 && ipv6_available()) {
 709         return Java_java_net_NetworkInterface_getByName0_XP (env, cls, name);
 710     }
 711 
 712     /* get the list of interfaces */
 713     if ((*enumInterfaces_fn)(env, &ifList) < 0) {
 714         return NULL;
 715     }
 716 
 717     /* get the name as a C string */
 718     name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 719 
 720     /* Search by name */
 721     curr = ifList;
 722     while (curr != NULL) {
 723         if (strcmp(name_utf, curr->name) == 0) {
 724             break;
 725         }
 726         curr = curr->next;
 727     }
 728 
 729     /* if found create a NetworkInterface */
 730     if (curr != NULL) {;
 731         netifObj = createNetworkInterface(env, curr, -1, NULL);
 732     }
 733 
 734     /* release the UTF string */
 735     (*env)->ReleaseStringUTFChars(env, name, name_utf);
 736 
 737     /* release the interface list */
 738     free_netif(ifList);
 739 
 740     return netifObj;
 741 }
 742 
 743 /*
 744  * Class:     NetworkInterface
 745  * Method:    getByIndex0
 746  * Signature: (I)LNetworkInterface;
 747  */
 748 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0
 749   (JNIEnv *env, jclass cls, jint index)
 750 {
 751     netif *ifList, *curr;
 752     jobject netifObj = NULL;
 753 
 754     if (os_supports_ipv6 && ipv6_available()) {
 755         return Java_java_net_NetworkInterface_getByIndex0_XP (env, cls, index);
 756     }
 757 
 758     /* get the list of interfaces */
 759     if ((*enumInterfaces_fn)(env, &ifList) < 0) {
 760         return NULL;
 761     }
 762 
 763     /* search by index */
 764     curr = ifList;
 765     while (curr != NULL) {
 766         if (index == curr->index) {
 767             break;
 768         }
 769         curr = curr->next;
 770     }
 771 
 772     /* if found create a NetworkInterface */
 773     if (curr != NULL) {
 774         netifObj = createNetworkInterface(env, curr, -1, NULL);
 775     }
 776 
 777     /* release the interface list */
 778     free_netif(ifList);
 779 
 780     return netifObj;
 781 }
 782 
 783 /*
 784  * Class:     java_net_NetworkInterface
 785  * Method:    getByInetAddress0
 786  * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
 787  */
 788 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
 789     (JNIEnv *env, jclass cls, jobject iaObj)
 790 {
 791     netif *ifList, *curr;
 792     jint addr = (*env)->GetIntField(env, iaObj, ia_addressID);
 793     jobject netifObj = NULL;
 794 
 795     if (os_supports_ipv6 && ipv6_available()) {
 796         return Java_java_net_NetworkInterface_getByInetAddress0_XP (env, cls, iaObj);
 797     }
 798 
 799     /* get the list of interfaces */
 800     if ((*enumInterfaces_fn)(env, &ifList) < 0) {
 801         return NULL;
 802     }
 803 
 804     /*
 805      * Enumerate the addresses on each interface until we find a
 806      * matching address.
 807      */
 808     curr = ifList;
 809     while (curr != NULL) {
 810         int count;
 811         netaddr *addrList;
 812         netaddr *addrP;
 813 
 814         /* enumerate the addresses on this interface */
 815         count = (*enumAddresses_fn)(env, curr, &addrList);
 816         if (count < 0) {
 817             free_netif(ifList);
 818             return NULL;
 819         }
 820 
 821         /* iterate through each address */
 822         addrP = addrList;
 823 
 824         while (addrP != NULL) {
 825             if ((unsigned long)addr == ntohl(addrP->addr.him4.sin_addr.s_addr)) {
 826                 break;
 827             }
 828             addrP = addrP->next;
 829         }
 830 
 831         /*
 832          * Address matched so create NetworkInterface for this interface
 833          * and address list.
 834          */
 835         if (addrP != NULL) {
 836             /* createNetworkInterface will free addrList */
 837             netifObj = createNetworkInterface(env, curr, count, addrList);
 838             break;
 839         }
 840 
 841         /* on next interface */
 842         curr = curr->next;
 843     }
 844 
 845     /* release the interface list */
 846     free_netif(ifList);
 847 
 848     return netifObj;
 849 }
 850 
 851 /*
 852  * Class:     java_net_NetworkInterface
 853  * Method:    getAll
 854  * Signature: ()[Ljava/net/NetworkInterface;
 855  */
 856 JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll
 857     (JNIEnv *env, jclass cls)
 858 {
 859     int count;
 860     netif *ifList, *curr;
 861     jobjectArray netIFArr;
 862     jint arr_index;
 863 
 864     if (os_supports_ipv6 && ipv6_available()) {
 865         return Java_java_net_NetworkInterface_getAll_XP (env, cls);
 866     }
 867 
 868     /*
 869      * Get list of interfaces
 870      */
 871     count = (*enumInterfaces_fn)(env, &ifList);
 872     if (count < 0) {
 873         return NULL;
 874     }
 875 
 876     /* allocate a NetworkInterface array */
 877     netIFArr = (*env)->NewObjectArray(env, count, cls, NULL);
 878     if (netIFArr == NULL) {
 879         return NULL;
 880     }
 881 
 882     /*
 883      * Iterate through the interfaces, create a NetworkInterface instance
 884      * for each array element and populate the object.
 885      */
 886     curr = ifList;
 887     arr_index = 0;
 888     while (curr != NULL) {
 889         jobject netifObj;
 890 
 891         netifObj = createNetworkInterface(env, curr, -1, NULL);
 892         if (netifObj == NULL) {
 893             return NULL;
 894         }
 895 
 896         /* put the NetworkInterface into the array */
 897         (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
 898 
 899         curr = curr->next;
 900     }
 901 
 902     /* release the interface list */
 903     free_netif(ifList);
 904 
 905     return netIFArr;
 906 }
 907 
 908 /*
 909  * Class:     java_net_NetworkInterface
 910  * Method:    isUp0
 911  * Signature: (Ljava/lang/String;)Z
 912  */
 913 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0
 914     (JNIEnv *env, jclass cls, jstring name, jint index) {
 915   jboolean ret = JNI_FALSE;
 916 
 917   if (os_supports_ipv6 && ipv6_available()) {
 918     return Java_java_net_NetworkInterface_isUp0_XP(env, cls, name, index);
 919   } else {
 920     MIB_IFROW *ifRowP;
 921     ifRowP = getIF(index);
 922     if (ifRowP != NULL) {
 923       ret = ifRowP->dwAdminStatus == 1 && (ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL || ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED);
 924       free(ifRowP);
 925     }
 926   }
 927     return ret;
 928 }
 929 
 930 /*
 931  * Class:     java_net_NetworkInterface
 932  * Method:    isP2P0
 933  * Signature: (Ljava/lang/String;I)Z
 934  */
 935 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0(JNIEnv *env, jclass cls, jstring name, jint index) {
 936   MIB_IFROW *ifRowP;
 937   jboolean ret = JNI_FALSE;
 938 
 939   if (os_supports_ipv6 && ipv6_available()) {
 940     return Java_java_net_NetworkInterface_isP2P0_XP(env, cls, name, index);
 941   } else {
 942     ifRowP = getIF(index);
 943     if (ifRowP != NULL) {
 944       switch(ifRowP->dwType) {
 945       case MIB_IF_TYPE_PPP:
 946       case MIB_IF_TYPE_SLIP:
 947         ret = JNI_TRUE;
 948         break;
 949       }
 950       free(ifRowP);
 951     }
 952   }
 953   return ret;
 954 }
 955 
 956 /*
 957  * Class:     java_net_NetworkInterface
 958  * Method:    isLoopback0
 959  * Signature: (Ljava/lang/String;I)Z
 960  */
 961 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0
 962     (JNIEnv *env, jclass cls, jstring name, jint index) {
 963   MIB_IFROW *ifRowP;
 964   jboolean ret = JNI_FALSE;
 965 
 966   if (os_supports_ipv6 && ipv6_available()) {
 967     return Java_java_net_NetworkInterface_isLoopback0_XP(env, cls, name, index);
 968   } else {
 969     ifRowP = getIF(index);
 970     if (ifRowP != NULL) {
 971       if (ifRowP->dwType == MIB_IF_TYPE_LOOPBACK)
 972         ret = JNI_TRUE;
 973       free(ifRowP);
 974     }
 975     return ret;
 976   }
 977 }
 978 
 979 /*
 980  * Class:     java_net_NetworkInterface
 981  * Method:    supportsMulticast0
 982  * Signature: (Ljava/lang/String;I)Z
 983  */
 984 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0
 985     (JNIEnv *env, jclass cls, jstring name, jint index) {
 986   MIB_IFROW *ifRowP;
 987   jboolean ret = JNI_TRUE;
 988 
 989   // Let's try to use the newer API (XP & 2003 only)
 990   if (GetAdaptersAddresses_fn != NULL) {
 991     ret = Java_java_net_NetworkInterface_supportsMulticast0_XP(env, cls,
 992                                                                name, index);
 993     return ret;
 994   }
 995   ifRowP = getIF(index);
 996   if (ifRowP != NULL) {
 997     if (ifRowP->dwType == MIB_IF_TYPE_LOOPBACK)
 998       ret = JNI_FALSE;
 999     free(ifRowP);
1000   }
1001   return ret;
1002 }
1003 
1004 /*
1005  * Class:     java_net_NetworkInterface
1006  * Method:    getMacAddr0
1007  * Signature: ([bLjava/lang/String;I)[b
1008  */
1009 JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0(JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) {
1010   jbyteArray ret = NULL;
1011   int len;
1012   MIB_IFROW *ifRowP;
1013 
1014   if (os_supports_ipv6 && ipv6_available()) {
1015     return Java_java_net_NetworkInterface_getMacAddr0_XP(env, class, name, index);
1016   } else {
1017     ifRowP = getIF(index);
1018     if (ifRowP != NULL) {
1019       switch(ifRowP->dwType) {
1020       case MIB_IF_TYPE_ETHERNET:
1021       case MIB_IF_TYPE_TOKENRING:
1022       case MIB_IF_TYPE_FDDI:
1023         len = ifRowP->dwPhysAddrLen;
1024         ret = (*env)->NewByteArray(env, len);
1025         if (!IS_NULL(ret)) {
1026           (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr);
1027         }
1028         break;
1029       }
1030       free(ifRowP);
1031     }
1032     return ret;
1033   }
1034 }
1035 
1036 /*
1037  * Class:       java_net_NetworkInterface
1038  * Method:      getMTU0
1039  * Signature:   ([bLjava/lang/String;I)I
1040  */
1041 JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0(JNIEnv *env, jclass class, jstring name, jint index) {
1042   jint ret = -1;
1043   MIB_IFROW *ifRowP;
1044 
1045   if (os_supports_ipv6 && ipv6_available()) {
1046     return Java_java_net_NetworkInterface_getMTU0_XP(env, class, name, index);
1047   } else {
1048     ifRowP = getIF(index);
1049     if (ifRowP != NULL) {
1050       ret = ifRowP->dwMtu;
1051       free(ifRowP);
1052     }
1053     return ret;
1054   }
1055 }