Loading services/java/com/android/server/connectivity/Vpn.java +69 −31 Original line number Diff line number Diff line Loading @@ -41,6 +41,9 @@ import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.server.ConnectivityService.VpnCallback; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charsets; import java.util.Arrays; Loading Loading @@ -192,10 +195,15 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } // Configure the interface. Abort if any of these steps fails. ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd( jniConfigure(config.mtu, config.addresses, config.routes)); ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); try { String interfaze = jniGetName(tun.getFd()); if (jniSetAddresses(interfaze, config.addresses) < 1) { throw new IllegalArgumentException("At least one address must be specified"); } if (config.routes != null) { jniSetRoutes(interfaze, config.routes); } if (mInterface != null && !mInterface.equals(interfaze)) { jniReset(mInterface); } Loading Loading @@ -279,8 +287,10 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } } private native int jniConfigure(int mtu, String addresses, String routes); private native int jniCreate(int mtu); private native String jniGetName(int tun); private native int jniSetAddresses(String interfaze, String addresses); private native int jniSetRoutes(String interfaze, String routes); private native void jniReset(String interfaze); private native int jniCheck(String interfaze); private native void jniProtect(int socket, String interfaze); Loading Loading @@ -323,7 +333,6 @@ public class Vpn extends INetworkManagementEventObserver.Stub { */ private class LegacyVpnRunner extends Thread { private static final String TAG = "LegacyVpnRunner"; private static final String NONE = "--"; private final VpnConfig mConfig; private final String[] mDaemons; Loading @@ -346,10 +355,10 @@ public class Vpn extends INetworkManagementEventObserver.Stub { public void exit() { // We assume that everything is reset after the daemons die. interrupt(); for (String daemon : mDaemons) { SystemProperties.set("ctl.stop", daemon); } interrupt(); } public LegacyVpnInfo getInfo() { Loading Loading @@ -380,7 +389,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { Thread.sleep(yield ? 200 : 1); } else { mInfo.state = LegacyVpnInfo.STATE_TIMEOUT; throw new IllegalStateException("time is up"); throw new IllegalStateException("Time is up"); } } Loading @@ -404,12 +413,11 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } } // Reset the properties. SystemProperties.set("vpn.dns", NONE); SystemProperties.set("vpn.via", NONE); while (!NONE.equals(SystemProperties.get("vpn.dns")) || !NONE.equals(SystemProperties.get("vpn.via"))) { checkpoint(true); // Clear the previous state. File state = new File("/data/misc/vpn/state"); state.delete(); if (state.exists()) { throw new IllegalStateException("Cannot delete the state"); } // Check if we need to restart any of the daemons. Loading Loading @@ -461,29 +469,34 @@ public class Vpn extends INetworkManagementEventObserver.Stub { OutputStream out = socket.getOutputStream(); for (String argument : arguments) { byte[] bytes = argument.getBytes(Charsets.UTF_8); if (bytes.length >= 0xFFFF) { throw new IllegalArgumentException("argument is too large"); if (bytes.length > 0xFFFF) { throw new IllegalArgumentException("Argument is too large"); } out.write(bytes.length >> 8); out.write(bytes.length); out.write(bytes); checkpoint(false); } // Send End-Of-Arguments. out.write(0xFF); out.write(0xFF); out.flush(); socket.shutdownOutput(); // Wait for End-of-File. InputStream in = socket.getInputStream(); while (true) { try { if (in.read() == -1) { break; } } catch (Exception e) { // ignore } checkpoint(true); } socket.close(); } // Now here is the beast from the old days. We check few // properties to figure out the current status. Ideally we // can read things back from the sockets and get rid of the // properties, but we have no time... while (NONE.equals(SystemProperties.get("vpn.dns")) || NONE.equals(SystemProperties.get("vpn.via"))) { // Wait for the daemons to create the new state. while (!state.exists()) { // Check if a running daemon is dead. for (int i = 0; i < mDaemons.length; ++i) { String daemon = mDaemons[i]; Loading @@ -495,20 +508,45 @@ public class Vpn extends INetworkManagementEventObserver.Stub { checkpoint(true); } // Now we are connected. Get the interface. mConfig.interfaze = SystemProperties.get("vpn.via"); // Now we are connected. Read and parse the new state. byte[] buffer = new byte[(int) state.length()]; if (new FileInputStream(state).read(buffer) != buffer.length) { throw new IllegalStateException("Cannot read the state"); } String[] parameters = new String(buffer, Charsets.UTF_8).split("\n", -1); if (parameters.length != 6) { throw new IllegalStateException("Cannot parse the state"); } // Set the interface and the addresses in the config. mConfig.interfaze = parameters[0].trim(); mConfig.addresses = parameters[1].trim(); // Set the routes if they are not set in the config. if (mConfig.routes == null || mConfig.routes.isEmpty()) { mConfig.routes = parameters[2].trim(); } // Get the DNS servers if they are not set in config. // Set the DNS servers if they are not set in the config. if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) { String dnsServers = SystemProperties.get("vpn.dns").trim(); String dnsServers = parameters[3].trim(); if (!dnsServers.isEmpty()) { mConfig.dnsServers = Arrays.asList(dnsServers.split(" ")); } } // TODO: support search domains from ISAKMP mode config. // Set the search domains if they are not set in the config. if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) { String searchDomains = parameters[4].trim(); if (!searchDomains.isEmpty()) { mConfig.searchDomains = Arrays.asList(searchDomains.split(" ")); } } // Set the routes. jniSetRoutes(mConfig.interfaze, mConfig.routes); // The final step must be synchronized. // Here is the last step and it must be done synchronously. synchronized (Vpn.this) { // Check if the thread is interrupted while we are waiting. checkpoint(false); Loading services/jni/com_android_server_connectivity_Vpn.cpp +104 −62 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ #define LOG_TAG "VpnJni" #include <cutils/log.h> #include <cutils/properties.h> #include <stdio.h> #include <string.h> Loading Loading @@ -54,7 +53,7 @@ static inline in_addr_t *as_in_addr(sockaddr *sa) { #define SYSTEM_ERROR -1 #define BAD_ARGUMENT -2 static int create_interface(char *name, int *index, int mtu) static int create_interface(int mtu) { int tun = open("/dev/tun", O_RDWR | O_NONBLOCK); Loading Loading @@ -82,14 +81,6 @@ static int create_interface(char *name, int *index, int mtu) goto error; } // Get interface index. if (ioctl(inet4, SIOGIFINDEX, &ifr4)) { LOGE("Cannot get index of %s: %s", ifr4.ifr_name, strerror(errno)); goto error; } strncpy(name, ifr4.ifr_name, IFNAMSIZ); *index = ifr4.ifr_ifindex; return tun; error: Loading @@ -97,12 +88,40 @@ error: return SYSTEM_ERROR; } static int set_addresses(const char *name, int index, const char *addresses) static int get_interface_name(char *name, int tun) { ifreq ifr4; if (ioctl(tun, TUNGETIFF, &ifr4)) { LOGE("Cannot get interface name: %s", strerror(errno)); return SYSTEM_ERROR; } strncpy(name, ifr4.ifr_name, IFNAMSIZ); return 0; } static int get_interface_index(const char *name) { ifreq ifr4; strncpy(ifr4.ifr_name, name, IFNAMSIZ); if (ioctl(inet4, SIOGIFINDEX, &ifr4)) { LOGE("Cannot get index of %s: %s", name, strerror(errno)); return SYSTEM_ERROR; } return ifr4.ifr_ifindex; } static int set_addresses(const char *name, const char *addresses) { int index = get_interface_index(name); if (index < 0) { return index; } ifreq ifr4; memset(&ifr4, 0, sizeof(ifr4)); strncpy(ifr4.ifr_name, name, IFNAMSIZ); ifr4.ifr_addr.sa_family = AF_INET; ifr4.ifr_netmask.sa_family = AF_INET; in6_ifreq ifr6; memset(&ifr6, 0, sizeof(ifr6)); Loading Loading @@ -146,7 +165,7 @@ static int set_addresses(const char *name, int index, const char *addresses) } in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0; *as_in_addr(&ifr4.ifr_addr) = htonl(mask); *as_in_addr(&ifr4.ifr_netmask) = htonl(mask); if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) { count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; break; Loading @@ -168,8 +187,13 @@ static int set_addresses(const char *name, int index, const char *addresses) return count; } static int set_routes(const char *name, int index, const char *routes) static int set_routes(const char *name, const char *routes) { int index = get_interface_index(name); if (index < 0) { return index; } rtentry rt4; memset(&rt4, 0, sizeof(rt4)); rt4.rt_dev = (char *)name; Loading Loading @@ -253,17 +277,6 @@ static int set_routes(const char *name, int index, const char *routes) return count; } static int get_interface_name(char *name, int tun) { ifreq ifr4; if (ioctl(tun, TUNGETIFF, &ifr4)) { LOGE("Cannot get interface name: %s", strerror(errno)); return SYSTEM_ERROR; } strncpy(name, ifr4.ifr_name, IFNAMSIZ); return 0; } static int reset_interface(const char *name) { ifreq ifr4; Loading Loading @@ -309,63 +322,90 @@ static void throwException(JNIEnv *env, int error, const char *message) } } static jint configure(JNIEnv *env, jobject thiz, jint mtu, jstring jAddresses, jstring jRoutes) static jint create(JNIEnv *env, jobject thiz, jint mtu) { char name[IFNAMSIZ]; int index; int tun = create_interface(name, &index, mtu); int tun = create_interface(mtu); if (tun < 0) { throwException(env, tun, "Cannot create interface"); return -1; } return tun; } static jstring getName(JNIEnv *env, jobject thiz, jint tun) { char name[IFNAMSIZ]; if (get_interface_name(name, tun) < 0) { throwException(env, SYSTEM_ERROR, "Cannot get interface name"); return NULL; } return env->NewStringUTF(name); } static jint setAddresses(JNIEnv *env, jobject thiz, jstring jName, jstring jAddresses) { const char *name = NULL; const char *addresses = NULL; const char *routes = NULL; int count; int count = -1; // At least one address must be set. name = jName ? env->GetStringUTFChars(jName, NULL) : NULL; if (!name) { jniThrowNullPointerException(env, "name"); goto error; } addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL; if (!addresses) { jniThrowNullPointerException(env, "address"); jniThrowNullPointerException(env, "addresses"); goto error; } count = set_addresses(name, index, addresses); env->ReleaseStringUTFChars(jAddresses, addresses); if (count <= 0) { count = set_addresses(name, addresses); if (count < 0) { throwException(env, count, "Cannot set address"); goto error; count = -1; } LOGD("Configured %d address(es) on %s", count, name); // On the contrary, routes are optional. error: if (name) { env->ReleaseStringUTFChars(jName, name); } if (addresses) { env->ReleaseStringUTFChars(jAddresses, addresses); } return count; } static jint setRoutes(JNIEnv *env, jobject thiz, jstring jName, jstring jRoutes) { const char *name = NULL; const char *routes = NULL; int count = -1; name = jName ? env->GetStringUTFChars(jName, NULL) : NULL; if (!name) { jniThrowNullPointerException(env, "name"); goto error; } routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL; if (routes) { count = set_routes(name, index, routes); env->ReleaseStringUTFChars(jRoutes, routes); if (count < 0) { throwException(env, count, "Cannot set route"); if (!routes) { jniThrowNullPointerException(env, "routes"); goto error; } LOGD("Configured %d route(s) on %s", count, name); count = set_routes(name, routes); if (count < 0) { throwException(env, count, "Cannot set route"); count = -1; } return tun; error: close(tun); LOGD("%s is destroyed", name); return -1; if (name) { env->ReleaseStringUTFChars(jName, name); } static jstring getName(JNIEnv *env, jobject thiz, jint tun) { char name[IFNAMSIZ]; if (get_interface_name(name, tun) < 0) { throwException(env, SYSTEM_ERROR, "Cannot get interface name"); return NULL; if (routes) { env->ReleaseStringUTFChars(jRoutes, routes); } return env->NewStringUTF(name); return count; } static void reset(JNIEnv *env, jobject thiz, jstring jName) Loading Loading @@ -409,8 +449,10 @@ static void protect(JNIEnv *env, jobject thiz, jint socket, jstring jName) //------------------------------------------------------------------------------ static JNINativeMethod gMethods[] = { {"jniConfigure", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)configure}, {"jniCreate", "(I)I", (void *)create}, {"jniGetName", "(I)Ljava/lang/String;", (void *)getName}, {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses}, {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes}, {"jniReset", "(Ljava/lang/String;)V", (void *)reset}, {"jniCheck", "(Ljava/lang/String;)I", (void *)check}, {"jniProtect", "(ILjava/lang/String;)V", (void *)protect}, Loading Loading
services/java/com/android/server/connectivity/Vpn.java +69 −31 Original line number Diff line number Diff line Loading @@ -41,6 +41,9 @@ import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.server.ConnectivityService.VpnCallback; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charsets; import java.util.Arrays; Loading Loading @@ -192,10 +195,15 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } // Configure the interface. Abort if any of these steps fails. ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd( jniConfigure(config.mtu, config.addresses, config.routes)); ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); try { String interfaze = jniGetName(tun.getFd()); if (jniSetAddresses(interfaze, config.addresses) < 1) { throw new IllegalArgumentException("At least one address must be specified"); } if (config.routes != null) { jniSetRoutes(interfaze, config.routes); } if (mInterface != null && !mInterface.equals(interfaze)) { jniReset(mInterface); } Loading Loading @@ -279,8 +287,10 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } } private native int jniConfigure(int mtu, String addresses, String routes); private native int jniCreate(int mtu); private native String jniGetName(int tun); private native int jniSetAddresses(String interfaze, String addresses); private native int jniSetRoutes(String interfaze, String routes); private native void jniReset(String interfaze); private native int jniCheck(String interfaze); private native void jniProtect(int socket, String interfaze); Loading Loading @@ -323,7 +333,6 @@ public class Vpn extends INetworkManagementEventObserver.Stub { */ private class LegacyVpnRunner extends Thread { private static final String TAG = "LegacyVpnRunner"; private static final String NONE = "--"; private final VpnConfig mConfig; private final String[] mDaemons; Loading @@ -346,10 +355,10 @@ public class Vpn extends INetworkManagementEventObserver.Stub { public void exit() { // We assume that everything is reset after the daemons die. interrupt(); for (String daemon : mDaemons) { SystemProperties.set("ctl.stop", daemon); } interrupt(); } public LegacyVpnInfo getInfo() { Loading Loading @@ -380,7 +389,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { Thread.sleep(yield ? 200 : 1); } else { mInfo.state = LegacyVpnInfo.STATE_TIMEOUT; throw new IllegalStateException("time is up"); throw new IllegalStateException("Time is up"); } } Loading @@ -404,12 +413,11 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } } // Reset the properties. SystemProperties.set("vpn.dns", NONE); SystemProperties.set("vpn.via", NONE); while (!NONE.equals(SystemProperties.get("vpn.dns")) || !NONE.equals(SystemProperties.get("vpn.via"))) { checkpoint(true); // Clear the previous state. File state = new File("/data/misc/vpn/state"); state.delete(); if (state.exists()) { throw new IllegalStateException("Cannot delete the state"); } // Check if we need to restart any of the daemons. Loading Loading @@ -461,29 +469,34 @@ public class Vpn extends INetworkManagementEventObserver.Stub { OutputStream out = socket.getOutputStream(); for (String argument : arguments) { byte[] bytes = argument.getBytes(Charsets.UTF_8); if (bytes.length >= 0xFFFF) { throw new IllegalArgumentException("argument is too large"); if (bytes.length > 0xFFFF) { throw new IllegalArgumentException("Argument is too large"); } out.write(bytes.length >> 8); out.write(bytes.length); out.write(bytes); checkpoint(false); } // Send End-Of-Arguments. out.write(0xFF); out.write(0xFF); out.flush(); socket.shutdownOutput(); // Wait for End-of-File. InputStream in = socket.getInputStream(); while (true) { try { if (in.read() == -1) { break; } } catch (Exception e) { // ignore } checkpoint(true); } socket.close(); } // Now here is the beast from the old days. We check few // properties to figure out the current status. Ideally we // can read things back from the sockets and get rid of the // properties, but we have no time... while (NONE.equals(SystemProperties.get("vpn.dns")) || NONE.equals(SystemProperties.get("vpn.via"))) { // Wait for the daemons to create the new state. while (!state.exists()) { // Check if a running daemon is dead. for (int i = 0; i < mDaemons.length; ++i) { String daemon = mDaemons[i]; Loading @@ -495,20 +508,45 @@ public class Vpn extends INetworkManagementEventObserver.Stub { checkpoint(true); } // Now we are connected. Get the interface. mConfig.interfaze = SystemProperties.get("vpn.via"); // Now we are connected. Read and parse the new state. byte[] buffer = new byte[(int) state.length()]; if (new FileInputStream(state).read(buffer) != buffer.length) { throw new IllegalStateException("Cannot read the state"); } String[] parameters = new String(buffer, Charsets.UTF_8).split("\n", -1); if (parameters.length != 6) { throw new IllegalStateException("Cannot parse the state"); } // Set the interface and the addresses in the config. mConfig.interfaze = parameters[0].trim(); mConfig.addresses = parameters[1].trim(); // Set the routes if they are not set in the config. if (mConfig.routes == null || mConfig.routes.isEmpty()) { mConfig.routes = parameters[2].trim(); } // Get the DNS servers if they are not set in config. // Set the DNS servers if they are not set in the config. if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) { String dnsServers = SystemProperties.get("vpn.dns").trim(); String dnsServers = parameters[3].trim(); if (!dnsServers.isEmpty()) { mConfig.dnsServers = Arrays.asList(dnsServers.split(" ")); } } // TODO: support search domains from ISAKMP mode config. // Set the search domains if they are not set in the config. if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) { String searchDomains = parameters[4].trim(); if (!searchDomains.isEmpty()) { mConfig.searchDomains = Arrays.asList(searchDomains.split(" ")); } } // Set the routes. jniSetRoutes(mConfig.interfaze, mConfig.routes); // The final step must be synchronized. // Here is the last step and it must be done synchronously. synchronized (Vpn.this) { // Check if the thread is interrupted while we are waiting. checkpoint(false); Loading
services/jni/com_android_server_connectivity_Vpn.cpp +104 −62 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ #define LOG_TAG "VpnJni" #include <cutils/log.h> #include <cutils/properties.h> #include <stdio.h> #include <string.h> Loading Loading @@ -54,7 +53,7 @@ static inline in_addr_t *as_in_addr(sockaddr *sa) { #define SYSTEM_ERROR -1 #define BAD_ARGUMENT -2 static int create_interface(char *name, int *index, int mtu) static int create_interface(int mtu) { int tun = open("/dev/tun", O_RDWR | O_NONBLOCK); Loading Loading @@ -82,14 +81,6 @@ static int create_interface(char *name, int *index, int mtu) goto error; } // Get interface index. if (ioctl(inet4, SIOGIFINDEX, &ifr4)) { LOGE("Cannot get index of %s: %s", ifr4.ifr_name, strerror(errno)); goto error; } strncpy(name, ifr4.ifr_name, IFNAMSIZ); *index = ifr4.ifr_ifindex; return tun; error: Loading @@ -97,12 +88,40 @@ error: return SYSTEM_ERROR; } static int set_addresses(const char *name, int index, const char *addresses) static int get_interface_name(char *name, int tun) { ifreq ifr4; if (ioctl(tun, TUNGETIFF, &ifr4)) { LOGE("Cannot get interface name: %s", strerror(errno)); return SYSTEM_ERROR; } strncpy(name, ifr4.ifr_name, IFNAMSIZ); return 0; } static int get_interface_index(const char *name) { ifreq ifr4; strncpy(ifr4.ifr_name, name, IFNAMSIZ); if (ioctl(inet4, SIOGIFINDEX, &ifr4)) { LOGE("Cannot get index of %s: %s", name, strerror(errno)); return SYSTEM_ERROR; } return ifr4.ifr_ifindex; } static int set_addresses(const char *name, const char *addresses) { int index = get_interface_index(name); if (index < 0) { return index; } ifreq ifr4; memset(&ifr4, 0, sizeof(ifr4)); strncpy(ifr4.ifr_name, name, IFNAMSIZ); ifr4.ifr_addr.sa_family = AF_INET; ifr4.ifr_netmask.sa_family = AF_INET; in6_ifreq ifr6; memset(&ifr6, 0, sizeof(ifr6)); Loading Loading @@ -146,7 +165,7 @@ static int set_addresses(const char *name, int index, const char *addresses) } in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0; *as_in_addr(&ifr4.ifr_addr) = htonl(mask); *as_in_addr(&ifr4.ifr_netmask) = htonl(mask); if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) { count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; break; Loading @@ -168,8 +187,13 @@ static int set_addresses(const char *name, int index, const char *addresses) return count; } static int set_routes(const char *name, int index, const char *routes) static int set_routes(const char *name, const char *routes) { int index = get_interface_index(name); if (index < 0) { return index; } rtentry rt4; memset(&rt4, 0, sizeof(rt4)); rt4.rt_dev = (char *)name; Loading Loading @@ -253,17 +277,6 @@ static int set_routes(const char *name, int index, const char *routes) return count; } static int get_interface_name(char *name, int tun) { ifreq ifr4; if (ioctl(tun, TUNGETIFF, &ifr4)) { LOGE("Cannot get interface name: %s", strerror(errno)); return SYSTEM_ERROR; } strncpy(name, ifr4.ifr_name, IFNAMSIZ); return 0; } static int reset_interface(const char *name) { ifreq ifr4; Loading Loading @@ -309,63 +322,90 @@ static void throwException(JNIEnv *env, int error, const char *message) } } static jint configure(JNIEnv *env, jobject thiz, jint mtu, jstring jAddresses, jstring jRoutes) static jint create(JNIEnv *env, jobject thiz, jint mtu) { char name[IFNAMSIZ]; int index; int tun = create_interface(name, &index, mtu); int tun = create_interface(mtu); if (tun < 0) { throwException(env, tun, "Cannot create interface"); return -1; } return tun; } static jstring getName(JNIEnv *env, jobject thiz, jint tun) { char name[IFNAMSIZ]; if (get_interface_name(name, tun) < 0) { throwException(env, SYSTEM_ERROR, "Cannot get interface name"); return NULL; } return env->NewStringUTF(name); } static jint setAddresses(JNIEnv *env, jobject thiz, jstring jName, jstring jAddresses) { const char *name = NULL; const char *addresses = NULL; const char *routes = NULL; int count; int count = -1; // At least one address must be set. name = jName ? env->GetStringUTFChars(jName, NULL) : NULL; if (!name) { jniThrowNullPointerException(env, "name"); goto error; } addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL; if (!addresses) { jniThrowNullPointerException(env, "address"); jniThrowNullPointerException(env, "addresses"); goto error; } count = set_addresses(name, index, addresses); env->ReleaseStringUTFChars(jAddresses, addresses); if (count <= 0) { count = set_addresses(name, addresses); if (count < 0) { throwException(env, count, "Cannot set address"); goto error; count = -1; } LOGD("Configured %d address(es) on %s", count, name); // On the contrary, routes are optional. error: if (name) { env->ReleaseStringUTFChars(jName, name); } if (addresses) { env->ReleaseStringUTFChars(jAddresses, addresses); } return count; } static jint setRoutes(JNIEnv *env, jobject thiz, jstring jName, jstring jRoutes) { const char *name = NULL; const char *routes = NULL; int count = -1; name = jName ? env->GetStringUTFChars(jName, NULL) : NULL; if (!name) { jniThrowNullPointerException(env, "name"); goto error; } routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL; if (routes) { count = set_routes(name, index, routes); env->ReleaseStringUTFChars(jRoutes, routes); if (count < 0) { throwException(env, count, "Cannot set route"); if (!routes) { jniThrowNullPointerException(env, "routes"); goto error; } LOGD("Configured %d route(s) on %s", count, name); count = set_routes(name, routes); if (count < 0) { throwException(env, count, "Cannot set route"); count = -1; } return tun; error: close(tun); LOGD("%s is destroyed", name); return -1; if (name) { env->ReleaseStringUTFChars(jName, name); } static jstring getName(JNIEnv *env, jobject thiz, jint tun) { char name[IFNAMSIZ]; if (get_interface_name(name, tun) < 0) { throwException(env, SYSTEM_ERROR, "Cannot get interface name"); return NULL; if (routes) { env->ReleaseStringUTFChars(jRoutes, routes); } return env->NewStringUTF(name); return count; } static void reset(JNIEnv *env, jobject thiz, jstring jName) Loading Loading @@ -409,8 +449,10 @@ static void protect(JNIEnv *env, jobject thiz, jint socket, jstring jName) //------------------------------------------------------------------------------ static JNINativeMethod gMethods[] = { {"jniConfigure", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)configure}, {"jniCreate", "(I)I", (void *)create}, {"jniGetName", "(I)Ljava/lang/String;", (void *)getName}, {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses}, {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes}, {"jniReset", "(Ljava/lang/String;)V", (void *)reset}, {"jniCheck", "(Ljava/lang/String;)I", (void *)check}, {"jniProtect", "(ILjava/lang/String;)V", (void *)protect}, Loading