Home | History | Annotate | Download | only in native
      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 "AndroidSystemNatives.h"
     19 #include "JNIHelp.h"
     20 #include "jni.h"
     21 
     22 #include <errno.h>
     23 #include <netinet/in.h>
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <string.h>
     27 #include <sys/ioctl.h>
     28 #include <sys/socket.h>
     29 #include <unistd.h>
     30 
     31 #include <net/if.h> // Note: Can't appear before <sys/socket.h> on OS X.
     32 
     33 #ifdef ANDROID
     34 #include "ifaddrs-android.h"
     35 #else
     36 #include <ifaddrs.h>
     37 #endif
     38 
     39 // Ensures we always call freeifaddrs(3) to clean up after getifaddrs(3).
     40 class ScopedInterfaceAddresses {
     41 public:
     42     ScopedInterfaceAddresses() : list(NULL) {
     43     }
     44 
     45     bool init() {
     46         int rc = getifaddrs(&list);
     47         return (rc != -1);
     48     }
     49 
     50     ~ScopedInterfaceAddresses() {
     51         freeifaddrs(list);
     52     }
     53 
     54     ifaddrs* list;
     55 };
     56 
     57 // TODO: add a header file for shared utilities like this.
     58 extern jobject socketAddressToInetAddress(JNIEnv* env, sockaddr_storage* sockAddress);
     59 
     60 // TODO(enh): move to JNIHelp.h
     61 static void jniThrowSocketException(JNIEnv* env) {
     62     char buf[BUFSIZ];
     63     jniThrowException(env, "java/net/SocketException",
     64             jniStrError(errno, buf, sizeof(buf)));
     65 }
     66 
     67 static jobject makeInterfaceAddress(JNIEnv* env, jint interfaceIndex, const char* name, sockaddr_storage* ss) {
     68     jclass clazz = env->FindClass("java/net/InterfaceAddress");
     69     if (clazz == NULL) {
     70         return NULL;
     71     }
     72     jmethodID constructor = env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;Ljava/net/InetAddress;)V");
     73     if (constructor == NULL) {
     74         return NULL;
     75     }
     76     jobject javaName = env->NewStringUTF(name);
     77     if (javaName == NULL) {
     78         return NULL;
     79     }
     80     jobject javaAddress = socketAddressToInetAddress(env, ss);
     81     if (javaAddress == NULL) {
     82         return NULL;
     83     }
     84     return env->NewObject(clazz, constructor, interfaceIndex, javaName, javaAddress);
     85 }
     86 
     87 static jobjectArray getInterfaceAddresses(JNIEnv* env, jclass) {
     88     // Get the list of interface addresses.
     89     ScopedInterfaceAddresses addresses;
     90     if (!addresses.init()) {
     91         jniThrowSocketException(env);
     92         return NULL;
     93     }
     94 
     95     // Count how many there are.
     96     int interfaceAddressCount = 0;
     97     for (ifaddrs* ifa = addresses.list; ifa != NULL; ifa = ifa->ifa_next) {
     98         ++interfaceAddressCount;
     99     }
    100 
    101     // Build the InterfaceAddress[]...
    102     jclass interfaceAddressClass = env->FindClass("java/net/InterfaceAddress");
    103     if (interfaceAddressClass == NULL) {
    104         return NULL;
    105     }
    106     jobjectArray result = env->NewObjectArray(interfaceAddressCount, interfaceAddressClass, NULL);
    107     if (result == NULL) {
    108         return NULL;
    109     }
    110 
    111     // And fill it in...
    112     int arrayIndex = 0;
    113     for (ifaddrs* ifa = addresses.list; ifa != NULL; ifa = ifa->ifa_next) {
    114         // We're only interested in IP addresses.
    115         int family = ifa->ifa_addr->sa_family;
    116         if (family != AF_INET && family != AF_INET6) {
    117             continue;
    118         }
    119         // Until we implement Java 6's NetworkInterface.isUp,
    120         // we only want interfaces that are up.
    121         if ((ifa->ifa_flags & IFF_UP) == 0) {
    122             continue;
    123         }
    124         // Find the interface's index, and skip this address if
    125         // the interface has gone away.
    126         int interfaceIndex = if_nametoindex(ifa->ifa_name);
    127         if (interfaceIndex == 0) {
    128             continue;
    129         }
    130         // Make a new InterfaceAddress, and insert it into the array.
    131         sockaddr_storage* ss = reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr);
    132         jobject element = makeInterfaceAddress(env, interfaceIndex, ifa->ifa_name, ss);
    133         if (element == NULL) {
    134             return NULL;
    135         }
    136         env->SetObjectArrayElement(result, arrayIndex, element);
    137         if (env->ExceptionCheck()) {
    138             return NULL;
    139         }
    140         ++arrayIndex;
    141     }
    142     return result;
    143 }
    144 
    145 static JNINativeMethod gMethods[] = {
    146     /* name, signature, funcPtr */
    147     { "getInterfaceAddresses", "()[Ljava/net/InterfaceAddress;", (void*) getInterfaceAddresses },
    148 };
    149 int register_java_net_NetworkInterface(JNIEnv* env) {
    150     return jniRegisterNativeMethods(env, "java/net/NetworkInterface",
    151             gMethods, NELEM(gMethods));
    152 }
    153