Home | History | Annotate | Download | only in vpn
      1 /*
      2  * Copyright (C) 2009, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.vpn;
     18 
     19 import android.app.Service;
     20 import android.content.Intent;
     21 import android.net.vpn.IVpnService;
     22 import android.net.vpn.L2tpIpsecProfile;
     23 import android.net.vpn.L2tpIpsecPskProfile;
     24 import android.net.vpn.L2tpProfile;
     25 import android.net.vpn.PptpProfile;
     26 import android.net.vpn.VpnManager;
     27 import android.net.vpn.VpnProfile;
     28 import android.net.vpn.VpnState;
     29 import android.os.Environment;
     30 import android.os.IBinder;
     31 import android.os.SystemProperties;
     32 import android.util.Log;
     33 
     34 import java.io.File;
     35 import java.io.FileInputStream;
     36 import java.io.FileNotFoundException;
     37 import java.io.FileOutputStream;
     38 import java.io.IOException;
     39 import java.io.ObjectInputStream;
     40 import java.io.ObjectOutputStream;
     41 
     42 /**
     43  * The service class for managing a VPN connection. It implements the
     44  * {@link IVpnService} binder interface.
     45  */
     46 public class VpnServiceBinder extends Service {
     47     private static final String TAG = VpnServiceBinder.class.getSimpleName();
     48     private static final boolean DBG = true;
     49 
     50     private static final String STATES_FILE_RELATIVE_PATH = "/misc/vpn/.states";
     51 
     52     // The actual implementation is delegated to the VpnService class.
     53     private VpnService<? extends VpnProfile> mService;
     54 
     55     private static String getStateFilePath() {
     56 	return Environment.getDataDirectory().getPath() + STATES_FILE_RELATIVE_PATH;
     57     }
     58 
     59     private final IBinder mBinder = new IVpnService.Stub() {
     60         public boolean connect(VpnProfile p, String username, String password) {
     61             return VpnServiceBinder.this.connect(p, username, password);
     62         }
     63 
     64         public void disconnect() {
     65             VpnServiceBinder.this.disconnect();
     66         }
     67 
     68         public void checkStatus(VpnProfile p) {
     69             VpnServiceBinder.this.checkStatus(p);
     70         }
     71     };
     72 
     73     @Override
     74     public void onCreate() {
     75         super.onCreate();
     76         checkSavedStates();
     77     }
     78 
     79 
     80     @Override
     81     public void onStart(Intent intent, int startId) {
     82         super.onStart(intent, startId);
     83     }
     84 
     85     @Override
     86     public IBinder onBind(Intent intent) {
     87         return mBinder;
     88     }
     89 
     90     void saveStates() throws IOException {
     91         if (DBG) Log.d("VpnServiceBinder", "     saving states");
     92         ObjectOutputStream oos =
     93                 new ObjectOutputStream(new FileOutputStream(getStateFilePath()));
     94         oos.writeObject(mService);
     95         oos.close();
     96     }
     97 
     98     void removeStates() {
     99         try {
    100             File f = new File(getStateFilePath());
    101             if (f.exists()) f.delete();
    102         } catch (Throwable e) {
    103             if (DBG) Log.d("VpnServiceBinder", "     remove states: " + e);
    104         }
    105     }
    106 
    107     private synchronized boolean connect(final VpnProfile p,
    108             final String username, final String password) {
    109         if (mService != null) return false;
    110         final VpnService s = mService = createService(p);
    111 
    112         new Thread(new Runnable() {
    113             public void run() {
    114                 s.onConnect(username, password);
    115             }
    116         }).start();
    117         return true;
    118     }
    119 
    120     private synchronized void disconnect() {
    121         if (mService == null) return;
    122         final VpnService s = mService;
    123 
    124         new Thread(new Runnable() {
    125             public void run() {
    126                 s.onDisconnect();
    127             }
    128         }).start();
    129     }
    130 
    131     private synchronized void checkStatus(VpnProfile p) {
    132         if ((mService == null)
    133                 || (!p.getName().equals(mService.mProfile.getName()))) {
    134             broadcastConnectivity(p.getName(), VpnState.IDLE);
    135         } else {
    136             broadcastConnectivity(p.getName(), mService.getState());
    137         }
    138     }
    139 
    140     private void checkSavedStates() {
    141         try {
    142             ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
    143                     getStateFilePath()));
    144             mService = (VpnService<? extends VpnProfile>) ois.readObject();
    145             mService.recover(this);
    146             ois.close();
    147         } catch (FileNotFoundException e) {
    148             // do nothing
    149         } catch (Throwable e) {
    150             Log.i("VpnServiceBinder", "recovery error, remove states: " + e);
    151             removeStates();
    152         }
    153     }
    154 
    155     private VpnService<? extends VpnProfile> createService(VpnProfile p) {
    156         switch (p.getType()) {
    157             case L2TP:
    158                 L2tpService l2tp = new L2tpService();
    159                 l2tp.setContext(this, (L2tpProfile) p);
    160                 return l2tp;
    161 
    162             case PPTP:
    163                 PptpService pptp = new PptpService();
    164                 pptp.setContext(this, (PptpProfile) p);
    165                 return pptp;
    166 
    167             case L2TP_IPSEC_PSK:
    168                 L2tpIpsecPskService psk = new L2tpIpsecPskService();
    169                 psk.setContext(this, (L2tpIpsecPskProfile) p);
    170                 return psk;
    171 
    172             case L2TP_IPSEC:
    173                 L2tpIpsecService l2tpIpsec = new L2tpIpsecService();
    174                 l2tpIpsec.setContext(this, (L2tpIpsecProfile) p);
    175                 return l2tpIpsec;
    176 
    177             default:
    178                 return null;
    179         }
    180     }
    181 
    182     private void broadcastConnectivity(String name, VpnState s) {
    183         new VpnManager(this).broadcastConnectivity(name, s);
    184     }
    185 }
    186