| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2011 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.connectivity; | 
 | 18 |  | 
 | 19 | import android.app.Notification; | 
 | 20 | import android.app.NotificationManager; | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 21 | import android.content.Context; | 
 | 22 | import android.content.Intent; | 
 | 23 | import android.content.pm.ApplicationInfo; | 
 | 24 | import android.content.pm.PackageManager; | 
 | 25 | import android.content.res.Resources; | 
 | 26 | import android.graphics.Bitmap; | 
 | 27 | import android.graphics.Canvas; | 
 | 28 | import android.graphics.drawable.Drawable; | 
 | 29 | import android.net.INetworkManagementEventObserver; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 30 | import android.net.LocalSocket; | 
 | 31 | import android.net.LocalSocketAddress; | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 32 | import android.os.Binder; | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 33 | import android.os.ParcelFileDescriptor; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 34 | import android.os.Process; | 
 | 35 | import android.os.SystemClock; | 
 | 36 | import android.os.SystemProperties; | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 37 | import android.util.Log; | 
 | 38 |  | 
 | 39 | import com.android.internal.R; | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 40 | import com.android.internal.net.LegacyVpnInfo; | 
| Chia-chi Yeh | 04ba25c | 2011-06-15 17:07:27 -0700 | [diff] [blame] | 41 | import com.android.internal.net.VpnConfig; | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 42 | import com.android.server.ConnectivityService.VpnCallback; | 
 | 43 |  | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 44 | import java.io.File; | 
 | 45 | import java.io.FileInputStream; | 
 | 46 | import java.io.InputStream; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 47 | import java.io.OutputStream; | 
 | 48 | import java.nio.charset.Charsets; | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 49 | import java.util.Arrays; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 50 |  | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 51 | /** | 
 | 52 |  * @hide | 
 | 53 |  */ | 
 | 54 | public class Vpn extends INetworkManagementEventObserver.Stub { | 
 | 55 |  | 
 | 56 |     private final static String TAG = "Vpn"; | 
 | 57 |     private final static String VPN = android.Manifest.permission.VPN; | 
 | 58 |  | 
 | 59 |     private final Context mContext; | 
 | 60 |     private final VpnCallback mCallback; | 
 | 61 |  | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 62 |     private String mPackage = VpnConfig.LEGACY_VPN; | 
 | 63 |     private String mInterface; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 64 |     private LegacyVpnRunner mLegacyVpnRunner; | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 65 |  | 
 | 66 |     public Vpn(Context context, VpnCallback callback) { | 
 | 67 |         mContext = context; | 
 | 68 |         mCallback = callback; | 
 | 69 |     } | 
 | 70 |  | 
 | 71 |     /** | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 72 |      * Protect a socket from routing changes by binding it to the given | 
| Chia-chi Yeh | 5779c9c | 2011-07-14 16:19:19 -0700 | [diff] [blame] | 73 |      * interface. The socket is NOT closed by this method. | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 74 |      * | 
 | 75 |      * @param socket The socket to be bound. | 
 | 76 |      * @param name The name of the interface. | 
 | 77 |      */ | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 78 |     public void protect(ParcelFileDescriptor socket, String interfaze) { | 
| Chia-chi Yeh | 5779c9c | 2011-07-14 16:19:19 -0700 | [diff] [blame] | 79 |         mContext.enforceCallingPermission(VPN, "protect"); | 
 | 80 |         jniProtect(socket.getFd(), interfaze); | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 81 |     } | 
 | 82 |  | 
 | 83 |     /** | 
| Chia-chi Yeh | 100155a | 2011-07-03 16:52:38 -0700 | [diff] [blame] | 84 |      * Prepare for a VPN application. This method is designed to solve | 
 | 85 |      * race conditions. It first compares the current prepared package | 
 | 86 |      * with {@code oldPackage}. If they are the same, the prepared | 
 | 87 |      * package is revoked and replaced with {@code newPackage}. If | 
 | 88 |      * {@code oldPackage} is {@code null}, the comparison is omitted. | 
 | 89 |      * If {@code newPackage} is the same package or {@code null}, the | 
 | 90 |      * revocation is omitted. This method returns {@code true} if the | 
 | 91 |      * operation is succeeded. | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 92 |      * | 
| Chia-chi Yeh | 100155a | 2011-07-03 16:52:38 -0700 | [diff] [blame] | 93 |      * Legacy VPN is handled specially since it is not a real package. | 
 | 94 |      * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and | 
 | 95 |      * it can be revoked by itself. | 
 | 96 |      * | 
 | 97 |      * @param oldPackage The package name of the old VPN application. | 
 | 98 |      * @param newPackage The package name of the new VPN application. | 
 | 99 |      * @return true if the operation is succeeded. | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 100 |      */ | 
| Chia-chi Yeh | 100155a | 2011-07-03 16:52:38 -0700 | [diff] [blame] | 101 |     public synchronized boolean prepare(String oldPackage, String newPackage) { | 
 | 102 |         // Return false if the package does not match. | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 103 |         if (oldPackage != null && !oldPackage.equals(mPackage)) { | 
| Chia-chi Yeh | 100155a | 2011-07-03 16:52:38 -0700 | [diff] [blame] | 104 |             return false; | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 105 |         } | 
 | 106 |  | 
| Chia-chi Yeh | 100155a | 2011-07-03 16:52:38 -0700 | [diff] [blame] | 107 |         // Return true if we do not need to revoke. | 
 | 108 |         if (newPackage == null || | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 109 |                 (newPackage.equals(mPackage) && !newPackage.equals(VpnConfig.LEGACY_VPN))) { | 
| Chia-chi Yeh | 100155a | 2011-07-03 16:52:38 -0700 | [diff] [blame] | 110 |             return true; | 
 | 111 |         } | 
 | 112 |  | 
 | 113 |         // Only system user can revoke a package. | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 114 |         if (Binder.getCallingUid() != Process.SYSTEM_UID) { | 
 | 115 |             throw new SecurityException("Unauthorized Caller"); | 
 | 116 |         } | 
 | 117 |  | 
 | 118 |         // Check the permission of the given package. | 
 | 119 |         PackageManager pm = mContext.getPackageManager(); | 
