summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2016-02-29 14:37:51 +0100
committerArne Schwabe <arne@rfc2549.org>2016-02-29 14:37:51 +0100
commit5e078020bfc7a49c8d6011c3c4c184d5593df40a (patch)
tree18bb17fb52d305d708982be99a58df9e7c71370f
parentb3e20603bb687da8a348f1c73d9645f86d159483 (diff)
Refactor the way the VPN is launched, move more of the responsibility to the OpenVPNService.
-rw-r--r--main/src/main/AndroidManifest.xml2
-rw-r--r--main/src/main/java/de/blinkt/openvpn/LaunchVPN.java349
-rw-r--r--main/src/main/java/de/blinkt/openvpn/VpnProfile.java132
-rw-r--r--main/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java5
-rw-r--r--main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java82
-rw-r--r--main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java247
-rw-r--r--main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java8
-rw-r--r--main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java20
-rw-r--r--main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java4
-rw-r--r--main/src/main/res/values-v21/styles.xml1
-rw-r--r--main/src/main/res/values/styles.xml6
11 files changed, 430 insertions, 426 deletions
diff --git a/main/src/main/AndroidManifest.xml b/main/src/main/AndroidManifest.xml
index a6ec8b0a..d4bb0674 100644
--- a/main/src/main/AndroidManifest.xml
+++ b/main/src/main/AndroidManifest.xml
@@ -146,7 +146,7 @@
android:noHistory="true"
android:label="@string/vpn_launch_title"
android:taskAffinity=""
- android:theme="@android:style/Theme.NoDisplay"
+ android:theme="@style/blinkt.dialog"
tools:ignore="ExportedActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java
index 7ac5cc11..26135eac 100644
--- a/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java
+++ b/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java
@@ -34,122 +34,117 @@ import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
/**
* This Activity actually handles two stages of a launcher shortcut's life cycle.
- *
+ * <p/>
* 1. Your application offers to provide shortcuts to the launcher. When
- * the user installs a shortcut, an activity within your application
- * generates the actual shortcut and returns it to the launcher, where it
- * is shown to the user as an icon.
- *
+ * the user installs a shortcut, an activity within your application
+ * generates the actual shortcut and returns it to the launcher, where it
+ * is shown to the user as an icon.
+ * <p/>
* 2. Any time the user clicks on an installed shortcut, an intent is sent.
- * Typically this would then be handled as necessary by an activity within
- * your application.
- *
+ * Typically this would then be handled as necessary by an activity within
+ * your application.
+ * <p/>
* We handle stage 1 (creating a shortcut) by simply sending back the information (in the form
* of an {@link android.content.Intent} that the launcher will use to create the shortcut.
- *
+ * <p/>
* You can also implement this in an interactive way, by having your activity actually present
* UI for the user to select the specific nature of the shortcut, such as a contact, picture, URL,
* media item, or action.
- *
+ * <p/>
* We handle stage 2 (responding to a shortcut) in this sample by simply displaying the contents
* of the incoming {@link android.content.Intent}.
- *
+ * <p/>
* In a real application, you would probably use the shortcut intent to display specific content
* or start a particular operation.
*/
public class LaunchVPN extends Activity {
- public static final String EXTRA_KEY = "de.blinkt.openvpn.shortcutProfileUUID";
- public static final String EXTRA_NAME = "de.blinkt.openvpn.shortcutProfileName";
- public static final String EXTRA_HIDELOG = "de.blinkt.openvpn.showNoLogWindow";
- public static final String CLEARLOG = "clearlogconnect";
+ public static final String EXTRA_KEY = "de.blinkt.openvpn.shortcutProfileUUID";
+ public static final String EXTRA_NAME = "de.blinkt.openvpn.shortcutProfileName";
+ public static final String EXTRA_HIDELOG = "de.blinkt.openvpn.showNoLogWindow";
+ public static final String CLEARLOG = "clearlogconnect";
- private static final int START_VPN_PROFILE= 70;
+ private static final int START_VPN_PROFILE = 70;
- private ProfileManager mPM;
- private VpnProfile mSelectedProfile;
- private boolean mhideLog=false;
+ private VpnProfile mSelectedProfile;
+ private boolean mhideLog = false;
- private boolean mCmfixed=false;
+ private boolean mCmfixed = false;
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
- mPM =ProfileManager.getInstance(this);
- startVpnFromIntent();
- finish();
- }
+ startVpnFromIntent();
+ }
- protected void startVpnFromIntent() {
- // Resolve the intent
+ protected void startVpnFromIntent() {
+ // Resolve the intent
- final Intent intent = getIntent();
- final String action = intent.getAction();
+ final Intent intent = getIntent();
+ final String action = intent.getAction();
- // If the intent is a request to create a shortcut, we'll do that and exit
+ // If the intent is a request to create a shortcut, we'll do that and exit
- if(Intent.ACTION_MAIN.equals(action)) {
- // Check if we need to clear the log
- if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(CLEARLOG, true))
- VpnStatus.clearLog();
+ if (Intent.ACTION_MAIN.equals(action)) {
+ // Check if we need to clear the log
+ if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(CLEARLOG, true))
+ VpnStatus.clearLog();
- // we got called to be the starting point, most likely a shortcut
- String shortcutUUID = intent.getStringExtra( EXTRA_KEY);
- String shortcutName = intent.getStringExtra( EXTRA_NAME);
- mhideLog = intent.getBooleanExtra(EXTRA_HIDELOG, false);
+ // we got called to be the starting point, most likely a shortcut
+ String shortcutUUID = intent.getStringExtra(EXTRA_KEY);
+ String shortcutName = intent.getStringExtra(EXTRA_NAME);
+ mhideLog = intent.getBooleanExtra(EXTRA_HIDELOG, false);
- VpnProfile profileToConnect = ProfileManager.get(this,shortcutUUID);
- if(shortcutName != null && profileToConnect ==null)
- profileToConnect = ProfileManager.getInstance(this).getProfileByName(shortcutName);
+ VpnProfile profileToConnect = ProfileManager.get(this, shortcutUUID);
+ if (shortcutName != null && profileToConnect == null)
+ profileToConnect = ProfileManager.getInstance(this).getProfileByName(shortcutName);
- if(profileToConnect ==null) {
- VpnStatus.logError(R.string.shortcut_profile_notfound);
- // show Log window to display error
- showLogWindow();
- finish();
- return;
- }
-
- mSelectedProfile = profileToConnect;
- launchVPN();
-
- }
- }
+ if (profileToConnect == null) {
+ VpnStatus.logError(R.string.shortcut_profile_notfound);
+ // show Log window to display error
+ showLogWindow();
+ finish();
+ } else {
+ mSelectedProfile = profileToConnect;
+ launchVPN();
+ }
+ }
+ }
- private void askForPW(final int type) {
+ private void askForPW(final int type) {
- final EditText entry = new EditText(this);
+ final EditText entry = new EditText(this);
final View userpwlayout = getLayoutInflater().inflate(R.layout.userpass, null, false);
- entry.setSingleLine();
- entry.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
- entry.setTransformationMethod(new PasswordTransformationMethod());
+ entry.setSingleLine();
+ entry.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ entry.setTransformationMethod(new PasswordTransformationMethod());
- AlertDialog.Builder dialog = new AlertDialog.Builder(this);
- dialog.setTitle(getString(R.string.pw_request_dialog_title, getString(type)));
- dialog.setMessage(getString(R.string.pw_request_dialog_prompt, mSelectedProfile.mName));
+ AlertDialog.Builder dialog = new AlertDialog.Builder(this);
+ dialog.setTitle(getString(R.string.pw_request_dialog_title, getString(type)));
+ dialog.setMessage(getString(R.string.pw_request_dialog_prompt, mSelectedProfile.mName));
if (type == R.string.password) {
- ((EditText)userpwlayout.findViewById(R.id.username)).setText(mSelectedProfile.mUsername);
- ((EditText)userpwlayout.findViewById(R.id.password)).setText(mSelectedProfile.mPassword);
- ((CheckBox)userpwlayout.findViewById(R.id.save_password)).setChecked(!TextUtils.isEmpty(mSelectedProfile.mPassword));
- ((CheckBox)userpwlayout.findViewById(R.id.show_password)).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ ((EditText) userpwlayout.findViewById(R.id.username)).setText(mSelectedProfile.mUsername);
+ ((EditText) userpwlayout.findViewById(R.id.password)).setText(mSelectedProfile.mPassword);
+ ((CheckBox) userpwlayout.findViewById(R.id.save_password)).setChecked(!TextUtils.isEmpty(mSelectedProfile.mPassword));
+ ((CheckBox) userpwlayout.findViewById(R.id.show_password)).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked)
- ((EditText)userpwlayout.findViewById(R.id.password)).setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
+ ((EditText) userpwlayout.findViewById(R.id.password)).setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
else
- ((EditText)userpwlayout.findViewById(R.id.password)).setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ ((EditText) userpwlayout.findViewById(R.id.password)).setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
}
});
dialog.setView(userpwlayout);
} else {
- dialog.setView(entry);
+ dialog.setView(entry);
}
AlertDialog.Builder builder = dialog.setPositiveButton(android.R.string.ok,
@@ -162,9 +157,9 @@ public class LaunchVPN extends Activity {
String pw = ((EditText) userpwlayout.findViewById(R.id.password)).getText().toString();
if (((CheckBox) userpwlayout.findViewById(R.id.save_password)).isChecked()) {
- mSelectedProfile.mPassword=pw;
+ mSelectedProfile.mPassword = pw;
} else {
- mSelectedProfile.mPassword=null;
+ mSelectedProfile.mPassword = null;
mSelectedProfile.mTransientPW = pw;
}
} else {
@@ -176,133 +171,119 @@ public class LaunchVPN extends Activity {
});
dialog.setNegativeButton(android.R.string.cancel,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- VpnStatus.updateStateString("USER_VPN_PASSWORD_CANCELLED", "", R.string.state_user_vpn_password_cancelled,
- ConnectionStatus.LEVEL_NOTCONNECTED);
- finish();
- }
- });
-
- dialog.create().show();
-
- }
- @Override
- protected void onActivityResult (int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- if(requestCode==START_VPN_PROFILE) {
- if(resultCode == Activity.RESULT_OK) {
- int needpw = mSelectedProfile.needUserPWInput(false);
- if(needpw !=0) {
- VpnStatus.updateStateString("USER_VPN_PASSWORD", "", R.string.state_user_vpn_password,
- ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT);
- askForPW(needpw);
- } else {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- boolean showLogWindow = prefs.getBoolean("showlogwindow", true);
-
- if(!mhideLog && showLogWindow)
- showLogWindow();
- new startOpenVpnThread().start();
- }
- } else if (resultCode == Activity.RESULT_CANCELED) {
- // User does not want us to start, so we just vanish
- VpnStatus.updateStateString("USER_VPN_PERMISSION_CANCELLED", "", R.string.state_user_vpn_permission_cancelled,
- ConnectionStatus.LEVEL_NOTCONNECTED);
-
- finish();
- }
- }
- }
- void showLogWindow() {
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ VpnStatus.updateStateString("USER_VPN_PASSWORD_CANCELLED", "", R.string.state_user_vpn_password_cancelled,
+ ConnectionStatus.LEVEL_NOTCONNECTED);
+ finish();
+ }
+ });
- Intent startLW = new Intent(getBaseContext(),LogWindow.class);
- startLW.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
- startActivity(startLW);
+ dialog.create().show();
- }
+ }
- void showConfigErrorDialog(int vpnok) {
- AlertDialog.Builder d = new AlertDialog.Builder(this);
- d.setTitle(R.string.config_error_found);
- d.setMessage(vpnok);
- d.setPositiveButton(android.R.string.ok, new OnClickListener() {
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
+ if (requestCode == START_VPN_PROFILE) {
+ if (resultCode == Activity.RESULT_OK) {
+ int needpw = mSelectedProfile.needUserPWInput(false);
+ if (needpw != 0) {
+ VpnStatus.updateStateString("USER_VPN_PASSWORD", "", R.string.state_user_vpn_password,
+ ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT);
+ askForPW(needpw);
+ } else {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ boolean showLogWindow = prefs.getBoolean("showlogwindow", true);
+
+ if (!mhideLog && showLogWindow)
+ showLogWindow();
+ VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext());
+ finish();
+ }
+ } else if (resultCode == Activity.RESULT_CANCELED) {
+ // User does not want us to start, so we just vanish
+ VpnStatus.updateStateString("USER_VPN_PERMISSION_CANCELLED", "", R.string.state_user_vpn_permission_cancelled,
+ ConnectionStatus.LEVEL_NOTCONNECTED);
- }
- });
- d.show();
- }
+ finish();
+ }
+ }
+ }
- void launchVPN () {
- int vpnok = mSelectedProfile.checkProfile(this);
- if(vpnok!= R.string.no_error_found) {
- showConfigErrorDialog(vpnok);
- return;
- }
+ void showLogWindow() {
- Intent intent = VpnService.prepare(this);
- // Check if we want to fix /dev/tun
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- boolean usecm9fix = prefs.getBoolean("useCM9Fix", false);
- boolean loadTunModule = prefs.getBoolean("loadTunModule", false);
+ Intent startLW = new Intent(getBaseContext(), LogWindow.class);
+ startLW.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+ startActivity(startLW);
- if(loadTunModule)
- execeuteSUcmd("insmod /system/lib/modules/tun.ko");
+ }
- if(usecm9fix && !mCmfixed ) {
- execeuteSUcmd("chown system /dev/tun");
- }
+ void showConfigErrorDialog(int vpnok) {
+ AlertDialog.Builder d = new AlertDialog.Builder(this);
+ d.setTitle(R.string.config_error_found);
+ d.setMessage(vpnok);
+ d.setPositiveButton(android.R.string.ok, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
- if (intent != null) {
- VpnStatus.updateStateString("USER_VPN_PERMISSION", "", R.string.state_user_vpn_permission,
- ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT);
- // Start the query
- try {
- startActivityForResult(intent, START_VPN_PROFILE);
- } catch (ActivityNotFoundException ane) {
- // Shame on you Sony! At least one user reported that
- // an official Sony Xperia Arc S image triggers this exception
- VpnStatus.logError(R.string.no_vpn_support_image);
- showLogWindow();
- }
- } else {
- onActivityResult(START_VPN_PROFILE, Activity.RESULT_OK, null);
- }
-
- }
-
- private void execeuteSUcmd(String command) {
- ProcessBuilder pb = new ProcessBuilder("su","-c",command);
- try {
- Process p = pb.start();
- int ret = p.waitFor();
- if(ret ==0)
- mCmfixed=true;
- } catch (InterruptedException e) {
- VpnStatus.logException("SU command", e);
+ }
+ });
+ d.show();
+ }
- } catch (IOException e) {
- VpnStatus.logException("SU command", e);
- }
- }
+ void launchVPN() {
+ int vpnok = mSelectedProfile.checkProfile(this);
+ if (vpnok != R.string.no_error_found) {
+ showConfigErrorDialog(vpnok);
+ return;
+ }
- private class startOpenVpnThread extends Thread {
+ Intent intent = VpnService.prepare(this);
+ // Check if we want to fix /dev/tun
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ boolean usecm9fix = prefs.getBoolean("useCM9Fix", false);
+ boolean loadTunModule = prefs.getBoolean("loadTunModule", false);
- @Override
- public void run() {
- VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext());
- finish();
+ if (loadTunModule)
+ execeuteSUcmd("insmod /system/lib/modules/tun.ko");
- }
+ if (usecm9fix && !mCmfixed) {
+ execeuteSUcmd("chown system /dev/tun");
+ }
- }
+ if (intent != null) {
+ VpnStatus.updateStateString("USER_VPN_PERMISSION", "", R.string.state_user_vpn_permission,
+ ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT);
+ // Start the query
+ try {
+ startActivityForResult(intent, START_VPN_PROFILE);
+ } catch (ActivityNotFoundException ane) {
+ // Shame on you Sony! At least one user reported that
+ // an official Sony Xperia Arc S image triggers this exception
+ VpnStatus.logError(R.string.no_vpn_support_image);
+ showLogWindow();
+ }
+ } else {
+ onActivityResult(START_VPN_PROFILE, Activity.RESULT_OK, null);
+ }
+ }
+ private void execeuteSUcmd(String command) {
+ try {
+ ProcessBuilder pb = new ProcessBuilder("su", "-c", command);
+ Process p = pb.start();
+ int ret = p.waitFor();
+ if (ret == 0)
+ mCmfixed = true;
+ } catch (InterruptedException | IOException e) {
+ VpnStatus.logException("SU command", e);
+ }
+ }
}
diff --git a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java
index 5ef95b6e..9d4e8588 100644
--- a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java
+++ b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java
@@ -62,7 +62,7 @@ public class VpnProfile implements Serializable, Cloneable {
// The Serializable documentation mentions that class name change are possible
// but the how is unclear
//
- transient public static final long MAX_EMBED_FILE_SIZE = 2048*1024; // 2048kB
+ transient public static final long MAX_EMBED_FILE_SIZE = 2048 * 1024; // 2048kB
// Don't change this, not all parts of the program use this constant
public static final String EXTRA_PROFILEUUID = "de.blinkt.openvpn.profileUUID";
public static final String INLINE_TAG = "[[INLINE]]";
@@ -148,15 +148,15 @@ public class VpnProfile implements Serializable, Cloneable {
private int mProfileVersion;
public String mExcludedRoutes;
public String mExcludedRoutesv6;
- public int mMssFix =0; // -1 is default,
+ public int mMssFix = 0; // -1 is default,
public Connection[] mConnections = new Connection[0];
- public boolean mRemoteRandom=false;
+ public boolean mRemoteRandom = false;
public HashSet<String> mAllowedAppsVpn = new HashSet<>();
public boolean mAllowedAppsVpnAreDisallowed = true;
public String mProfileCreator;
- public boolean mPushPeerInfo=false;
+ public boolean mPushPeerInfo = false;
public static final boolean mIsOpenVPN22 = false;
/* Options no longer used in new profiles */
@@ -170,7 +170,7 @@ public class VpnProfile implements Serializable, Cloneable {
mProfileVersion = CURRENT_PROFILE_VERSION;
mConnections = new Connection[1];
- mConnections[0] = new Connection();
+ mConnections[0] = new Connection();
}
public static String openVpnEscape(String unescaped) {
@@ -198,7 +198,7 @@ public class VpnProfile implements Serializable, Cloneable {
mCheckRemoteCN = false;
mPersistTun = false;
mAllowLocalLAN = true;
- mPushPeerInfo =false;
+ mPushPeerInfo = false;
mMssFix = 0;
}
@@ -208,33 +208,33 @@ public class VpnProfile implements Serializable, Cloneable {
}
public String getName() {
- if (mName==null)
+ if (mName == null)
return "No profile name";
return mName;
}
- public void upgradeProfile(){
- if(mProfileVersion< 2) {
+ public void upgradeProfile() {
+ if (mProfileVersion < 2) {
/* default to the behaviour the OS used */
mAllowLocalLAN = Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT;
}
if (mProfileVersion < 4) {
moveOptionsToConnection();
- mAllowedAppsVpnAreDisallowed=true;
+ mAllowedAppsVpnAreDisallowed = true;
}
- if (mAllowedAppsVpn==null)
+ if (mAllowedAppsVpn == null)
mAllowedAppsVpn = new HashSet<>();
- if (mConnections ==null)
+ if (mConnections == null)
mConnections = new Connection[0];
if (mProfileVersion < 6) {
if (TextUtils.isEmpty(mProfileCreator))
- mUserEditable=true;
+ mUserEditable = true;
}
- mProfileVersion= CURRENT_PROFILE_VERSION;
+ mProfileVersion = CURRENT_PROFILE_VERSION;
}
@@ -272,7 +272,7 @@ public class VpnProfile implements Serializable, Cloneable {
cfg += String.format("setenv IV_GUI_VER %s \n", openVpnEscape(getVersionEnvString(context)));
String versionString = String.format("%d %s %s %s %s %s", Build.VERSION.SDK_INT, Build.VERSION.RELEASE,
NativeUtils.getNativeAPI(), Build.BRAND, Build.BOARD, Build.MODEL);
- cfg += String.format("setenv IV_PLAT_VER %s\n", openVpnEscape(versionString)) ;
+ cfg += String.format("setenv IV_PLAT_VER %s\n", openVpnEscape(versionString));
}
cfg += "machine-readable-output\n";
@@ -317,7 +317,7 @@ public class VpnProfile implements Serializable, Cloneable {
boolean canUsePlainRemotes = true;
- if (mConnections.length==1) {
+ if (mConnections.length == 1) {
cfg += mConnections[0].getConnectionBlock();
} else {
for (Connection conn : mConnections) {
@@ -325,7 +325,7 @@ public class VpnProfile implements Serializable, Cloneable {
}
if (mRemoteRandom)
- cfg+="remote-random\n";
+ cfg += "remote-random\n";
if (canUsePlainRemotes) {
for (Connection conn : mConnections) {
@@ -413,13 +413,12 @@ public class VpnProfile implements Serializable, Cloneable {
if (mUseDefaultRoute)
routes += "route 0.0.0.0 0.0.0.0 vpn_gateway\n";
- else
- {
+ else {
for (String route : getCustomRoutes(mCustomRoutes)) {
routes += "route " + route + " vpn_gateway\n";
}
- for (String route: getCustomRoutes(mExcludedRoutes)) {
+ for (String route : getCustomRoutes(mExcludedRoutes)) {
routes += "route " + route + " net_gateway\n";
}
}
@@ -444,11 +443,11 @@ public class VpnProfile implements Serializable, Cloneable {
}
- if (mMssFix !=0){
- if (mMssFix!=1450) {
+ if (mMssFix != 0) {
+ if (mMssFix != 1450) {
cfg += String.format("mssfix %d\n", mMssFix, Locale.US);
} else
- cfg+="mssfix\n";
+ cfg += "mssfix\n";
}
if (mNobind)
@@ -509,7 +508,7 @@ public class VpnProfile implements Serializable, Cloneable {
}
if (mPushPeerInfo)
- cfg+="push-peer-info\n";
+ cfg += "push-peer-info\n";
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean usesystemproxy = prefs.getBoolean("usesystemproxy", true);
@@ -539,8 +538,6 @@ public class VpnProfile implements Serializable, Cloneable {
}
-
-
return cfg;
}
@@ -630,39 +627,32 @@ public class VpnProfile implements Serializable, Cloneable {
}
-
-
public Intent prepareStartService(Context context) {
Intent intent = getStartServiceIntent(context);
+ // TODO: Handle this?!
+// if (mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) {
+// if (getKeyStoreCertificates(context) == null)
+// return null;
+// }
- if (mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) {
- if (getKeyStoreCertificates(context) == null)
- return null;
- }
-
+ return intent;
+ }
- try {
- FileWriter cfg = new FileWriter(VPNLaunchHelper.getConfigFilePath(context));
- cfg.write(getConfigFile(context, false));
- cfg.flush();
- cfg.close();
- } catch (IOException e) {
- VpnStatus.logException(e);
- }
+ public void writeConfigFile(Context context) throws IOException {
+ FileWriter cfg = new FileWriter(VPNLaunchHelper.getConfigFilePath(context));
+ cfg.write(getConfigFile(context, false));
+ cfg.flush();
+ cfg.close();
- return intent;
}
public Intent getStartServiceIntent(Context context) {
String prefix = context.getPackageName();
Intent intent = new Intent(context, OpenVPNService.class);
- intent.putExtra(prefix + ".ARGV", VPNLaunchHelper.buildOpenvpnArgv(context));
intent.putExtra(prefix + ".profileUUID", mUuid.toString());
- ApplicationInfo info = context.getApplicationInfo();
- intent.putExtra(prefix + ".nativelib", info.nativeLibraryDir);
return intent;
}
@@ -673,11 +663,10 @@ public class VpnProfile implements Serializable, Cloneable {
public static String getDisplayName(String embeddedFile) {
int start = DISPLAYNAME_TAG.length();
int end = embeddedFile.indexOf(INLINE_TAG);
- return embeddedFile.substring(start,end);
+ return embeddedFile.substring(start, end);
}
- public static String getEmbeddedContent(String data)
- {
+ public static String getEmbeddedContent(String data) {
if (!data.contains(INLINE_TAG))
return data;
@@ -686,7 +675,7 @@ public class VpnProfile implements Serializable, Cloneable {
}
public static boolean isEmbedded(String data) {
- if (data==null)
+ if (data == null)
return false;
if (data.startsWith(INLINE_TAG) || data.startsWith(DISPLAYNAME_TAG))
return true;
@@ -698,8 +687,8 @@ public class VpnProfile implements Serializable, Cloneable {
/* This method is called when OpenVPNService is restarted */
if ((mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE)
- && mPrivateKey==null) {
- new Thread( new Runnable() {
+ && mPrivateKey == null) {
+ new Thread(new Runnable() {
@Override
public void run() {
getKeyStoreCertificates(context);
@@ -714,9 +703,9 @@ public class VpnProfile implements Serializable, Cloneable {
VpnProfile copy = (VpnProfile) super.clone();
copy.mUuid = UUID.randomUUID();
copy.mConnections = new Connection[mConnections.length];
- int i=0;
- for (Connection conn: mConnections) {
- copy.mConnections[i++]=conn.clone();
+ int i = 0;
+ for (Connection conn : mConnections) {
+ copy.mConnections[i++] = conn.clone();
}
copy.mAllowedAppsVpn = (HashSet<String>) mAllowedAppsVpn.clone();
return copy;
@@ -736,12 +725,12 @@ public class VpnProfile implements Serializable, Cloneable {
class NoCertReturnedException extends Exception {
- public NoCertReturnedException (String msg) {
+ public NoCertReturnedException(String msg) {
super(msg);
}
}
- synchronized String[] getKeyStoreCertificates(Context context,int tries) {
+ synchronized String[] getKeyStoreCertificates(Context context, int tries) {
try {
PrivateKey privateKey = KeyChain.getPrivateKey(context, mAlias);
mPrivateKey = privateKey;
@@ -750,7 +739,7 @@ public class VpnProfile implements Serializable, Cloneable {
X509Certificate[] caChain = KeyChain.getCertificateChain(context, mAlias);
- if(caChain == null)
+ if (caChain == null)
throw new NoCertReturnedException("No certificate returned from Keystore");
if (caChain.length <= 1 && TextUtils.isEmpty(mCaFilename)) {
@@ -775,10 +764,10 @@ public class VpnProfile implements Serializable, Cloneable {
StringWriter caoutWriter = new StringWriter();
PemWriter pw = new PemWriter(caoutWriter);
- for (Certificate cert: cacerts)
+ for (Certificate cert : cacerts)
pw.writeObject(new PemObject("CERTIFICATE", cert.getEncoded()));
pw.close();
- caout= caoutWriter.toString();
+ caout = caoutWriter.toString();
} catch (Exception e) {
VpnStatus.logError("Could not read CA certificate" + e.getLocalizedMessage());
@@ -801,12 +790,12 @@ public class VpnProfile implements Serializable, Cloneable {
String ca, extra;
- if(caout==null) {
- ca =keystoreChain;
- extra=null;
+ if (caout == null) {
+ ca = keystoreChain;
+ extra = null;
} else {
ca = caout;
- extra=keystoreChain;
+ extra = keystoreChain;
}
return new String[]{ca, extra, user};
@@ -824,15 +813,15 @@ public class VpnProfile implements Serializable, Cloneable {
return null;
} catch (AssertionError e) {
- if (tries ==0)
+ if (tries == 0)
return null;
- VpnStatus.logError(String.format("Failure getting Keystore Keys (%s), retrying",e.getLocalizedMessage()));
+ VpnStatus.logError(String.format("Failure getting Keystore Keys (%s), retrying", e.getLocalizedMessage()));
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
VpnStatus.logException(e1);
}
- return getKeyStoreCertificates(context, tries-1);
+ return getKeyStoreCertificates(context, tries - 1);
}
}
@@ -849,10 +838,10 @@ public class VpnProfile implements Serializable, Cloneable {
return R.string.ipv4_format_error;
}
if (!mUseDefaultRoute) {
- if (!TextUtils.isEmpty(mCustomRoutes) && getCustomRoutes(mCustomRoutes).size() == 0 )
+ if (!TextUtils.isEmpty(mCustomRoutes) && getCustomRoutes(mCustomRoutes).size() == 0)
return R.string.custom_route_format_error;
- if (!TextUtils.isEmpty(mExcludedRoutes) && getCustomRoutes(mExcludedRoutes).size() == 0 )
+ if (!TextUtils.isEmpty(mExcludedRoutes) && getCustomRoutes(mExcludedRoutes).size() == 0)
return R.string.custom_route_format_error;
}
@@ -865,17 +854,16 @@ public class VpnProfile implements Serializable, Cloneable {
return R.string.missing_certificates;
if (!(mAuthenticationType == TYPE_KEYSTORE || mAuthenticationType == TYPE_USERPASS_KEYSTORE)
- && TextUtils.isEmpty(mCaFilename))
+ && TextUtils.isEmpty(mCaFilename))
return R.string.missing_ca_certificate;
-
boolean noRemoteEnabled = true;
for (Connection c : mConnections)
if (c.mEnabled)
noRemoteEnabled = false;
- if(noRemoteEnabled)
+ if (noRemoteEnabled)
return R.string.remote_no_server_selected;
// Everything okay
@@ -970,7 +958,7 @@ public class VpnProfile implements Serializable, Cloneable {
if (isUserPWAuth() &&
(TextUtils.isEmpty(mUsername) ||
- (TextUtils.isEmpty(mPassword) && (mTransientPW == null || ignoreTransient)))) {
+ (TextUtils.isEmpty(mPassword) && (mTransientPW == null || ignoreTransient)))) {
return R.string.password;
}
return 0;
diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java
index 2771fa6a..85c1d526 100644
--- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java
+++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java
@@ -24,7 +24,10 @@ public interface OpenVPNManagement {
void resume();
- boolean stopVPN();
+ /**
+ * @param replaceConnection True if the VPN is connected by a new connection.
+ */
+ boolean stopVPN(boolean replaceConnection);
/*
* Rebind the interface
diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
index 7dc93674..d2a21946 100644
--- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
+++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
@@ -32,6 +32,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
+import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Inet6Address;
@@ -115,7 +116,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
@Override
public void onRevoke() {
VpnStatus.logInfo(R.string.permission_revoked);
- mManagement.stopVPN();
+ mManagement.stopVPN(false);
endVpnService();
}
@@ -184,13 +185,13 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
startForeground(OPENVPN_STATUS, notification);
// Check if running on a TV
- if(runningOnAndroidTV() && !lowpriority)
+ if (runningOnAndroidTV() && !lowpriority)
guiHandler.post(new Runnable() {
@Override
public void run() {
- if (mlastToast!=null)
+ if (mlastToast != null)
mlastToast.cancel();
String toastText = String.format(Locale.getDefault(), "%s - %s", mProfile.mName, msg);
mlastToast = Toast.makeText(getBaseContext(), toastText, Toast.LENGTH_SHORT);
@@ -377,21 +378,49 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
mProfile = ProfileManager.get(this, profileUUID);
}
+ /* start the OpenVPN process itself in a background thread */
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ startOpenVPN();
+ }
+ }).start();
+
+
+ ProfileManager.setConnectedVpnProfile(this, mProfile);
+ /* TODO: At the moment we have no way to handle asynchronous PW input
+ * Fixing will also allow to handle challenge/response authentication */
+ if (mProfile.needUserPWInput(true) != 0)
+ return START_NOT_STICKY;
+
+ return START_STICKY;
+ }
+
+ private void startOpenVPN() {
+ VpnStatus.logInfo(R.string.building_configration);
+ VpnStatus.updateStateString("VPN_GENERATE_CONFIG", "", R.string.building_configration, VpnStatus.ConnectionStatus.LEVEL_START);
+
+
+ try {
+ mProfile.writeConfigFile(this);
+ } catch (IOException e) {
+ VpnStatus.logException("Error writing config file", e);
+ endVpnService();
+ return;
+ }
// Extract information from the intent.
String prefix = getPackageName();
- String[] argv = intent.getStringArrayExtra(prefix + ".ARGV");
- String nativeLibraryDirectory = intent.getStringExtra(prefix + ".nativelib");
+ String nativeLibraryDirectory = getApplicationInfo().nativeLibraryDir;
+
+ // Also writes OpenVPN binary
+ String[] argv = VPNLaunchHelper.buildOpenvpnArgv(this);
- String startTitle = getString(R.string.start_vpn_title, mProfile.mName);
- String startTicker = getString(R.string.start_vpn_ticker, mProfile.mName);
- showNotification(startTitle, startTicker,
- false, 0, LEVEL_CONNECTING_NO_SERVER_REPLY_YET);
// Set a flag that we are starting a new VPN
mStarting = true;
// Stop the previous session by interrupting the thread.
- if (mManagement != null && mManagement.stopVPN())
+ if (mManagement != null && mManagement.stopVPN(true))
// an old was asked to exit, wait 1s
try {
Thread.sleep(1000);
@@ -432,11 +461,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
mManagement = ovpnManagementThread;
VpnStatus.logInfo("started Socket Thread");
} else {
- return START_NOT_STICKY;
+ endVpnService();
+ return;
}
}
-
Runnable processThread;
if (mOvpn3) {
@@ -454,19 +483,16 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
mProcessThread = new Thread(processThread, "OpenVPNProcessThread");
mProcessThread.start();
}
- if (mDeviceStateReceiver != null)
- unregisterDeviceStateReceiver();
-
- registerDeviceStateReceiver(mManagement);
+ new Handler(getMainLooper()).post(new Runnable() {
+ @Override
+ public void run() {
+ if (mDeviceStateReceiver != null)
+ unregisterDeviceStateReceiver();
- ProfileManager.setConnectedVpnProfile(this, mProfile);
- /* TODO: At the moment we have no way to handle asynchronous PW input
- * Fixing will also allow to handle challenge/response authentication */
- if (mProfile.needUserPWInput(true) != 0)
- return START_NOT_STICKY;
-
- return START_STICKY;
+ registerDeviceStateReceiver(mManagement);
+ }
+ });
}
private OpenVPNManagement instantiateOpenVPN3Core() {
@@ -474,7 +500,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
Class cl = Class.forName("de.blinkt.openvpn.core.OpenVPNThreadv3");
return (OpenVPNManagement) cl.getConstructor(OpenVPNService.class, VpnProfile.class).newInstance(this, mProfile);
} catch (IllegalArgumentException | InstantiationException | InvocationTargetException |
- NoSuchMethodException | ClassNotFoundException | IllegalAccessException e ) {
+ NoSuchMethodException | ClassNotFoundException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
@@ -484,7 +510,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
public void onDestroy() {
synchronized (mProcessLock) {
if (mProcessThread != null) {
- mManagement.stopVPN();
+ mManagement.stopVPN(true);
}
}
@@ -580,7 +606,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
// Check if the first DNS Server is in the VPN range
try {
ipAddress dnsServer = new ipAddress(new CIDRIP(mDnslist.get(0), 32), true);
- boolean dnsIncluded=false;
+ boolean dnsIncluded = false;
for (ipAddress net : positiveIPv4Routes) {
if (net.containsNet(dnsServer)) {
dnsIncluded = true;
@@ -619,8 +645,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
-
-
if (mDomain != null)
builder.addSearchDomain(mDomain);
@@ -715,7 +739,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setAllowedVpnPackages(Builder builder) {
- boolean atLeastOneAllowedApp=false;
+ boolean atLeastOneAllowedApp = false;
for (String pkg : mProfile.mAllowedAppsVpn) {
try {
if (mProfile.mAllowedAppsVpnAreDisallowed) {
diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java
index baffaffc..fabe7e3e 100644
--- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java
+++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java
@@ -34,51 +34,50 @@ public class OpenVPNThread implements Runnable {
@SuppressLint("SdCardPath")
private static final String BROKEN_PIE_SUPPORT = "/data/data/de.blinkt.openvpn/cache/pievpn";
private final static String BROKEN_PIE_SUPPORT2 = "syntax error";
- private static final String TAG = "OpenVPN";
+ private static final String TAG = "OpenVPN";
public static final int M_FATAL = (1 << 4);
public static final int M_NONFATAL = (1 << 5);
public static final int M_WARN = (1 << 6);
public static final int M_DEBUG = (1 << 7);
private String[] mArgv;
- private Process mProcess;
- private String mNativeDir;
- private OpenVPNService mService;
- private String mDumpPath;
- private Map<String, String> mProcessEnv;
- private boolean mBrokenPie=false;
-
- public OpenVPNThread(OpenVPNService service,String[] argv, Map<String,String> processEnv, String nativelibdir)
- {
- mArgv = argv;
- mNativeDir = nativelibdir;
- mService = service;
- mProcessEnv = processEnv;
- }
-
- public void stopProcess() {
- mProcess.destroy();
- }
-
- @Override
- public void run() {
- try {
- Log.i(TAG, "Starting openvpn");
- startOpenVPNThreadArgs(mArgv, mProcessEnv);
- Log.i(TAG, "Giving up");
- } catch (Exception e) {
- VpnStatus.logException("Starting OpenVPN Thread" ,e);
- Log.e(TAG, "OpenVPNThread Got " + e.toString());
- } finally {
- int exitvalue = 0;
- try {
- if (mProcess!=null)
- exitvalue = mProcess.waitFor();
- } catch ( IllegalThreadStateException ite) {
- VpnStatus.logError("Illegal Thread state: " + ite.getLocalizedMessage());
- } catch (InterruptedException ie) {
- VpnStatus.logError("InterruptedException: " + ie.getLocalizedMessage());
- }
- if( exitvalue != 0) {
+ private Process mProcess;
+ private String mNativeDir;
+ private OpenVPNService mService;
+ private String mDumpPath;
+ private Map<String, String> mProcessEnv;
+ private boolean mBrokenPie = false;
+
+ public OpenVPNThread(OpenVPNService service, String[] argv, Map<String, String> processEnv, String nativelibdir) {
+ mArgv = argv;
+ mNativeDir = nativelibdir;
+ mService = service;
+ mProcessEnv = processEnv;
+ }
+
+ public void stopProcess() {
+ mProcess.destroy();
+ }
+
+ @Override
+ public void run() {
+ try {
+ Log.i(TAG, "Starting openvpn");
+ startOpenVPNThreadArgs(mArgv, mProcessEnv);
+ Log.i(TAG, "Giving up");
+ } catch (Exception e) {
+ VpnStatus.logException("Starting OpenVPN Thread", e);
+ Log.e(TAG, "OpenVPNThread Got " + e.toString());
+ } finally {
+ int exitvalue = 0;
+ try {
+ if (mProcess != null)
+ exitvalue = mProcess.waitFor();
+ } catch (IllegalThreadStateException ite) {
+ VpnStatus.logError("Illegal Thread state: " + ite.getLocalizedMessage());
+ } catch (InterruptedException ie) {
+ VpnStatus.logError("InterruptedException: " + ie.getLocalizedMessage());
+ }
+ if (exitvalue != 0) {
VpnStatus.logError("Process exited with exit value " + exitvalue);
if (mBrokenPie) {
/* This will probably fail since the NoPIE binary is probably not written */
@@ -95,70 +94,70 @@ public class OpenVPNThread implements Runnable {
}
}
-
- VpnStatus.updateStateString("NOPROCESS", "No process running.", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED);
- if(mDumpPath!=null) {
- try {
- BufferedWriter logout = new BufferedWriter(new FileWriter(mDumpPath + ".log"));
- SimpleDateFormat timeformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.GERMAN);
- for(LogItem li : VpnStatus.getlogbuffer()){
- String time = timeformat.format(new Date(li.getLogtime()));
- logout.write(time +" " + li.getString(mService) + "\n");
- }
- logout.close();
- VpnStatus.logError(R.string.minidump_generated);
- } catch (IOException e) {
- VpnStatus.logError("Writing minidump log: " + e.getLocalizedMessage());
- }
- }
-
- mService.processDied();
- Log.i(TAG, "Exiting");
- }
- }
-
- private void startOpenVPNThreadArgs(String[] argv, Map<String, String> env) {
- LinkedList<String> argvlist = new LinkedList<String>();
+
+ VpnStatus.updateStateString("NOPROCESS", "No process running.", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED);
+ if (mDumpPath != null) {
+ try {
+ BufferedWriter logout = new BufferedWriter(new FileWriter(mDumpPath + ".log"));
+ SimpleDateFormat timeformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.GERMAN);
+ for (LogItem li : VpnStatus.getlogbuffer()) {
+ String time = timeformat.format(new Date(li.getLogtime()));
+ logout.write(time + " " + li.getString(mService) + "\n");
+ }
+ logout.close();
+ VpnStatus.logError(R.string.minidump_generated);
+ } catch (IOException e) {
+ VpnStatus.logError("Writing minidump log: " + e.getLocalizedMessage());
+ }
+ }
+
+ mService.processDied();
+ Log.i(TAG, "Exiting");
+ }
+ }
+
+ private void startOpenVPNThreadArgs(String[] argv, Map<String, String> env) {
+ LinkedList<String> argvlist = new LinkedList<String>();
Collections.addAll(argvlist, argv);
-
- ProcessBuilder pb = new ProcessBuilder(argvlist);
- // Hack O rama
-
- String lbpath = genLibraryPath(argv, pb);
-
- pb.environment().put("LD_LIBRARY_PATH", lbpath);
-
- // Add extra variables
- for(Entry<String,String> e:env.entrySet()){
- pb.environment().put(e.getKey(), e.getValue());
- }
- pb.redirectErrorStream(true);
- try {
- mProcess = pb.start();
- // Close the output, since we don't need it
- mProcess.getOutputStream().close();
- InputStream in = mProcess.getInputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(in));
-
- while(true) {
- String logline = br.readLine();
- if(logline==null)
- return;
-
- if (logline.startsWith(DUMP_PATH_STRING))
- mDumpPath = logline.substring(DUMP_PATH_STRING.length());
+
+ ProcessBuilder pb = new ProcessBuilder(argvlist);
+ // Hack O rama
+
+ String lbpath = genLibraryPath(argv, pb);
+
+ pb.environment().put("LD_LIBRARY_PATH", lbpath);
+
+ // Add extra variables
+ for (Entry<String, String> e : env.entrySet()) {
+ pb.environment().put(e.getKey(), e.getValue());
+ }
+ pb.redirectErrorStream(true);
+ try {
+ mProcess = pb.start();
+ // Close the output, since we don't need it
+ mProcess.getOutputStream().close();
+ InputStream in = mProcess.getInputStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
+
+ while (true) {
+ String logline = br.readLine();
+ if (logline == null)
+ return;
+
+ if (logline.startsWith(DUMP_PATH_STRING))
+ mDumpPath = logline.substring(DUMP_PATH_STRING.length());
if (logline.startsWith(BROKEN_PIE_SUPPORT) || logline.contains(BROKEN_PIE_SUPPORT2))
mBrokenPie = true;
-
+
// 1380308330.240114 18000002 Send to HTTP proxy: 'X-Online-Host: bla.blabla.com'
Pattern p = Pattern.compile("(\\d+).(\\d+) ([0-9a-f])+ (.*)");
Matcher m = p.matcher(logline);
- if(m.matches()) {
- int flags = Integer.parseInt(m.group(3),16);
+ if (m.matches()) {
+ int flags = Integer.parseInt(m.group(3), 16);
String msg = m.group(4);
int logLevel = flags & 0x0F;
@@ -166,45 +165,45 @@ public class OpenVPNThread implements Runnable {
if ((flags & M_FATAL) != 0)
logStatus = VpnStatus.LogLevel.ERROR;
- else if ((flags & M_NONFATAL)!=0)
+ else if ((flags & M_NONFATAL) != 0)
logStatus = VpnStatus.LogLevel.WARNING;
- else if ((flags & M_WARN)!=0)
+ else if ((flags & M_WARN) != 0)
logStatus = VpnStatus.LogLevel.WARNING;
- else if ((flags & M_DEBUG)!=0)
+ else if ((flags & M_DEBUG) != 0)
logStatus = VpnStatus.LogLevel.VERBOSE;
if (msg.startsWith("MANAGEMENT: CMD"))
logLevel = Math.max(4, logLevel);
- VpnStatus.logMessageOpenVPN(logStatus,logLevel,msg);
+ VpnStatus.logMessageOpenVPN(logStatus, logLevel, msg);
} else {
VpnStatus.logInfo("P:" + logline);
}
- }
-
-
- } catch (IOException e) {
- VpnStatus.logException("Error reading from output of OpenVPN process" , e);
- stopProcess();
- }
-
-
- }
-
- private String genLibraryPath(String[] argv, ProcessBuilder pb) {
- // Hack until I find a good way to get the real library path
- String applibpath = argv[0].replaceFirst("/cache/.*$" , "/lib");
-
- String lbpath = pb.environment().get("LD_LIBRARY_PATH");
- if(lbpath==null)
- lbpath = applibpath;
- else
- lbpath = applibpath + ":" + lbpath;
-
- if (!applibpath.equals(mNativeDir)) {
- lbpath = mNativeDir + ":" + lbpath;
- }
- return lbpath;
- }
+ }
+
+
+ } catch (IOException e) {
+ VpnStatus.logException("Error reading from output of OpenVPN process", e);
+ stopProcess();
+ }
+
+
+ }
+
+ private String genLibraryPath(String[] argv, ProcessBuilder pb) {
+ // Hack until I find a good way to get the real library path
+ String applibpath = argv[0].replaceFirst("/cache/.*$", "/lib");
+
+ String lbpath = pb.environment().get("LD_LIBRARY_PATH");
+ if (lbpath == null)
+ lbpath = applibpath;
+ else
+ lbpath = applibpath + ":" + lbpath;
+
+ if (!applibpath.equals(mNativeDir)) {
+ lbpath = mNativeDir + ":" + lbpath;
+ }
+ return lbpath;
+ }
}
diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
index 44426e97..1004ab00 100644
--- a/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
+++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
@@ -49,6 +49,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
private pauseReason lastPauseReason = pauseReason.noNetwork;
private PausedStateCallback mPauseCallback;
+ private boolean mShuttingDown;
public OpenVpnManagementThread(VpnProfile profile, OpenVPNService openVpnService) {
mProfile = profile;
@@ -223,7 +224,8 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
processByteCount(argument);
break;
case "STATE":
- processState(argument);
+ if (!mShuttingDown)
+ processState(argument);
break;
case "PROXY":
processProxyCMD(argument);
@@ -621,7 +623,9 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
}
@Override
- public boolean stopVPN() {
+ public boolean stopVPN(boolean replaceConnection) {
+ mShuttingDown = true;
return stopOpenVPN();
}
+
}
diff --git a/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java b/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java
index 7d0f6578..564ee1a4 100644
--- a/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java
+++ b/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java
@@ -27,7 +27,7 @@ public class VPNLaunchHelper {
- static private String writeMiniVPN(Context context) {
+ private static String writeMiniVPN(Context context) {
String[] abis;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
abis = getSupportedABIsLollipop();
@@ -73,12 +73,18 @@ public class VPNLaunchHelper {
}
- public static String[] buildOpenvpnArgv(Context c) {
+ static String[] buildOpenvpnArgv(Context c) {
Vector<String> args = new Vector<>();
+ String binaryName = writeMiniVPN(c);
// Add fixed paramenters
//args.add("/data/data/de.blinkt.openvpn/lib/openvpn");
- args.add(writeMiniVPN(c));
+ if(binaryName==null) {
+ VpnStatus.logError("Error writing minivpn binary");
+ return null;
+ }
+
+ args.add(binaryName);
args.add("--config");
args.add(getConfigFilePath(c));
@@ -126,14 +132,6 @@ public class VPNLaunchHelper {
public static void startOpenVpn(VpnProfile startprofile, Context context) {
- VpnStatus.logInfo(R.string.building_configration);
- VpnStatus.updateStateString("VPN_GENERATE_CONFIG", "", R.string.building_configration, VpnStatus.ConnectionStatus.LEVEL_START);
- if(writeMiniVPN(context)==null) {
- VpnStatus.logError("Error writing minivpn binary");
- return;
- }
-
-
Intent startVPN = startprofile.prepareStartService(context);
if(startVPN!=null)
context.startService(startVPN);
diff --git a/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java b/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
index 168dd080..bae94624 100644
--- a/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
+++ b/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
@@ -622,8 +622,8 @@ public class VpnStatus {
public static synchronized void updateByteCount(long in, long out) {
long lastIn = mlastByteCount[0];
long lastOut = mlastByteCount[1];
- long diffIn = mlastByteCount[2] = in - lastIn;
- long diffOut = mlastByteCount[3] = out - lastOut;
+ long diffIn = mlastByteCount[2] = Math.max(0, in - lastIn);
+ long diffOut = mlastByteCount[3] = Math.max(0, out - lastOut);
mlastByteCount = new long[]{in, out, diffIn, diffOut};
diff --git a/main/src/main/res/values-v21/styles.xml b/main/src/main/res/values-v21/styles.xml
index 83a693f1..fa27ebe8 100644
--- a/main/src/main/res/values-v21/styles.xml
+++ b/main/src/main/res/values-v21/styles.xml
@@ -25,4 +25,5 @@
<item name="android:colorPrimaryDark">@color/primary_dark</item>
<item name="android:colorAccent">@color/accent</item>
</style>
+
</resources>
diff --git a/main/src/main/res/values/styles.xml b/main/src/main/res/values/styles.xml
index 13d5e0b1..4cdf2c00 100644
--- a/main/src/main/res/values/styles.xml
+++ b/main/src/main/res/values/styles.xml
@@ -53,4 +53,10 @@
</style>
+ <style name="blinkt.translucent" parent="blinkt.dialog">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
</resources> \ No newline at end of file