Merge change 6883 into donut

* changes:
  Add error code in vpn connectivity broadcast.
This commit is contained in:
Android (Google) Code Review
2009-07-12 23:40:46 -07:00
5 changed files with 133 additions and 47 deletions

View File

@@ -18,6 +18,7 @@ package com.android.server.vpn;
import android.net.LocalSocket; import android.net.LocalSocket;
import android.net.LocalSocketAddress; import android.net.LocalSocketAddress;
import android.net.vpn.VpnManager;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.util.Log; 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 END_OF_ARGUMENTS = 255;
private static final int STOP_SERVICE = -1;
private static final int AUTH_ERROR_CODE = 51;
private String mServiceName; private String mServiceName;
private String mSocketName; private String mSocketName;
private LocalSocket mKeepaliveSocket; private LocalSocket mKeepaliveSocket;
@@ -72,14 +76,21 @@ public class AndroidServiceProxy extends ProcessProxy {
@Override @Override
public synchronized void stop() { public synchronized void stop() {
if (isRunning()) setResultAndCloseControlSocket(-1); if (isRunning()) {
try {
setResultAndCloseControlSocket(STOP_SERVICE);
} catch (IOException e) {
// should not occur
throw new RuntimeException(e);
}
}
SystemProperties.set(SVC_STOP_CMD, mServiceName); SystemProperties.set(SVC_STOP_CMD, mServiceName);
} }
/** /**
* Sends a command with arguments to the service through the control socket. * 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(); OutputStream out = getControlSocketOutput();
for (String arg : args) outputString(out, arg); for (String arg : args) outputString(out, arg);
out.write(END_OF_ARGUMENTS); out.write(END_OF_ARGUMENTS);
@@ -114,30 +125,22 @@ public class AndroidServiceProxy extends ProcessProxy {
InputStream in = s.getInputStream(); InputStream in = s.getInputStream();
int data = in.read(); int data = in.read();
if (data >= 0) { if (data >= 0) {
Log.d(mTag, "got data from keepalive socket: " + data); Log.d(mTag, "got data from control socket: " + data);
if (data == 0) { setSocketResult(data);
// 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);
}
} else { } else {
// service is gone // service is gone
if (mControlSocketInUse) setSocketResult(-1); if (mControlSocketInUse) setSocketResult(-1);
break; break;
} }
} }
Log.d(mTag, "keepalive connection closed"); Log.d(mTag, "control connection closed");
} catch (IOException e) { } 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 // Wait 5 seconds for the service to exit
@@ -179,7 +182,7 @@ public class AndroidServiceProxy extends ProcessProxy {
} }
} }
private synchronized void checkSocketResult() throws IOException { private void checkSocketResult() throws IOException {
try { try {
// will be notified when the result comes back from service // will be notified when the result comes back from service
if (mSocketResult == null) wait(); if (mSocketResult == null) wait();
@@ -194,14 +197,21 @@ public class AndroidServiceProxy extends ProcessProxy {
} }
} }
private synchronized void setSocketResult(int result) { private synchronized void setSocketResult(int result)
throws VpnConnectingError {
if (mControlSocketInUse) { if (mControlSocketInUse) {
mSocketResult = result; mSocketResult = result;
notifyAll(); 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); setSocketResult(result);
try { try {
mKeepaliveSocket.shutdownInput(); mKeepaliveSocket.shutdownInput();

View File

@@ -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;
}
}

View File

@@ -32,6 +32,7 @@ import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.NetworkInterface; import java.net.NetworkInterface;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
@@ -46,9 +47,9 @@ abstract class VpnService<E extends VpnProfile> {
private static final String DNS2 = "net.dns2"; private static final String DNS2 = "net.dns2";
private static final String VPN_DNS1 = "vpn.dns1"; private static final String VPN_DNS1 = "vpn.dns1";
private static final String VPN_DNS2 = "vpn.dns2"; private static final String VPN_DNS2 = "vpn.dns2";
private static final String VPN_UP = "vpn.up"; private static final String VPN_STATUS = "vpn.status";
private static final String VPN_IS_UP = "1"; private static final String VPN_IS_UP = "ok";
private static final String VPN_IS_DOWN = "0"; private static final String VPN_IS_DOWN = "down";
private static final String REMOTE_IP = "net.ipremote"; private static final String REMOTE_IP = "net.ipremote";
private static final String DNS_DOMAIN_SUFFICES = "net.dns.search"; private static final String DNS_DOMAIN_SUFFICES = "net.dns.search";
@@ -60,6 +61,7 @@ abstract class VpnService<E extends VpnProfile> {
private VpnState mState = VpnState.IDLE; private VpnState mState = VpnState.IDLE;
private boolean mInError; private boolean mInError;
private VpnConnectingError mError;
// connection settings // connection settings
private String mOriginalDns1; private String mOriginalDns1;
@@ -166,16 +168,23 @@ abstract class VpnService<E extends VpnProfile> {
return mState; return mState;
} }
synchronized void onConnect(String username, String password) synchronized boolean onConnect(String username, String password) {
throws IOException { try {
mState = VpnState.CONNECTING; mState = VpnState.CONNECTING;
broadcastConnectivity(VpnState.CONNECTING); broadcastConnectivity(VpnState.CONNECTING);
String serverIp = getIp(getProfile().getServerName()); String serverIp = getIp(getProfile().getServerName());
onBeforeConnect(); onBeforeConnect();
connect(serverIp, username, password); connect(serverIp, username, password);
waitUntilConnectedOrTimedout(); waitUntilConnectedOrTimedout();
return true;
} catch (Throwable e) {
Log.e(TAG, "onConnect()", e);
mError = newConnectingError(e);
onError();
return false;
}
} }
synchronized void onDisconnect(boolean cleanUpServices) { synchronized void onDisconnect(boolean cleanUpServices) {
@@ -214,8 +223,8 @@ abstract class VpnService<E extends VpnProfile> {
SystemProperties.set(VPN_DNS1, "-"); SystemProperties.set(VPN_DNS1, "-");
SystemProperties.set(VPN_DNS2, "-"); SystemProperties.set(VPN_DNS2, "-");
SystemProperties.set(VPN_UP, VPN_IS_DOWN); SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_UP)); Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS));
} }
private void waitUntilConnectedOrTimedout() { private void waitUntilConnectedOrTimedout() {
@@ -224,7 +233,7 @@ abstract class VpnService<E extends VpnProfile> {
public void run() { public void run() {
sleep(2000); // 2 seconds sleep(2000); // 2 seconds
for (int i = 0; i < 60; i++) { for (int i = 0; i < 60; i++) {
if (VPN_IS_UP.equals(SystemProperties.get(VPN_UP))) { if (VPN_IS_UP.equals(SystemProperties.get(VPN_STATUS))) {
onConnected(); onConnected();
return; return;
} else if (mState != VpnState.CONNECTING) { } else if (mState != VpnState.CONNECTING) {
@@ -271,6 +280,13 @@ abstract class VpnService<E extends VpnProfile> {
mContext.stopSelf(); 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() { private synchronized void onOneServiceGone() {
switch (mState) { switch (mState) {
case IDLE: case IDLE:
@@ -347,7 +363,13 @@ abstract class VpnService<E extends VpnProfile> {
} }
private void broadcastConnectivity(VpnState s) { 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() { private void startConnectivityMonitor() {
@@ -447,6 +469,9 @@ abstract class VpnService<E extends VpnProfile> {
//@Override //@Override
public void error(ProcessProxy p, Throwable e) { public void error(ProcessProxy p, Throwable e) {
Log.e(TAG, "service error: " + p.getName(), e); Log.e(TAG, "service error: " + p.getName(), e);
if (e instanceof VpnConnectingError) {
mError = (VpnConnectingError) e;
}
commonCallback((AndroidServiceProxy) p); commonCallback((AndroidServiceProxy) p);
} }

View File

@@ -27,7 +27,6 @@ import android.net.vpn.VpnManager;
import android.net.vpn.VpnProfile; import android.net.vpn.VpnProfile;
import android.net.vpn.VpnState; import android.net.vpn.VpnState;
import android.os.IBinder; import android.os.IBinder;
import android.util.Log;
import java.io.IOException; import java.io.IOException;
@@ -55,6 +54,11 @@ public class VpnServiceBinder extends Service {
} }
}; };
public void onStart (Intent intent, int startId) {
super.onStart(intent, startId);
setForeground(true);
}
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
return mBinder; return mBinder;
} }
@@ -62,15 +66,8 @@ public class VpnServiceBinder extends Service {
private synchronized boolean connect( private synchronized boolean connect(
VpnProfile p, String username, String password) { VpnProfile p, String username, String password) {
if (mService != null) return false; if (mService != null) return false;
try { mService = createService(p);
mService = createService(p); return mService.onConnect(username, password);
mService.onConnect(username, password);
return true;
} catch (Throwable e) {
Log.e(TAG, "connect()", e);
if (mService != null) mService.onError();
return false;
}
} }
private synchronized void checkStatus(VpnProfile p) { private synchronized void checkStatus(VpnProfile p) {

View File

@@ -42,6 +42,15 @@ public class VpnManager {
public static final String BROADCAST_PROFILE_NAME = "profile_name"; public static final String BROADCAST_PROFILE_NAME = "profile_name";
/** Key to the connectivity state of a connectivity broadcast event. */ /** Key to the connectivity state of a connectivity broadcast event. */
public static final String BROADCAST_CONNECTION_STATE = "connection_state"; public static final String BROADCAST_CONNECTION_STATE = "connection_state";
/** Key to the error code of a connectivity broadcast event. */
public static final String BROADCAST_ERROR_CODE = "err";
/** Error code to indicate an error from authentication. */
public static final int VPN_ERROR_AUTH = 1;
/** Error code to indicate the connection attempt failed. */
public static final int VPN_ERROR_CONNECTION_FAILED = 2;
/** Error code to indicate the server is not known. */
public static final int VPN_ERROR_UNKNOWN_SERVER = 3;
private static final int VPN_ERROR_NO_ERROR = 0;
public static final String PROFILES_PATH = "/data/misc/vpn/profiles"; public static final String PROFILES_PATH = "/data/misc/vpn/profiles";
@@ -52,7 +61,8 @@ public class VpnManager {
private static final String ACTION_VPN_SERVICE = PACKAGE_PREFIX + "SERVICE"; private static final String ACTION_VPN_SERVICE = PACKAGE_PREFIX + "SERVICE";
// Action to start VPN settings // Action to start VPN settings
private static final String ACTION_VPN_SETTINGS = PACKAGE_PREFIX + "SETTINGS"; private static final String ACTION_VPN_SETTINGS =
PACKAGE_PREFIX + "SETTINGS";
private static final String TAG = VpnManager.class.getSimpleName(); private static final String TAG = VpnManager.class.getSimpleName();
@@ -130,9 +140,18 @@ public class VpnManager {
/** Broadcasts the connectivity state of the specified profile. */ /** Broadcasts the connectivity state of the specified profile. */
public void broadcastConnectivity(String profileName, VpnState s) { public void broadcastConnectivity(String profileName, VpnState s) {
broadcastConnectivity(profileName, s, VPN_ERROR_NO_ERROR);
}
/** Broadcasts the connectivity state with an error code. */
public void broadcastConnectivity(String profileName, VpnState s,
int error) {
Intent intent = new Intent(ACTION_VPN_CONNECTIVITY); Intent intent = new Intent(ACTION_VPN_CONNECTIVITY);
intent.putExtra(BROADCAST_PROFILE_NAME, profileName); intent.putExtra(BROADCAST_PROFILE_NAME, profileName);
intent.putExtra(BROADCAST_CONNECTION_STATE, s); intent.putExtra(BROADCAST_CONNECTION_STATE, s);
if (error != VPN_ERROR_NO_ERROR) {
intent.putExtra(BROADCAST_ERROR_CODE, error);
}
mContext.sendBroadcast(intent); mContext.sendBroadcast(intent);
} }