| Chia-chi Yeh | 100155a | 2011-07-03 16:52:38 -0700 | [diff] [blame] | 120 |         if (!newPackage.equals(VpnConfig.LEGACY_VPN) && | 
 | 121 |                 pm.checkPermission(VPN, newPackage) != PackageManager.PERMISSION_GRANTED) { | 
 | 122 |             throw new SecurityException(newPackage + " does not have " + VPN); | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 123 |         } | 
 | 124 |  | 
 | 125 |         // Reset the interface and hide the notification. | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 126 |         if (mInterface != null) { | 
 | 127 |             jniReset(mInterface); | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 128 |             mCallback.restore(); | 
 | 129 |             hideNotification(); | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 130 |             mInterface = null; | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 131 |         } | 
 | 132 |  | 
 | 133 |         // Send out the broadcast or stop LegacyVpnRunner. | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 134 |         if (!mPackage.equals(VpnConfig.LEGACY_VPN)) { | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 135 |             Intent intent = new Intent(VpnConfig.ACTION_VPN_REVOKED); | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 136 |             intent.setPackage(mPackage); | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 137 |             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); | 
 | 138 |             mContext.sendBroadcast(intent); | 
 | 139 |         } else if (mLegacyVpnRunner != null) { | 
 | 140 |             mLegacyVpnRunner.exit(); | 
 | 141 |             mLegacyVpnRunner = null; | 
 | 142 |         } | 
 | 143 |  | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 144 |         Log.i(TAG, "Switched from " + mPackage + " to " + newPackage); | 
 | 145 |         mPackage = newPackage; | 
| Chia-chi Yeh | 100155a | 2011-07-03 16:52:38 -0700 | [diff] [blame] | 146 |         return true; | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 147 |     } | 
 | 148 |  | 
 | 149 |     /** | 
 | 150 |      * Establish a VPN network and return the file descriptor of the VPN | 
 | 151 |      * interface. This methods returns {@code null} if the application is | 
| Chia-chi Yeh | 100155a | 2011-07-03 16:52:38 -0700 | [diff] [blame] | 152 |      * revoked or not prepared. | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 153 |      * | 
 | 154 |      * @param config The parameters to configure the network. | 
 | 155 |      * @return The file descriptor of the VPN interface. | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 156 |      */ | 
