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