1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18#include "JNIHelp.h"
19#include "jni.h"
20#include "errno.h"
21
22#include <string.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <stdio.h>
26#include <sys/socket.h>
27#include <net/if.h>
28#include <netinet/in.h>
29#include <sys/ioctl.h>
30
31//--------------------------------------------------------------------
32// TODO copied from OSNetworkSystem. Might get into a separate .h file
33/**
34 * Throws an IOException with the given message.
35 */
36static void throwSocketException(JNIEnv *env, const char *message) {
37    jclass exClass = (*env)->FindClass(env, "java/net/SocketException");
38
39    if(exClass == NULL) {
40        LOGE("Unable to find class java/net/SocketException");
41    } else {
42        (*env)->ThrowNew(env, exClass, message);
43    }
44}
45
46
47/**
48 * Throws a NullPointerException.
49 */
50static void throwNullPointerException(JNIEnv *env) {
51    jclass exClass = (*env)->FindClass(env, "java/lang/NullPointerException");
52
53    if(exClass == NULL) {
54        LOGE("Unable to find class java/lang/NullPointerException");
55    } else {
56        (*env)->ThrowNew(env, exClass, NULL);
57    }
58}
59
60/**
61 * @name Socket Errors
62 * Error codes for socket operations
63 *
64 * @internal SOCKERR* range from -200 to -299 avoid overlap
65 */
66#define SOCKERR_BADSOCKET          -200 /* generic error */
67#define SOCKERR_NOTINITIALIZED     -201 /* socket library uninitialized */
68#define SOCKERR_BADAF              -202 /* bad address family */
69#define SOCKERR_BADPROTO           -203 /* bad protocol */
70#define SOCKERR_BADTYPE            -204 /* bad type */
71#define SOCKERR_SYSTEMBUSY         -205 /* system busy handling requests */
72#define SOCKERR_SYSTEMFULL         -206 /* too many sockets */
73#define SOCKERR_NOTCONNECTED       -207 /* socket is not connected */
74#define SOCKERR_INTERRUPTED        -208 /* the call was cancelled */
75#define SOCKERR_TIMEOUT            -209 /* the operation timed out */
76#define SOCKERR_CONNRESET          -210 /* the connection was reset */
77#define SOCKERR_WOULDBLOCK         -211 /* the socket is marked as nonblocking operation would block */
78#define SOCKERR_ADDRNOTAVAIL       -212 /* address not available */
79#define SOCKERR_ADDRINUSE          -213 /* address already in use */
80#define SOCKERR_NOTBOUND           -214 /* the socket is not bound */
81#define SOCKERR_UNKNOWNSOCKET      -215 /* resolution of fileDescriptor to socket failed */
82#define SOCKERR_INVALIDTIMEOUT     -216 /* the specified timeout is invalid */
83#define SOCKERR_FDSETFULL          -217 /* Unable to create an FDSET */
84#define SOCKERR_TIMEVALFULL        -218 /* Unable to create a TIMEVAL */
85#define SOCKERR_REMSOCKSHUTDOWN    -219 /* The remote socket has shutdown gracefully */
86#define SOCKERR_NOTLISTENING       -220 /* listen() was not invoked prior to accept() */
87#define SOCKERR_NOTSTREAMSOCK      -221 /* The socket does not support connection-oriented service */
88#define SOCKERR_ALREADYBOUND       -222 /* The socket is already bound to an address */
89#define SOCKERR_NBWITHLINGER       -223 /* The socket is marked non-blocking & SO_LINGER is non-zero */
90#define SOCKERR_ISCONNECTED        -224 /* The socket is already connected */
91#define SOCKERR_NOBUFFERS          -225 /* No buffer space is available */
92#define SOCKERR_HOSTNOTFOUND       -226 /* Authoritative Answer Host not found */
93#define SOCKERR_NODATA             -227 /* Valid name, no data record of requested type */
94#define SOCKERR_BOUNDORCONN        -228 /* The socket has not been bound or is already connected */
95#define SOCKERR_OPNOTSUPP          -229 /* The socket does not support the operation */
96#define SOCKERR_OPTUNSUPP          -230 /* The socket option is not supported */
97#define SOCKERR_OPTARGSINVALID     -231 /* The socket option arguments are invalid */
98#define SOCKERR_SOCKLEVELINVALID   -232 /* The socket level is invalid */
99#define SOCKERR_TIMEOUTFAILURE     -233
100#define SOCKERR_SOCKADDRALLOCFAIL  -234 /* Unable to allocate the sockaddr structure */
101#define SOCKERR_FDSET_SIZEBAD      -235 /* The calculated maximum size of the file descriptor set is bad */
102#define SOCKERR_UNKNOWNFLAG        -236 /* The flag is unknown */
103#define SOCKERR_MSGSIZE            -237 /* The datagram was too big to fit the specified buffer & was truncated. */
104#define SOCKERR_NORECOVERY         -238 /* The operation failed with no recovery possible */
105#define SOCKERR_ARGSINVALID        -239 /* The arguments are invalid */
106#define SOCKERR_BADDESC            -240 /* The socket argument is not a valid file descriptor */
107#define SOCKERR_NOTSOCK            -241 /* The socket argument is not a socket */
108#define SOCKERR_HOSTENTALLOCFAIL   -242 /* Unable to allocate the hostent structure */
109#define SOCKERR_TIMEVALALLOCFAIL   -243 /* Unable to allocate the timeval structure */
110#define SOCKERR_LINGERALLOCFAIL    -244 /* Unable to allocate the linger structure */
111#define SOCKERR_IPMREQALLOCFAIL    -245 /* Unable to allocate the ipmreq structure */
112#define SOCKERR_FDSETALLOCFAIL     -246 /* Unable to allocate the fdset structure */
113#define SOCKERR_OPFAILED           -247
114#define SOCKERR_VALUE_NULL         -248 /* The value indexed was NULL */
115#define SOCKERR_CONNECTION_REFUSED -249 /* connection was refused */
116#define SOCKERR_ENETUNREACH        -250 /* network is not reachable */
117#define SOCKERR_EACCES             -251 /* permissions do not allow action on socket */
118
119/**
120 * Answer the errorString corresponding to the errorNumber, if available.
121 * This function will answer a default error string, if the errorNumber is not
122 * recognized.
123 *
124 * This function will have to be reworked to handle internationalization properly, removing
125 * the explicit strings.
126 *
127 * @param anErrorNum    the error code to resolve to a human readable string
128 *
129 * @return  a human readable error string
130 */
131
132static char * netLookupErrorString(int anErrorNum) {
133    switch(anErrorNum) {
134        case SOCKERR_BADSOCKET:
135            return "Bad socket";
136        case SOCKERR_NOTINITIALIZED:
137            return "Socket library uninitialized";
138        case SOCKERR_BADAF:
139            return "Bad address family";
140        case SOCKERR_BADPROTO:
141            return "Bad protocol";
142        case SOCKERR_BADTYPE:
143            return "Bad type";
144        case SOCKERR_SYSTEMBUSY:
145            return "System busy handling requests";
146        case SOCKERR_SYSTEMFULL:
147            return "Too many sockets allocated";
148        case SOCKERR_NOTCONNECTED:
149            return "Socket is not connected";
150        case SOCKERR_INTERRUPTED:
151            return "The call was cancelled";
152        case SOCKERR_TIMEOUT:
153            return "The operation timed out";
154        case SOCKERR_CONNRESET:
155            return "The connection was reset";
156        case SOCKERR_WOULDBLOCK:
157            return "The socket is marked as nonblocking operation would block";
158        case SOCKERR_ADDRNOTAVAIL:
159            return "The address is not available";
160        case SOCKERR_ADDRINUSE:
161            return "The address is already in use";
162        case SOCKERR_NOTBOUND:
163            return "The socket is not bound";
164        case SOCKERR_UNKNOWNSOCKET:
165            return "Resolution of the FileDescriptor to socket failed";
166        case SOCKERR_INVALIDTIMEOUT:
167            return "The specified timeout is invalid";
168        case SOCKERR_FDSETFULL:
169            return "Unable to create an FDSET";
170        case SOCKERR_TIMEVALFULL:
171            return "Unable to create a TIMEVAL";
172        case SOCKERR_REMSOCKSHUTDOWN:
173            return "The remote socket has shutdown gracefully";
174        case SOCKERR_NOTLISTENING:
175            return "Listen() was not invoked prior to accept()";
176        case SOCKERR_NOTSTREAMSOCK:
177            return "The socket does not support connection-oriented service";
178        case SOCKERR_ALREADYBOUND:
179            return "The socket is already bound to an address";
180        case SOCKERR_NBWITHLINGER:
181            return "The socket is marked non-blocking & SO_LINGER is non-zero";
182        case SOCKERR_ISCONNECTED:
183            return "The socket is already connected";
184        case SOCKERR_NOBUFFERS:
185            return "No buffer space is available";
186        case SOCKERR_HOSTNOTFOUND:
187            return "Authoritative Answer Host not found";
188        case SOCKERR_NODATA:
189            return "Valid name, no data record of requested type";
190        case SOCKERR_BOUNDORCONN:
191            return "The socket has not been bound or is already connected";
192        case SOCKERR_OPNOTSUPP:
193            return "The socket does not support the operation";
194        case SOCKERR_OPTUNSUPP:
195            return "The socket option is not supported";
196        case SOCKERR_OPTARGSINVALID:
197            return "The socket option arguments are invalid";
198        case SOCKERR_SOCKLEVELINVALID:
199            return "The socket level is invalid";
200        case SOCKERR_TIMEOUTFAILURE:
201            return "The timeout operation failed";
202        case SOCKERR_SOCKADDRALLOCFAIL:
203            return "Failed to allocate address structure";
204        case SOCKERR_FDSET_SIZEBAD:
205            return "The calculated maximum size of the file descriptor set is bad";
206        case SOCKERR_UNKNOWNFLAG:
207            return "The flag is unknown";
208        case SOCKERR_MSGSIZE:
209            return "The datagram was too big to fit the specified buffer, so truncated";
210        case SOCKERR_NORECOVERY:
211            return "The operation failed with no recovery possible";
212        case SOCKERR_ARGSINVALID:
213            return "The arguments are invalid";
214        case SOCKERR_BADDESC:
215            return "The socket argument is not a valid file descriptor";
216        case SOCKERR_NOTSOCK:
217            return "The socket argument is not a socket";
218        case SOCKERR_HOSTENTALLOCFAIL:
219            return "Unable to allocate the hostent structure";
220        case SOCKERR_TIMEVALALLOCFAIL:
221            return "Unable to allocate the timeval structure";
222        case SOCKERR_LINGERALLOCFAIL:
223            return "Unable to allocate the linger structure";
224        case SOCKERR_IPMREQALLOCFAIL:
225            return "Unable to allocate the ipmreq structure";
226        case SOCKERR_FDSETALLOCFAIL:
227            return "Unable to allocate the fdset structure";
228        case SOCKERR_CONNECTION_REFUSED:
229            return "Connection refused";
230
231        default:
232            return "unkown error";
233    }
234}
235
236/**
237 * Converts a native address structure to a 4-byte array. Throws a
238 * NullPointerException or an IOException in case of error. This is
239 * signaled by a return value of -1. The normal return value is 0.
240 */
241static int structInToJavaAddress(
242        JNIEnv *env, struct in_addr *address, jbyteArray java_address) {
243
244    if(java_address == NULL) {
245        throwNullPointerException(env);
246        return -1;
247    }
248
249    if((*env)->GetArrayLength(env, java_address) != sizeof(address->s_addr)) {
250        jniThrowIOException(env, errno);
251        return -1;
252    }
253
254    jbyte *java_address_bytes;
255
256    java_address_bytes = (*env)->GetByteArrayElements(env, java_address, NULL);
257
258    memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr));
259
260    (*env)->ReleaseByteArrayElements(env, java_address, java_address_bytes, 0);
261
262    return 0;
263}
264
265static jobject structInToInetAddress(JNIEnv *env, struct in_addr *address) {
266    jbyteArray bytes;
267    int success;
268
269    bytes = (*env)->NewByteArray(env, 4);
270
271    if(bytes == NULL) {
272        return NULL;
273    }
274
275    success = structInToJavaAddress(env, address, bytes);
276
277    if(success < 0) {
278        return NULL;
279    }
280
281    jclass iaddrclass = (*env)->FindClass(env, "java/net/InetAddress");
282
283    if(iaddrclass == NULL) {
284        LOGE("Can't find java/net/InetAddress");
285        jniThrowException(env, "java/lang/ClassNotFoundException", "java.net.InetAddress");
286        return NULL;
287    }
288
289    jmethodID iaddrgetbyaddress = (*env)->GetStaticMethodID(env, iaddrclass, "getByAddress", "([B)Ljava/net/InetAddress;");
290
291    if(iaddrgetbyaddress == NULL) {
292        LOGE("Can't find method InetAddress.getByAddress(byte[] val)");
293        jniThrowException(env, "java/lang/NoSuchMethodError", "InetAddress.getByAddress(byte[] val)");
294        return NULL;
295    }
296
297    return (*env)->CallStaticObjectMethod(env, iaddrclass, iaddrgetbyaddress, bytes);
298}
299//--------------------------------------------------------------------
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322/* structure for returning either and IPV4 or IPV6 ip address */
323typedef struct ipAddress_struct {
324    union {
325        char bytes[sizeof(struct in_addr)];
326        struct in_addr inAddr;
327    } addr;
328    unsigned int length;
329    unsigned int  scope;
330} ipAddress_struct;
331
332/* structure for returning network interface information */
333typedef struct NetworkInterface_struct {
334    char *name;
335    char *displayName;
336    unsigned int  numberAddresses;
337    unsigned int  index;
338    struct ipAddress_struct *addresses;
339} NetworkInterface_struct;
340
341/* array of network interface structures */
342typedef struct NetworkInterfaceArray_struct {
343    unsigned int  length;
344    struct NetworkInterface_struct *elements;
345} NetworkInterfaceArray_struct;
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373/**
374 * Frees the memory allocated for the hyNetworkInterface_struct array passed in
375 *
376 * @param[in] portLibrary The port library.
377 * @param[in] handle Pointer to array of network interface structures to be freed
378 *
379 * @return 0 on success
380*/
381int sock_free_network_interface_struct (struct NetworkInterfaceArray_struct *array) {
382    unsigned int i = 0;
383
384    if((array != NULL) && (array->elements != NULL)) {
385
386        /* free the allocated memory in each of the structures */
387        for(i = 0; i < array->length; i++) {
388
389            /* free the name, displayName and addresses */
390            if(array->elements[i].name != NULL) {
391                free(array->elements[i].name);
392            }
393
394            if(array->elements[i].displayName != NULL) {
395                free(array->elements[i].displayName);
396            }
397
398            if(array->elements[i].addresses != NULL) {
399                free(array->elements[i].addresses);
400            }
401        }
402
403        /* now free the array itself */
404        free(array->elements);
405    }
406
407    return 0;
408}
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438/**
439 * Queries and returns the information for the network interfaces that are currently active within the system.
440 * Applications are responsible for freeing the memory returned via the handle.
441 *
442 * @param[in] portLibrary The port library.
443 * @param[in,out] array Pointer to structure with array of network interface entries
444 * @param[in] boolean which indicates if we should prefer the IPv4 stack or not
445 *
446 * @return The number of elements in handle on success, negatvie portable error code on failure.
447                               -WSANO_RECOVERY if system calls required to get the info fail, -WSAENOBUFS if memory allocation fails
448 * @note A return value of 0 indicates no interfaces exist
449*/
450int sockGetNetworkInterfaces(struct NetworkInterfaceArray_struct * array) {
451
452    struct NetworkInterface_struct *interfaces = NULL;
453    unsigned int nameLength = 0;
454    unsigned int currentAdapterIndex = 0;
455    unsigned int counter = 0;
456    unsigned int result = 0;
457    unsigned int numAddresses = 0;
458    unsigned int currentIPAddressIndex = 0;
459    unsigned int numAdapters = 0;
460    int err = 0;
461
462    struct ifconf ifc;
463    int len = 32 * sizeof(struct ifreq);
464    int socketP = 0;
465    unsigned int totalInterfaces = 0;
466    struct ifreq reqCopy;
467    unsigned int counter2 = 0;
468    char *lastName = NULL;
469
470    int ifconfCommand = SIOCGIFCONF;
471
472    /* this method is not guarranteed to return the IPV6 addresses.  Code is include so that if the platform returns IPV6 addresses
473       in reply to the SIOCGIFCONF they will be included.  Howerver, it is not guarranteed or even expected that many platforms will
474       include the IPV6 addresses.  For this reason there are other specific implementations that will return the IPV6 addresses */
475    /* first get the list of interfaces.  We do not know how long the buffer needs to be so we try with one that allows for
476       32 interfaces.  If this turns out not to be big enough then we expand the buffer to be able to support another
477       32 interfaces and try again.  We do this until the result indicates that the result fit into the buffer provided */
478    /* we need  socket to do the ioctl so create one */
479    socketP = socket(PF_INET, SOCK_DGRAM, 0);
480    if(socketP < 0) {
481        return socketP;
482    }
483    for(;;) {
484        char *data = (char *)malloc(len * sizeof(char));
485        if(data == NULL) {
486          close(socketP);
487          return SOCKERR_NOBUFFERS;
488        }
489        ifc.ifc_len = len;
490        ifc.ifc_buf = data;
491        errno = 0;
492        if(ioctl(socketP, ifconfCommand, &ifc) != 0) {
493          err = errno;
494          free(ifc.ifc_buf);
495          close(socketP);
496          return SOCKERR_NORECOVERY;
497        }
498        if(ifc.ifc_len < len)
499        break;
500        /* the returned data was likely truncated, expand the buffer and try again */
501        free(ifc.ifc_buf);
502        len += 32 * sizeof(struct ifreq);
503    }
504
505    /* get the number of distinct interfaces */
506    if(ifc.ifc_len != 0) {
507        totalInterfaces = ifc.ifc_len / sizeof(struct ifreq);
508    }
509    lastName = NULL;
510    for(counter = 0; counter < totalInterfaces; counter++) {
511        if((NULL == lastName) || (strncmp(lastName, ifc.ifc_req[counter].ifr_name, IFNAMSIZ) != 0)) {
512            /* make sure the interface is up */
513            reqCopy = ifc.ifc_req[counter];
514            ioctl(socketP, SIOCGIFFLAGS, &reqCopy);
515            if((reqCopy.ifr_flags) & (IFF_UP == IFF_UP)) {
516                numAdapters++;
517            }
518        }
519        lastName = ifc.ifc_req[counter].ifr_name;
520    }
521
522    /* now allocate the space for the hyNetworkInterface structs and fill it in */
523    interfaces = malloc(numAdapters * sizeof(NetworkInterface_struct));
524    if(NULL == interfaces) {
525        free(ifc.ifc_buf);
526        close(socketP);
527        return SOCKERR_NOBUFFERS;
528    }
529
530    /* initialize the structure so that we can free allocated if a failure occurs */
531    for(counter = 0; counter < numAdapters; counter++) {
532        interfaces[counter].name = NULL;
533        interfaces[counter].displayName = NULL;
534        interfaces[counter].addresses = NULL;
535    }
536
537    /* set up the return stucture */
538    array->elements = interfaces;
539    array->length = numAdapters;
540    lastName = NULL;
541    for(counter = 0; counter < totalInterfaces; counter++) {
542        /* make sure the interface is still up */
543        reqCopy = ifc.ifc_req[counter];
544        ioctl(socketP, SIOCGIFFLAGS, &reqCopy);
545        if((reqCopy.ifr_flags) & (IFF_UP == IFF_UP)) {
546            /* since this function can return multiple entries for the same name, only do it for the first one with any given name */
547            if((NULL == lastName) || (strncmp(lastName, ifc.ifc_req[counter].ifr_name, IFNAMSIZ) != 0)) {
548
549                /* get the index for the interface.  This is only truely necessary on platforms that support IPV6 */
550                interfaces[currentAdapterIndex].index = 0;
551                /* get the name and display name for the adapter */
552                /* there only seems to be one name so use it for both the name and the display name */
553                nameLength = strlen(ifc.ifc_req[counter].ifr_name);
554                interfaces[currentAdapterIndex].name = malloc(nameLength + 1);
555
556                if(NULL == interfaces[currentAdapterIndex].name) {
557                    free(ifc.ifc_buf);
558                    sock_free_network_interface_struct(array);
559                    close(socketP);
560                    return SOCKERR_NOBUFFERS;
561                }
562                strncpy(interfaces[currentAdapterIndex].name, ifc.ifc_req[counter].ifr_name, nameLength);
563                interfaces[currentAdapterIndex].name[nameLength] = 0;
564                nameLength = strlen(ifc.ifc_req[counter].ifr_name);
565                interfaces[currentAdapterIndex].displayName = malloc(nameLength + 1);
566                if(NULL == interfaces[currentAdapterIndex].displayName) {
567                    free(ifc.ifc_buf);
568                    sock_free_network_interface_struct(array);
569                    close(socketP);
570                    return SOCKERR_NOBUFFERS;
571                }
572                strncpy(interfaces[currentAdapterIndex].displayName, ifc.ifc_req[counter].ifr_name, nameLength);
573                interfaces[currentAdapterIndex].displayName[nameLength] = 0;
574
575                /* check how many addresses/aliases this adapter has.  aliases show up as adaptors with the same name */
576                numAddresses = 0;
577                for(counter2 = counter; counter2 < totalInterfaces; counter2++) {
578                    if(strncmp(ifc.ifc_req[counter].ifr_name, ifc.ifc_req[counter2].ifr_name, IFNAMSIZ) == 0) {
579                        if(ifc.ifc_req[counter2].ifr_addr.sa_family == AF_INET) {
580                            numAddresses++;
581                        }
582                    } else {
583                      break;
584                    }
585                }
586
587                /* allocate space for the addresses */
588                interfaces[currentAdapterIndex].numberAddresses = numAddresses;
589                interfaces[currentAdapterIndex].addresses = malloc(numAddresses * sizeof(ipAddress_struct));
590                if(NULL == interfaces[currentAdapterIndex].addresses) {
591                    free(ifc.ifc_buf);
592                    sock_free_network_interface_struct(array);
593                    close(socketP);
594                    return SOCKERR_NOBUFFERS;
595                }
596
597                /* now get the addresses */
598                currentIPAddressIndex = 0;
599                lastName = ifc.ifc_req[counter].ifr_name;
600
601                for(;;) {
602                    if(ifc.ifc_req[counter].ifr_addr.sa_family == AF_INET) {
603                        interfaces[currentAdapterIndex].addresses[currentIPAddressIndex].addr.inAddr.s_addr = ((struct sockaddr_in *) (&ifc.ifc_req[counter].ifr_addr))->sin_addr.s_addr;
604                        interfaces[currentAdapterIndex].addresses[currentIPAddressIndex].length = sizeof(struct in_addr);
605                        interfaces[currentAdapterIndex].addresses[currentIPAddressIndex].scope = 0;
606                        currentIPAddressIndex++;
607                    }
608
609                    /* we mean to increment the outside counter here as we want to skip the next entry as it is for the same interface
610                                          as we are currently working on */
611                    if((counter + 1 < totalInterfaces) && (strncmp(ifc.ifc_req[counter + 1].ifr_name, lastName, IFNAMSIZ) == 0)) {
612                        counter++;
613                    } else {
614                        break;
615                    }
616
617                }
618                currentAdapterIndex++;
619            }
620        }
621    }          /* for over all interfaces */
622    /* now an interface might have been taken down since we first counted them */
623    array->length = currentAdapterIndex;
624    /* free the memory now that we are done with it */
625    free(ifc.ifc_buf);
626    close(socketP);
627
628    return 0;
629}
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685/**
686 * Answer an array of NetworkInterface objects.  One for each network interface within the system
687 *
688 * @param      env     pointer to the JNI library
689 * @param      clazz   the class of the object invoking the JNI function
690 *
691 * @return                     an array of NetworkInterface objects of length 0 or more
692 */
693
694static jobjectArray getNetworkInterfacesImpl(JNIEnv * env, jclass clazz) {
695
696    /* variables to store network interfac edata returned by call to port library */
697    struct NetworkInterfaceArray_struct networkInterfaceArray;
698    int result = 0;
699
700    /* variables for class and method objects needed to create bridge to java */
701    jclass networkInterfaceClass = NULL;
702    jclass inetAddressClass = NULL;
703    jclass utilClass = NULL;
704    jmethodID methodID = NULL;
705    jmethodID utilMid = NULL;
706
707    /* JNI objects used to return values from native call */
708    jstring name = NULL;
709    jstring displayName = NULL;
710    jobjectArray addresses = NULL;
711    jobjectArray networkInterfaces = NULL;
712    jbyteArray bytearray = NULL;
713
714    /* jobjects used to build the object arrays returned */
715    jobject currentInterface = NULL;
716    jobject element = NULL;
717
718    /* misc variables needed for looping and determining inetAddress info */
719    unsigned int i = 0;
720    unsigned int j = 0;
721    unsigned int nameLength = 0;
722
723    /* get the classes and methods that we need for later calls */
724    networkInterfaceClass = (*env)->FindClass(env, "java/net/NetworkInterface");
725    if(networkInterfaceClass == NULL) {
726        throwSocketException(env, netLookupErrorString(SOCKERR_NORECOVERY));
727        return NULL;
728    }
729
730    inetAddressClass = (*env)->FindClass(env, "java/net/InetAddress");
731    if(inetAddressClass == NULL) {
732        throwSocketException(env, netLookupErrorString(SOCKERR_NORECOVERY));
733        return NULL;
734    }
735
736    methodID = (*env)->GetMethodID(env, networkInterfaceClass, "<init>",
737            "(Ljava/lang/String;Ljava/lang/String;[Ljava/net/InetAddress;I)V");
738    if(methodID == NULL) {
739        throwSocketException(env, netLookupErrorString(SOCKERR_NORECOVERY));
740        return NULL;
741    }
742
743    utilClass = (*env)->FindClass(env, "org/apache/harmony/luni/util/Util");
744    if(!utilClass) {
745        return NULL;
746    }
747
748    utilMid = ((*env)->GetStaticMethodID(env, utilClass, "toString",
749            "([BII)Ljava/lang/String;"));
750    if(!utilMid) {
751        return NULL;
752    }
753
754    result = sockGetNetworkInterfaces(&networkInterfaceArray);
755
756    if(result < 0) {
757        /* this means an error occured.  The value returned is the socket error that should be returned */
758        throwSocketException(env, netLookupErrorString(result));
759        return NULL;
760    }
761
762    /* now loop through the interfaces and extract the information to be returned */
763    for(j = 0; j < networkInterfaceArray.length; j++) {
764        /* set the name and display name and reset the addresses object array */
765        addresses = NULL;
766        name = NULL;
767        displayName = NULL;
768
769        if(networkInterfaceArray.elements[j].name != NULL) {
770            nameLength = strlen(networkInterfaceArray.elements[j].name);
771            bytearray = (*env)->NewByteArray(env, nameLength);
772            if(bytearray == NULL) {
773                /* NewByteArray should have thrown an exception */
774                return NULL;
775            }
776            (*env)->SetByteArrayRegion(env, bytearray, (jint) 0, nameLength,
777                    (jbyte *)networkInterfaceArray.elements[j].name);
778            name = (*env)->CallStaticObjectMethod(env, utilClass, utilMid,
779                    bytearray, (jint) 0, nameLength);
780            if((*env)->ExceptionCheck(env)) {
781                return NULL;
782            }
783        }
784
785        if(networkInterfaceArray.elements[j].displayName != NULL) {
786            nameLength = strlen(networkInterfaceArray.elements[j].displayName);
787            bytearray = (*env)->NewByteArray(env, nameLength);
788            if(bytearray == NULL) {
789                /* NewByteArray should have thrown an exception */
790                return NULL;
791            }
792            (*env)->SetByteArrayRegion(env, bytearray, (jint) 0, nameLength,
793                    (jbyte *)networkInterfaceArray.elements[j].displayName);
794            displayName = (*env)->CallStaticObjectMethod(env, utilClass, utilMid,
795                    bytearray, (jint) 0, nameLength);
796            if((*env)->ExceptionCheck(env)) {
797                return NULL;
798            }
799        }
800
801        /* generate the object with the inet addresses for the itnerface       */
802        for(i = 0; i < networkInterfaceArray.elements[j].numberAddresses; i++) {
803            element = structInToInetAddress(env, (struct in_addr *) &(networkInterfaceArray.elements[j].addresses[i].addr.inAddr));
804            if(i == 0) {
805                addresses = (*env)->NewObjectArray(env,
806                        networkInterfaceArray.elements[j].numberAddresses,
807                        inetAddressClass, element);
808            } else {
809                (*env)->SetObjectArrayElement(env, addresses, i, element);
810            }
811        }
812
813        /* now  create the NetworkInterface object for this interface and then add it it ot the arrary that will be returned */
814        currentInterface = (*env)->NewObject(env, networkInterfaceClass,
815                methodID, name, displayName, addresses,
816                networkInterfaceArray.elements[j].index);
817
818        if(j == 0) {
819            networkInterfaces = (*env)->NewObjectArray(env,
820                    networkInterfaceArray.length, networkInterfaceClass,
821                    currentInterface);
822        } else {
823            (*env)->SetObjectArrayElement(env, networkInterfaces, j, currentInterface);
824        }
825    }
826
827    /* free the memory for the interfaces struct and return the new NetworkInterface List */
828    sock_free_network_interface_struct(&networkInterfaceArray);
829    return networkInterfaces;
830}
831
832
833/*
834 * JNI registration
835 */
836static JNINativeMethod gMethods[] = {
837    /* name, signature, funcPtr */
838    { "getNetworkInterfacesImpl", "()[Ljava/net/NetworkInterface;", getNetworkInterfacesImpl }
839};
840int register_java_net_NetworkInterface(JNIEnv* env) {
841    return jniRegisterNativeMethods(env, "java/net/NetworkInterface",
842        gMethods, NELEM(gMethods));
843
844}
845