| Chia-chi Yeh | 04ba25c | 2011-06-15 17:07:27 -0700 | [diff] [blame] | 157 |     public synchronized ParcelFileDescriptor establish(VpnConfig config) { | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 158 |         // Check the permission of the caller. | 
 | 159 |         mContext.enforceCallingPermission(VPN, "establish"); | 
 | 160 |  | 
 | 161 |         // Check if the caller is already prepared. | 
 | 162 |         PackageManager pm = mContext.getPackageManager(); | 
 | 163 |         ApplicationInfo app = null; | 
 | 164 |         try { | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 165 |             app = pm.getApplicationInfo(mPackage, 0); | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 166 |         } catch (Exception e) { | 
| Chia-chi Yeh | 7b0b834 | 2011-06-17 14:34:11 -0700 | [diff] [blame] | 167 |             return null; | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 168 |         } | 
 | 169 |         if (Binder.getCallingUid() != app.uid) { | 
| Chia-chi Yeh | 7b0b834 | 2011-06-17 14:34:11 -0700 | [diff] [blame] | 170 |             return null; | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 171 |         } | 
 | 172 |  | 
| Chia-chi Yeh | a4b87b5 | 2011-06-30 23:21:55 -0700 | [diff] [blame] | 173 |         // Load the label. | 
 | 174 |         String label = app.loadLabel(pm).toString(); | 
 | 175 |  | 
 | 176 |         // Load the icon and convert it into a bitmap. | 
 | 177 |         Drawable icon = app.loadIcon(pm); | 
 | 178 |         Bitmap bitmap = null; | 
 | 179 |         if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) { | 
 | 180 |             int width = mContext.getResources().getDimensionPixelSize( | 
 | 181 |                     android.R.dimen.notification_large_icon_width); | 
 | 182 |             int height = mContext.getResources().getDimensionPixelSize( | 
 | 183 |                     android.R.dimen.notification_large_icon_height); | 
 | 184 |             icon.setBounds(0, 0, width, height); | 
 | 185 |             bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); | 
 | 186 |             icon.draw(new Canvas(bitmap)); | 
 | 187 |         } | 
 | 188 |  | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 189 |         // Configure the interface. Abort if any of these steps fails. | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 190 |         ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 191 |         try { | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 192 |             String interfaze = jniGetName(tun.getFd()); | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 193 |             if (jniSetAddresses(interfaze, config.addresses) < 1) { | 
 | 194 |                 throw new IllegalArgumentException("At least one address must be specified"); | 
 | 195 |             } | 
 | 196 |             if (config.routes != null) { | 
 | 197 |                 jniSetRoutes(interfaze, config.routes); | 
 | 198 |             } | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 199 |             if (mInterface != null && !mInterface.equals(interfaze)) { | 
 | 200 |                 jniReset(mInterface); | 
| Chia-chi Yeh | f4e3bf8 | 2011-06-30 12:33:17 -0700 | [diff] [blame] | 201 |             } | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 202 |             mInterface = interfaze; | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 203 |         } catch (RuntimeException e) { | 
 | 204 |             try { | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 205 |                 tun.close(); | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 206 |             } catch (Exception ex) { | 
 | 207 |                 // ignore | 
 | 208 |             } | 
 | 209 |             throw e; | 
 | 210 |         } | 
 | 211 |  | 
| Chia-chi Yeh | 8909b10 | 2011-07-01 01:09:42 -0700 | [diff] [blame] | 212 |         // Override DNS servers and search domains. | 
 | 213 |         mCallback.override(config.dnsServers, config.searchDomains); | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 214 |  | 
| Chia-chi Yeh | 8909b10 | 2011-07-01 01:09:42 -0700 | [diff] [blame] | 215 |         // Fill more values. | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 216 |         config.packagz = mPackage; | 
 | 217 |         config.interfaze = mInterface; | 
| Chia-chi Yeh | 8909b10 | 2011-07-01 01:09:42 -0700 | [diff] [blame] | 218 |  | 
 | 219 |         // Show the notification! | 
| Chia-chi Yeh | 383e052 | 2011-07-01 00:13:25 -0700 | [diff] [blame] | 220 |         showNotification(config, label, bitmap); | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 221 |         return tun; | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 222 |     } | 
 | 223 |  | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 224 |     // INetworkManagementEventObserver.Stub | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 225 |     public void interfaceAdded(String interfaze) { | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 226 |     } | 
 | 227 |  | 
 | 228 |     // INetworkManagementEventObserver.Stub | 
