diff options
Diffstat (limited to 'packages/VpnServices/src')
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()); |