summaryrefslogtreecommitdiffstats
path: root/packages/VpnServices/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/VpnServices/src')
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java64
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java3
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java4
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java1
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/VpnConnectingError.java35
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/VpnService.java144
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java23
7 files changed, 157 insertions, 117 deletions
diff --git a/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java b/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java
index 7dd9d9e..e4c070f 100644
--- a/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java
+++ b/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java
@@ -18,6 +18,7 @@ package com.android.server.vpn;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
+import android.net.vpn.VpnManager;
import android.os.SystemProperties;
import android.util.Log;
@@ -48,6 +49,9 @@ public class AndroidServiceProxy extends ProcessProxy {
private static final int END_OF_ARGUMENTS = 255;
+ private static final int STOP_SERVICE = -1;
+ private static final int AUTH_ERROR_CODE = 51;
+
private String mServiceName;
private String mSocketName;
private LocalSocket mKeepaliveSocket;
@@ -72,14 +76,22 @@ public class AndroidServiceProxy extends ProcessProxy {
@Override
public synchronized void stop() {
- if (isRunning()) setResultAndCloseControlSocket(-1);
+ if (isRunning()) {
+ try {
+ setResultAndCloseControlSocket(STOP_SERVICE);
+ } catch (IOException e) {
+ // should not occur
+ throw new RuntimeException(e);
+ }
+ }
+ Log.d(mTag, "----- Stop: " + mServiceName);
SystemProperties.set(SVC_STOP_CMD, mServiceName);
}
/**
* Sends a command with arguments to the service through the control socket.
*/
- public void sendCommand(String ...args) throws IOException {
+ public synchronized void sendCommand(String ...args) throws IOException {
OutputStream out = getControlSocketOutput();
for (String arg : args) outputString(out, arg);
out.write(END_OF_ARGUMENTS);
@@ -94,7 +106,14 @@ public class AndroidServiceProxy extends ProcessProxy {
@Override
protected void performTask() throws IOException {
String svc = mServiceName;
- Log.d(mTag, "+++++ Execute: " + svc);
+ Log.d(mTag, "----- Stop the daemon just in case: " + mServiceName);
+ SystemProperties.set(SVC_STOP_CMD, mServiceName);
+ if (!blockUntil(SVC_STATE_STOPPED, 5)) {
+ throw new IOException("cannot start service anew: " + svc
+ + ", it is still running");
+ }
+
+ Log.d(mTag, "+++++ Start: " + svc);
SystemProperties.set(SVC_START_CMD, svc);
boolean success = blockUntil(SVC_STATE_RUNNING, WAITING_TIME);
@@ -114,30 +133,22 @@ public class AndroidServiceProxy extends ProcessProxy {
InputStream in = s.getInputStream();
int data = in.read();
if (data >= 0) {
- Log.d(mTag, "got data from keepalive socket: " + data);
-
- if (data == 0) {
- // re-establish the connection:
- // synchronized here so that checkSocketResult()
- // returns when new mKeepaliveSocket is available for
- // next cmd
- synchronized (this) {
- setResultAndCloseControlSocket((byte) data);
- s = mKeepaliveSocket = createServiceSocket();
- }
- } else {
- // keep the socket
- setSocketResult(data);
- }
+ Log.d(mTag, "got data from control socket: " + data);
+
+ setSocketResult(data);
} else {
// service is gone
if (mControlSocketInUse) setSocketResult(-1);
break;
}
}
- Log.d(mTag, "keepalive connection closed");
+ Log.d(mTag, "control connection closed");
} catch (IOException e) {
- Log.d(mTag, "keepalive socket broken: " + e.getMessage());
+ if (e instanceof VpnConnectingError) {
+ throw e;
+ } else {
+ Log.d(mTag, "control socket broken: " + e.getMessage());
+ }
}
// Wait 5 seconds for the service to exit
@@ -179,7 +190,7 @@ public class AndroidServiceProxy extends ProcessProxy {
}
}
- private synchronized void checkSocketResult() throws IOException {
+ private void checkSocketResult() throws IOException {
try {
// will be notified when the result comes back from service
if (mSocketResult == null) wait();
@@ -194,14 +205,21 @@ public class AndroidServiceProxy extends ProcessProxy {
}
}
- private synchronized void setSocketResult(int result) {
+ private synchronized void setSocketResult(int result)
+ throws VpnConnectingError {
if (mControlSocketInUse) {
mSocketResult = result;
notifyAll();
+ } else if (result > 0) {
+ // error from daemon
+ throw new VpnConnectingError((result == AUTH_ERROR_CODE)
+ ? VpnManager.VPN_ERROR_AUTH
+ : VpnManager.VPN_ERROR_CONNECTION_FAILED);
}
}
- private void setResultAndCloseControlSocket(int result) {
+ private void setResultAndCloseControlSocket(int result)
+ throws VpnConnectingError {
setSocketResult(result);
try {
mKeepaliveSocket.shutdownInput();
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java
index 6abf81c..7b3ddf8 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java
@@ -30,12 +30,11 @@ class L2tpIpsecPskService extends VpnService<L2tpIpsecPskProfile> {
@Override
protected void connect(String serverIp, String username, String password)
throws IOException {
- String hostIp = getHostIp();
L2tpIpsecPskProfile p = getProfile();
// IPSEC
AndroidServiceProxy ipsecService = startService(IPSEC_DAEMON);
- ipsecService.sendCommand(hostIp, serverIp, L2tpService.L2TP_PORT,
+ ipsecService.sendCommand(serverIp, L2tpService.L2TP_PORT,
p.getPresharedKey());
sleep(2000); // 2 seconds
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
index 825953c..e2d4ff4 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
@@ -30,11 +30,9 @@ class L2tpIpsecService extends VpnService<L2tpIpsecProfile> {
@Override
protected void connect(String serverIp, String username, String password)
throws IOException {
- String hostIp = getHostIp();
-
// IPSEC
AndroidServiceProxy ipsecService = startService(IPSEC_DAEMON);
- ipsecService.sendCommand(hostIp, serverIp, L2tpService.L2TP_PORT,
+ ipsecService.sendCommand(serverIp, L2tpService.L2TP_PORT,
getUserkeyPath(), getUserCertPath(), getCaCertPath());
sleep(2000); // 2 seconds
diff --git a/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
index 16d253a..5fac799 100644
--- a/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
+++ b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
@@ -48,7 +48,6 @@ class MtpdHelper {
"linkname", VPN_LINKNAME,
"name", username,
"password", password,
- "ipparam", serverIp + "@" + vpnService.getGatewayIp(),
"refuse-eap", "nodefaultroute", "usepeerdns",
"idle", "1800",
"mtu", "1400",
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnConnectingError.java b/packages/VpnServices/src/com/android/server/vpn/VpnConnectingError.java
new file mode 100644
index 0000000..3c4ec7d
--- /dev/null
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnConnectingError.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vpn;
+
+import java.io.IOException;
+
+/**
+ * Exception thrown when a connecting attempt fails.
+ */
+class VpnConnectingError extends IOException {
+ private int mErrorCode;
+
+ VpnConnectingError(int errorCode) {
+ super("Connecting error: " + errorCode);
+ mErrorCode = errorCode;
+ }
+
+ int getErrorCode() {
+ return mErrorCode;
+ }
+}
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
index a60788a..87bd780 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
@@ -20,7 +20,6 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
-import android.net.NetworkUtils;
import android.net.vpn.VpnManager;
import android.net.vpn.VpnProfile;
import android.net.vpn.VpnState;
@@ -30,10 +29,8 @@ import android.util.Log;
import java.io.IOException;
import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.Socket;
+import java.net.UnknownHostException;
import java.util.ArrayList;
-import java.util.Enumeration;
import java.util.List;
/**
@@ -46,9 +43,9 @@ abstract class VpnService<E extends VpnProfile> {
private static final String DNS2 = "net.dns2";
private static final String VPN_DNS1 = "vpn.dns1";
private static final String VPN_DNS2 = "vpn.dns2";
- private static final String VPN_UP = "vpn.up";
- private static final String VPN_IS_UP = "1";
- private static final String VPN_IS_DOWN = "0";
+ private static final String VPN_STATUS = "vpn.status";
+ private static final String VPN_IS_UP = "ok";
+ private static final String VPN_IS_DOWN = "down";
private static final String REMOTE_IP = "net.ipremote";
private static final String DNS_DOMAIN_SUFFICES = "net.dns.search";
@@ -60,6 +57,7 @@ abstract class VpnService<E extends VpnProfile> {
private VpnState mState = VpnState.IDLE;
private boolean mInError;
+ private VpnConnectingError mError;
// connection settings
private String mOriginalDns1;
@@ -67,7 +65,6 @@ abstract class VpnService<E extends VpnProfile> {
private String mVpnDns1 = "";
private String mVpnDns2 = "";
private String mOriginalDomainSuffices;
- private String mHostIp;
private long mStartTime; // VPN connection start time
@@ -106,14 +103,6 @@ abstract class VpnService<E extends VpnProfile> {
}
/**
- * Returns the host IP for establishing the VPN connection.
- */
- protected String getHostIp() throws IOException {
- if (mHostIp == null) mHostIp = reallyGetHostIp();
- return mHostIp;
- }
-
- /**
* Returns the IP address of the specified host name.
*/
protected String getIp(String hostName) throws IOException {
@@ -121,21 +110,6 @@ abstract class VpnService<E extends VpnProfile> {
}
/**
- * Returns the IP address of the default gateway.
- */
- protected String getGatewayIp() throws IOException {
- Enumeration<NetworkInterface> ifces =
- NetworkInterface.getNetworkInterfaces();
- for (; ifces.hasMoreElements(); ) {
- NetworkInterface ni = ifces.nextElement();
- int gateway = NetworkUtils.getDefaultRoute(ni.getName());
- if (gateway == 0) continue;
- return toInetAddress(gateway).getHostAddress();
- }
- throw new IOException("Default gateway is not available");
- }
-
- /**
* Sets the system property. The method is blocked until the value is
* settled in.
* @param name the name of the property
@@ -166,20 +140,28 @@ abstract class VpnService<E extends VpnProfile> {
return mState;
}
- synchronized void onConnect(String username, String password)
- throws IOException {
- mState = VpnState.CONNECTING;
- broadcastConnectivity(VpnState.CONNECTING);
+ synchronized boolean onConnect(String username, String password) {
+ try {
+ mState = VpnState.CONNECTING;
+ broadcastConnectivity(VpnState.CONNECTING);
- String serverIp = getIp(getProfile().getServerName());
+ String serverIp = getIp(getProfile().getServerName());
- onBeforeConnect();
- connect(serverIp, username, password);
- waitUntilConnectedOrTimedout();
+ onBeforeConnect();
+ connect(serverIp, username, password);
+ waitUntilConnectedOrTimedout();
+ return true;
+ } catch (Throwable e) {
+ Log.e(TAG, "onConnect()", e);
+ mError = newConnectingError(e);
+ onError();
+ return false;
+ }
}
synchronized void onDisconnect(boolean cleanUpServices) {
try {
+ Log.d(TAG, " disconnecting VPN...");
mState = VpnState.DISCONNECTING;
broadcastConnectivity(VpnState.DISCONNECTING);
mNotification.showDisconnect();
@@ -189,7 +171,7 @@ abstract class VpnService<E extends VpnProfile> {
mServiceHelper.stop();
} catch (Throwable e) {
- Log.e(TAG, "onError()", e);
+ Log.e(TAG, "onDisconnect()", e);
onFinalCleanUp();
}
}
@@ -214,26 +196,35 @@ abstract class VpnService<E extends VpnProfile> {
SystemProperties.set(VPN_DNS1, "-");
SystemProperties.set(VPN_DNS2, "-");
- SystemProperties.set(VPN_UP, VPN_IS_DOWN);
- Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_UP));
+ SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
+ Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS));
}
private void waitUntilConnectedOrTimedout() {
- sleep(2000); // 2 seconds
- for (int i = 0; i < 60; i++) {
- if (VPN_IS_UP.equals(SystemProperties.get(VPN_UP))) {
- onConnected();
- return;
- }
- sleep(500); // 0.5 second
- }
+ // Run this in the background thread to not block UI
+ new Thread(new Runnable() {
+ public void run() {
+ sleep(2000); // 2 seconds
+ for (int i = 0; i < 60; i++) {
+ if (VPN_IS_UP.equals(SystemProperties.get(VPN_STATUS))) {
+ onConnected();
+ return;
+ } else if (mState != VpnState.CONNECTING) {
+ break;
+ }
+ sleep(500); // 0.5 second
+ }
- synchronized (this) {
- if (mState == VpnState.CONNECTING) {
- Log.d(TAG, " connecting timed out !!");
- onError();
+ synchronized (VpnService.this) {
+ if (mState == VpnState.CONNECTING) {
+ Log.d(TAG, " connecting timed out !!");
+ mError = newConnectingError(
+ new IOException("Connecting timed out"));
+ onError();
+ }
+ }
}
- }
+ }).start();
}
private synchronized void onConnected() {
@@ -264,6 +255,13 @@ abstract class VpnService<E extends VpnProfile> {
mContext.stopSelf();
}
+ private VpnConnectingError newConnectingError(Throwable e) {
+ return new VpnConnectingError(
+ (e instanceof UnknownHostException)
+ ? VpnManager.VPN_ERROR_UNKNOWN_SERVER
+ : VpnManager.VPN_ERROR_CONNECTION_FAILED);
+ }
+
private synchronized void onOneServiceGone() {
switch (mState) {
case IDLE:
@@ -304,12 +302,12 @@ abstract class VpnService<E extends VpnProfile> {
private void saveVpnDnsProperties() {
mOriginalDns1 = mOriginalDns2 = "";
- for (int i = 0; i < 10; i++) {
+ for (int i = 0; i < 5; i++) {
mVpnDns1 = SystemProperties.get(VPN_DNS1);
mVpnDns2 = SystemProperties.get(VPN_DNS2);
if (mOriginalDns1.equals(mVpnDns1)) {
Log.d(TAG, "wait for vpn dns to settle in..." + i);
- sleep(500);
+ sleep(200);
} else {
mOriginalDns1 = SystemProperties.get(DNS1);
mOriginalDns2 = SystemProperties.get(DNS2);
@@ -322,7 +320,9 @@ abstract class VpnService<E extends VpnProfile> {
return;
}
}
- Log.e(TAG, "saveVpnDnsProperties(): DNS not updated??");
+ Log.d(TAG, "saveVpnDnsProperties(): DNS not updated??");
+ mOriginalDns1 = mVpnDns1 = SystemProperties.get(DNS1);
+ mOriginalDns2 = mVpnDns2 = SystemProperties.get(DNS2);
}
private void saveAndSetDomainSuffices() {
@@ -340,7 +340,13 @@ abstract class VpnService<E extends VpnProfile> {
}
private void broadcastConnectivity(VpnState s) {
- new VpnManager(mContext).broadcastConnectivity(mProfile.getName(), s);
+ VpnManager m = new VpnManager(mContext);
+ if ((s == VpnState.IDLE) && (mError != null)) {
+ m.broadcastConnectivity(mProfile.getName(), s,
+ mError.getErrorCode());
+ } else {
+ m.broadcastConnectivity(mProfile.getName(), s);
+ }
}
private void startConnectivityMonitor() {
@@ -373,26 +379,11 @@ abstract class VpnService<E extends VpnProfile> {
private void checkDnsProperties() {
String dns1 = SystemProperties.get(DNS1);
if (!mVpnDns1.equals(dns1)) {
- Log.w(TAG, " @@ !!! dns being overridden");
+ Log.w(TAG, " dns being overridden by: " + dns1);
onError();
}
}
- private String reallyGetHostIp() throws IOException {
- Enumeration<NetworkInterface> ifces =
- NetworkInterface.getNetworkInterfaces();
- for (; ifces.hasMoreElements(); ) {
- NetworkInterface ni = ifces.nextElement();
- int gateway = NetworkUtils.getDefaultRoute(ni.getName());
- if (gateway == 0) continue;
- Enumeration<InetAddress> addrs = ni.getInetAddresses();
- for (; addrs.hasMoreElements(); ) {
- return addrs.nextElement().getHostAddress();
- }
- }
- throw new IOException("Host IP is not available");
- }
-
protected void sleep(int ms) {
try {
Thread.currentThread().sleep(ms);
@@ -440,6 +431,9 @@ abstract class VpnService<E extends VpnProfile> {
//@Override
public void error(ProcessProxy p, Throwable e) {
Log.e(TAG, "service error: " + p.getName(), e);
+ if (e instanceof VpnConnectingError) {
+ mError = (VpnConnectingError) e;
+ }
commonCallback((AndroidServiceProxy) p);
}
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
index 617875e..32b8e51 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
@@ -27,7 +27,6 @@ import android.net.vpn.VpnManager;
import android.net.vpn.VpnProfile;
import android.net.vpn.VpnState;
import android.os.IBinder;
-import android.util.Log;
import java.io.IOException;
@@ -55,6 +54,12 @@ public class VpnServiceBinder extends Service {
}
};
+ public void onStart (Intent intent, int startId) {
+ super.onStart(intent, startId);
+ setForeground(true);
+ android.util.Log.d("VpnServiceBinder", "becomes a foreground service");
+ }
+
public IBinder onBind(Intent intent) {
return mBinder;
}
@@ -62,21 +67,13 @@ public class VpnServiceBinder extends Service {
private synchronized boolean connect(
VpnProfile p, String username, String password) {
if (mService != null) return false;
- try {
- mService = createService(p);
- mService.onConnect(username, password);
- return true;
- } catch (Throwable e) {
- Log.e(TAG, "connect()", e);
- if (mService != null) mService.onError();
- return false;
- }
+ mService = createService(p);
+ return mService.onConnect(username, password);
}
private synchronized void checkStatus(VpnProfile p) {
- if (mService == null) broadcastConnectivity(p.getName(), VpnState.IDLE);
-
- if (!p.getName().equals(mService.mProfile.getName())) {
+ if ((mService == null)
+ || (!p.getName().equals(mService.mProfile.getName()))) {
broadcastConnectivity(p.getName(), VpnState.IDLE);
} else {
broadcastConnectivity(p.getName(), mService.getState());