| Chia-chi Yeh | aa1727f | 2011-07-14 18:55:33 -0700 | [diff] [blame^] | 229 |     public synchronized void interfaceStatusChanged(String interfaze, boolean up) { | 
 | 230 |         if (!up && mLegacyVpnRunner != null) { | 
 | 231 |             mLegacyVpnRunner.check(interfaze); | 
 | 232 |         } | 
 | 233 |     } | 
 | 234 |  | 
 | 235 |     // INetworkManagementEventObserver.Stub | 
 | 236 |     public synchronized void interfaceLinkStateChanged(String interfaze, boolean up) { | 
 | 237 |         if (!up && mLegacyVpnRunner != null) { | 
 | 238 |             mLegacyVpnRunner.check(interfaze); | 
 | 239 |         } | 
 | 240 |     } | 
 | 241 |  | 
 | 242 |     // INetworkManagementEventObserver.Stub | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 243 |     public synchronized void interfaceRemoved(String interfaze) { | 
 | 244 |         if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) { | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 245 |             mCallback.restore(); | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 246 |             hideNotification(); | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 247 |             mInterface = null; | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 248 |         } | 
 | 249 |     } | 
 | 250 |  | 
| Chia-chi Yeh | a4b87b5 | 2011-06-30 23:21:55 -0700 | [diff] [blame] | 251 |     private void showNotification(VpnConfig config, String label, Bitmap icon) { | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 252 |         NotificationManager nm = (NotificationManager) | 
 | 253 |                 mContext.getSystemService(Context.NOTIFICATION_SERVICE); | 
 | 254 |  | 
 | 255 |         if (nm != null) { | 
| Chia-chi Yeh | a4b87b5 | 2011-06-30 23:21:55 -0700 | [diff] [blame] | 256 |             String title = (label == null) ? mContext.getString(R.string.vpn_title) : | 
 | 257 |                     mContext.getString(R.string.vpn_title_long, label); | 
| Chia-chi Yeh | 34e7813 | 2011-07-03 03:07:07 -0700 | [diff] [blame] | 258 |             String text = (config.session == null) ? mContext.getString(R.string.vpn_text) : | 
 | 259 |                     mContext.getString(R.string.vpn_text_long, config.session); | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 260 |             config.startTime = SystemClock.elapsedRealtime(); | 
| Chia-chi Yeh | a4b87b5 | 2011-06-30 23:21:55 -0700 | [diff] [blame] | 261 |  | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 262 |             long identity = Binder.clearCallingIdentity(); | 
 | 263 |             Notification notification = new Notification.Builder(mContext) | 
 | 264 |                     .setSmallIcon(R.drawable.vpn_connected) | 
| Chia-chi Yeh | a4b87b5 | 2011-06-30 23:21:55 -0700 | [diff] [blame] | 265 |                     .setLargeIcon(icon) | 
 | 266 |                     .setContentTitle(title) | 
| Chia-chi Yeh | f8905fd | 2011-06-14 16:35:02 -0700 | [diff] [blame] | 267 |                     .setContentText(text) | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 268 |                     .setContentIntent(VpnConfig.getIntentForStatusPanel(mContext, config)) | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 269 |                     .setDefaults(Notification.DEFAULT_ALL) | 
 | 270 |                     .setOngoing(true) | 
 | 271 |                     .getNotification(); | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 272 |             nm.notify(R.drawable.vpn_connected, notification); | 
 | 273 |             Binder.restoreCallingIdentity(identity); | 
 | 274 |         } | 
 | 275 |     } | 
 | 276 |  | 
 | 277 |     private void hideNotification() { | 
 | 278 |         NotificationManager nm = (NotificationManager) | 
 | 279 |                 mContext.getSystemService(Context.NOTIFICATION_SERVICE); | 
 | 280 |  | 
 | 281 |         if (nm != null) { | 
 | 282 |             long identity = Binder.clearCallingIdentity(); | 
 | 283 |             nm.cancel(R.drawable.vpn_connected); | 
 | 284 |             Binder.restoreCallingIdentity(identity); | 
 | 285 |         } | 
 | 286 |     } | 
 | 287 |  | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 288 |     private native int jniCreate(int mtu); | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 289 |     private native String jniGetName(int tun); | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 290 |     private native int jniSetAddresses(String interfaze, String addresses); | 
 | 291 |     private native int jniSetRoutes(String interfaze, String routes); | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 292 |     private native void jniReset(String interfaze); | 
 | 293 |     private native int jniCheck(String interfaze); | 
 | 294 |     private native void jniProtect(int socket, String interfaze); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 295 |  | 
 | 296 |     /** | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 297 |      * Start legacy VPN. This method stops the daemons and restart them | 
 | 298 |      * if arguments are not null. Heavy things are offloaded to another | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 299 |      * thread, so callers will not be blocked for a long time. | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 300 |      * | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 301 |      * @param config The parameters to configure the network. | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 302 |      * @param raoocn The arguments to be passed to racoon. | 
 | 303 |      * @param mtpd The arguments to be passed to mtpd. | 
 | 304 |      */ | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 305 |     public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { | 
| Chia-chi Yeh | 100155a | 2011-07-03 16:52:38 -0700 | [diff] [blame] | 306 |         // Prepare for the new request. This also checks the caller. | 
 | 307 |         prepare(null, VpnConfig.LEGACY_VPN); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 308 |  | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 309 |         // Start a new LegacyVpnRunner and we are done! | 
| Chia-chi Yeh | 100155a | 2011-07-03 16:52:38 -0700 | [diff] [blame] | 310 |         mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd); | 
 | 311 |         mLegacyVpnRunner.start(); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 312 |     } | 
 | 313 |  | 
 | 314 |     /** | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 315 |      * Return the information of the current ongoing legacy VPN. | 
 | 316 |      */ | 
 | 317 |     public synchronized LegacyVpnInfo getLegacyVpnInfo() { | 
 | 318 |         // Only system user can call this method. | 
 | 319 |         if (Binder.getCallingUid() != Process.SYSTEM_UID) { | 
 | 320 |             throw new SecurityException("Unauthorized Caller"); | 
 | 321 |         } | 
 | 322 |         return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo(); | 
 | 323 |     } | 
 | 324 |  | 
 | 325 |     /** | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 326 |      * Bringing up a VPN connection takes time, and that is all this thread | 
 | 327 |      * does. Here we have plenty of time. The only thing we need to take | 
 | 328 |      * care of is responding to interruptions as soon as possible. Otherwise | 
 | 329 |      * requests will be piled up. This can be done in a Handler as a state | 
 | 330 |      * machine, but it is much easier to read in the current form. | 
 | 331 |      */ | 
 | 332 |     private class LegacyVpnRunner extends Thread { | 
 | 333 |         private static final String TAG = "LegacyVpnRunner"; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 334 |  | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 335 |         private final VpnConfig mConfig; | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 336 |         private final String[] mDaemons; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 337 |         private final String[][] mArguments; | 
| Chia-chi Yeh | aa1727f | 2011-07-14 18:55:33 -0700 | [diff] [blame^] | 338 |         private final String mOuterInterface; | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 339 |         private final LegacyVpnInfo mInfo; | 
 | 340 |  | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 341 |         private long mTimer = -1; | 
 | 342 |  | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 343 |         public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) { | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 344 |             super(TAG); | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 345 |             mConfig = config; | 
 | 346 |             mDaemons = new String[] {"racoon", "mtpd"}; | 
 | 347 |             mArguments = new String[][] {racoon, mtpd}; | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 348 |             mInfo = new LegacyVpnInfo(); | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 349 |  | 
| Chia-chi Yeh | aa1727f | 2011-07-14 18:55:33 -0700 | [diff] [blame^] | 350 |             // This is the interface which VPN is running on. | 
 | 351 |             mOuterInterface = mConfig.interfaze; | 
 | 352 |  | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 353 |             // Legacy VPN is not a real package, so we use it to carry the key. | 
 | 354 |             mInfo.key = mConfig.packagz; | 
| Chia-chi Yeh | 34e7813 | 2011-07-03 03:07:07 -0700 | [diff] [blame] | 355 |             mConfig.packagz = VpnConfig.LEGACY_VPN; | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 356 |         } | 
 | 357 |  | 
| Chia-chi Yeh | aa1727f | 2011-07-14 18:55:33 -0700 | [diff] [blame^] | 358 |         public void check(String interfaze) { | 
 | 359 |             if (interfaze.equals(mOuterInterface)) { | 
 | 360 |                 Log.i(TAG, "Legacy VPN is going down with " + interfaze); | 
 | 361 |                 exit(); | 
 | 362 |             } | 
 | 363 |         } | 
 | 364 |  | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 365 |         public void exit() { | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 366 |             // We assume that everything is reset after the daemons die. | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 367 |             interrupt(); | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 368 |             for (String daemon : mDaemons) { | 
 | 369 |                 SystemProperties.set("ctl.stop", daemon); | 
 | 370 |             } | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 371 |         } | 
 | 372 |  | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 373 |         public LegacyVpnInfo getInfo() { | 
 | 374 |             // Update the info when VPN is disconnected. | 
 | 375 |             if (mInfo.state == LegacyVpnInfo.STATE_CONNECTED && mInterface == null) { | 
 | 376 |                 mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED; | 
 | 377 |                 mInfo.intent = null; | 
 | 378 |             } | 
 | 379 |             return mInfo; | 
 | 380 |         } | 
 | 381 |  | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 382 |         @Override | 
 | 383 |         public void run() { | 
 | 384 |             // Wait for the previous thread since it has been interrupted. | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 385 |             Log.v(TAG, "Waiting"); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 386 |             synchronized (TAG) { | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 387 |                 Log.v(TAG, "Executing"); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 388 |                 execute(); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 389 |             } | 
 | 390 |         } | 
 | 391 |  | 
 | 392 |         private void checkpoint(boolean yield) throws InterruptedException { | 
 | 393 |             long now = SystemClock.elapsedRealtime(); | 
 | 394 |             if (mTimer == -1) { | 
 | 395 |                 mTimer = now; | 
 | 396 |                 Thread.sleep(1); | 
 | 397 |             } else if (now - mTimer <= 30000) { | 
 | 398 |                 Thread.sleep(yield ? 200 : 1); | 
 | 399 |             } else { | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 400 |                 mInfo.state = LegacyVpnInfo.STATE_TIMEOUT; | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 401 |                 throw new IllegalStateException("Time is up"); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 402 |             } | 
 | 403 |         } | 
 | 404 |  | 
 | 405 |         private void execute() { | 
 | 406 |             // Catch all exceptions so we can clean up few things. | 
 | 407 |             try { | 
 | 408 |                 // Initialize the timer. | 
 | 409 |                 checkpoint(false); | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 410 |                 mInfo.state = LegacyVpnInfo.STATE_INITIALIZING; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 411 |  | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 412 |                 // First stop the daemons. | 
 | 413 |                 for (String daemon : mDaemons) { | 
 | 414 |                     SystemProperties.set("ctl.stop", daemon); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 415 |                 } | 
 | 416 |  | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 417 |                 // Wait for the daemons to stop. | 
 | 418 |                 for (String daemon : mDaemons) { | 
 | 419 |                     String key = "init.svc." + daemon; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 420 |                     while (!"stopped".equals(SystemProperties.get(key))) { | 
 | 421 |                         checkpoint(true); | 
 | 422 |                     } | 
 | 423 |                 } | 
 | 424 |  | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 425 |                 // Clear the previous state. | 
 | 426 |                 File state = new File("/data/misc/vpn/state"); | 
 | 427 |                 state.delete(); | 
 | 428 |                 if (state.exists()) { | 
 | 429 |                     throw new IllegalStateException("Cannot delete the state"); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 430 |                 } | 
 | 431 |  | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 432 |                 // Check if we need to restart any of the daemons. | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 433 |                 boolean restart = false; | 
 | 434 |                 for (String[] arguments : mArguments) { | 
 | 435 |                     restart = restart || (arguments != null); | 
 | 436 |                 } | 
 | 437 |                 if (!restart) { | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 438 |                     mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 439 |                     return; | 
 | 440 |                 } | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 441 |                 mInfo.state = LegacyVpnInfo.STATE_CONNECTING; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 442 |  | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 443 |                 // Start the daemon with arguments. | 
 | 444 |                 for (int i = 0; i < mDaemons.length; ++i) { | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 445 |                     String[] arguments = mArguments[i]; | 
 | 446 |                     if (arguments == null) { | 
 | 447 |                         continue; | 
 | 448 |                     } | 
 | 449 |  | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 450 |                     // Start the daemon. | 
 | 451 |                     String daemon = mDaemons[i]; | 
 | 452 |                     SystemProperties.set("ctl.start", daemon); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 453 |  | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 454 |                     // Wait for the daemon to start. | 
 | 455 |                     String key = "init.svc." + daemon; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 456 |                     while (!"running".equals(SystemProperties.get(key))) { | 
 | 457 |                         checkpoint(true); | 
 | 458 |                     } | 
 | 459 |  | 
 | 460 |                     // Create the control socket. | 
 | 461 |                     LocalSocket socket = new LocalSocket(); | 
 | 462 |                     LocalSocketAddress address = new LocalSocketAddress( | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 463 |                             daemon, LocalSocketAddress.Namespace.RESERVED); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 464 |  | 
 | 465 |                     // Wait for the socket to connect. | 
 | 466 |                     while (true) { | 
 | 467 |                         try { | 
 | 468 |                             socket.connect(address); | 
 | 469 |                             break; | 
 | 470 |                         } catch (Exception e) { | 
 | 471 |                             // ignore | 
 | 472 |                         } | 
 | 473 |                         checkpoint(true); | 
 | 474 |                     } | 
 | 475 |                     socket.setSoTimeout(500); | 
 | 476 |  | 
 | 477 |                     // Send over the arguments. | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 478 |                     OutputStream out = socket.getOutputStream(); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 479 |                     for (String argument : arguments) { | 
 | 480 |                         byte[] bytes = argument.getBytes(Charsets.UTF_8); | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 481 |                         if (bytes.length > 0xFFFF) { | 
 | 482 |                             throw new IllegalArgumentException("Argument is too large"); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 483 |                         } | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 484 |                         out.write(bytes.length >> 8); | 
 | 485 |                         out.write(bytes.length); | 
 | 486 |                         out.write(bytes); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 487 |                         checkpoint(false); | 
 | 488 |                     } | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 489 |                     out.flush(); | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 490 |                     socket.shutdownOutput(); | 
 | 491 |  | 
 | 492 |                     // Wait for End-of-File. | 
 | 493 |                     InputStream in = socket.getInputStream(); | 
 | 494 |                     while (true) { | 
 | 495 |                         try { | 
 | 496 |                             if (in.read() == -1) { | 
 | 497 |                                 break; | 
 | 498 |                             } | 
 | 499 |                         } catch (Exception e) { | 
 | 500 |                             // ignore | 
 | 501 |                         } | 
 | 502 |                         checkpoint(true); | 
 | 503 |                     } | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 504 |                     socket.close(); | 
 | 505 |                 } | 
 | 506 |  | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 507 |                 // Wait for the daemons to create the new state. | 
 | 508 |                 while (!state.exists()) { | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 509 |                     // Check if a running daemon is dead. | 
 | 510 |                     for (int i = 0; i < mDaemons.length; ++i) { | 
 | 511 |                         String daemon = mDaemons[i]; | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 512 |                         if (mArguments[i] != null && !"running".equals( | 
| Chia-chi Yeh | 1f7746b | 2011-07-01 00:29:06 -0700 | [diff] [blame] | 513 |                                 SystemProperties.get("init.svc." + daemon))) { | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 514 |                             throw new IllegalStateException(daemon + " is dead"); | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 515 |                         } | 
 | 516 |                     } | 
 | 517 |                     checkpoint(true); | 
 | 518 |                 } | 
 | 519 |  | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 520 |                 // Now we are connected. Read and parse the new state. | 
 | 521 |                 byte[] buffer = new byte[(int) state.length()]; | 
 | 522 |                 if (new FileInputStream(state).read(buffer) != buffer.length) { | 
 | 523 |                     throw new IllegalStateException("Cannot read the state"); | 
 | 524 |                 } | 
 | 525 |                 String[] parameters = new String(buffer, Charsets.UTF_8).split("\n", -1); | 
 | 526 |                 if (parameters.length != 6) { | 
 | 527 |                     throw new IllegalStateException("Cannot parse the state"); | 
 | 528 |                 } | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 529 |  | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 530 |                 // Set the interface and the addresses in the config. | 
 | 531 |                 mConfig.interfaze = parameters[0].trim(); | 
 | 532 |                 mConfig.addresses = parameters[1].trim(); | 
 | 533 |  | 
 | 534 |                 // Set the routes if they are not set in the config. | 
 | 535 |                 if (mConfig.routes == null || mConfig.routes.isEmpty()) { | 
 | 536 |                     mConfig.routes = parameters[2].trim(); | 
 | 537 |                 } | 
 | 538 |  | 
 | 539 |                 // Set the DNS servers if they are not set in the config. | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 540 |                 if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) { | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 541 |                     String dnsServers = parameters[3].trim(); | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 542 |                     if (!dnsServers.isEmpty()) { | 
 | 543 |                         mConfig.dnsServers = Arrays.asList(dnsServers.split(" ")); | 
 | 544 |                     } | 
 | 545 |                 } | 
 | 546 |  | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 547 |                 // Set the search domains if they are not set in the config. | 
 | 548 |                 if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) { | 
 | 549 |                     String searchDomains = parameters[4].trim(); | 
 | 550 |                     if (!searchDomains.isEmpty()) { | 
 | 551 |                         mConfig.searchDomains = Arrays.asList(searchDomains.split(" ")); | 
 | 552 |                     } | 
 | 553 |                 } | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 554 |  | 
| Chia-chi Yeh | 97a61565 | 2011-07-14 15:05:05 -0700 | [diff] [blame] | 555 |                 // Set the routes. | 
 | 556 |                 jniSetRoutes(mConfig.interfaze, mConfig.routes); | 
 | 557 |  | 
 | 558 |                 // Here is the last step and it must be done synchronously. | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 559 |                 synchronized (Vpn.this) { | 
 | 560 |                     // Check if the thread is interrupted while we are waiting. | 
 | 561 |                     checkpoint(false); | 
 | 562 |  | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 563 |                     // Check if the interface is gone while we are waiting. | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 564 |                     if (jniCheck(mConfig.interfaze) == 0) { | 
| Chia-chi Yeh | 34e7813 | 2011-07-03 03:07:07 -0700 | [diff] [blame] | 565 |                         throw new IllegalStateException(mConfig.interfaze + " is gone"); | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 566 |                     } | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 567 |  | 
 | 568 |                     // Now INetworkManagementEventObserver is watching our back. | 
| Chia-chi Yeh | c2b8aa0 | 2011-07-03 18:00:47 -0700 | [diff] [blame] | 569 |                     mInterface = mConfig.interfaze; | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 570 |                     mCallback.override(mConfig.dnsServers, mConfig.searchDomains); | 
 | 571 |                     showNotification(mConfig, null, null); | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 572 |  | 
 | 573 |                     Log.i(TAG, "Connected!"); | 
 | 574 |                     mInfo.state = LegacyVpnInfo.STATE_CONNECTED; | 
 | 575 |                     mInfo.intent = VpnConfig.getIntentForStatusPanel(mContext, null); | 
| Chia-chi Yeh | 41d1685 | 2011-07-01 02:12:06 -0700 | [diff] [blame] | 576 |                 } | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 577 |             } catch (Exception e) { | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 578 |                 Log.i(TAG, "Aborting", e); | 
| Chia-chi Yeh | e910790 | 2011-07-02 01:48:50 -0700 | [diff] [blame] | 579 |                 exit(); | 
| Chia-chi Yeh | 2e46764 | 2011-07-04 03:23:12 -0700 | [diff] [blame] | 580 |             } finally { | 
 | 581 |                 // Do not leave an unstable state. | 
 | 582 |                 if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING || | 
 | 583 |                         mInfo.state == LegacyVpnInfo.STATE_CONNECTING) { | 
 | 584 |                     mInfo.state = LegacyVpnInfo.STATE_FAILED; | 
 | 585 |                 } | 
| Chia-chi Yeh | 85a7ce0 | 2011-06-29 16:05:58 -0700 | [diff] [blame] | 586 |             } | 
 | 587 |         } | 
 | 588 |     } | 
| Chia-chi Yeh | ff3bdca | 2011-05-23 17:26:46 -0700 | [diff] [blame] | 589 | } |