diff options
Diffstat (limited to 'src/de/blinkt/openvpn/OpenVpnService.java')
-rw-r--r-- | src/de/blinkt/openvpn/OpenVpnService.java | 236 |
1 files changed, 178 insertions, 58 deletions
diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 4dff943b..ce9f75a1 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -14,11 +14,10 @@ * limitations under the License. */ -package de.blinkt.openvpn; - -import java.io.IOException; +package de.blinkt.openvpn;import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Locale; import java.util.Vector; import android.annotation.TargetApi; @@ -28,22 +27,27 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.net.VpnService; import android.os.Binder; -import android.os.Handler; -import android.os.Handler.Callback; import android.os.Build; +import android.os.Handler.Callback; import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; +import android.preference.PreferenceManager; +import de.blinkt.openvpn.OpenVPN.ByteCountListener; import de.blinkt.openvpn.OpenVPN.StateListener; -public class OpenVpnService extends VpnService implements StateListener, Callback { +public class OpenVpnService extends VpnService implements StateListener, Callback, ByteCountListener { public static final String START_SERVICE = "de.blinkt.openvpn.START_SERVICE"; + public static final String START_SERVICE_STICKY = "de.blinkt.openvpn.START_SERVICE_STICKY"; + public static final String ALWAYS_SHOW_NOTIFICATION = "de.blinkt.openvpn.NOTIFICATION_ALWAYS_VISIBLE"; + private Thread mProcessThread=null; @@ -58,9 +62,6 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac private CIDRIP mLocalIP=null; - private OpenVpnManagementThread mSocketManager; - - private Thread mSocketManagerThread; private int mMtu; private String mLocalIPv6=null; private NetworkSateReceiver mNetworkStateReceiver; @@ -76,15 +77,25 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac public static final int PROTECT_FD = 0; + + private static final int LEVEL_OFFLINE = 0; + private static final int LEVEL_NOTCONNECTED = 1; + private static final int LEVEL_CONNECTED = 2; + + private static boolean mNotificationalwaysVisible=false; + private final IBinder mBinder = new LocalBinder(); - + private boolean mOvpn3; + private Thread mSocketManagerThread; + private OpenVPNMangement mManagement; + public class LocalBinder extends Binder { public OpenVpnService getService() { - // Return this instance of LocalService so clients can call public methods - return OpenVpnService.this; - } - } - + // Return this instance of LocalService so clients can call public methods + return OpenVpnService.this; + } + } + @Override public IBinder onBind(Intent intent) { String action = intent.getAction(); @@ -93,10 +104,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac else return super.onBind(intent); } - + @Override public void onRevoke() { - OpenVpnManagementThread.stopOpenVPN(); + mManagement.stopVPN(); endVpnService(); } @@ -108,34 +119,43 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac private void endVpnService() { mProcessThread=null; OpenVPN.logBuilderConfig(null); + OpenVPN.removeStateListener(this); + OpenVPN.removeByteCountListener(this); + unregisterNetworkStateReceiver(); ProfileManager.setConntectedVpnProfileDisconnected(this); if(!mStarting) { - stopSelf(); - stopForeground(true); + stopForeground(!mNotificationalwaysVisible); + + if( !mNotificationalwaysVisible) + stopSelf(); } } - private void showNotification(String msg, String tickerText, boolean lowpriority, long when) { + private void showNotification(String msg, String tickerText, boolean lowpriority, long when, int level) { String ns = Context.NOTIFICATION_SERVICE; NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns); - int icon = R.drawable.ic_stat_vpn; + int icon = R.drawable.notification_icon; android.app.Notification.Builder nbuilder = new Notification.Builder(this); - nbuilder.setContentTitle(getString(R.string.notifcation_title,mProfile.mName)); + if(mProfile!=null) + nbuilder.setContentTitle(getString(R.string.notifcation_title,mProfile.mName)); + else + nbuilder.setContentTitle(getString(R.string.notifcation_title_notconnect)); + nbuilder.setContentText(msg); nbuilder.setOnlyAlertOnce(true); nbuilder.setOngoing(true); nbuilder.setContentIntent(getLogPendingIntent()); - nbuilder.setSmallIcon(icon); + nbuilder.setSmallIcon(icon,level); if(when !=0) nbuilder.setWhen(when); // Try to set the priority available since API 16 (Jellybean) jbNotificationExtras(lowpriority, nbuilder); - if(tickerText!=null) + if(tickerText!=null && !tickerText.equals("")) nbuilder.setTicker(tickerText); @SuppressWarnings("deprecation") @@ -146,6 +166,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac startForeground(OPENVPN_STATUS, notification); } + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void jbNotificationExtras(boolean lowpriority, android.app.Notification.Builder nbuilder) { @@ -155,7 +176,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // PRIORITY_MIN == -2 setpriority.invoke(nbuilder, -2 ); - nbuilder.setUsesChronometer(true); + Method setUsesChronometer = nbuilder.getClass().getMethod("setUsesChronometer", boolean.class); + setUsesChronometer.invoke(nbuilder,true); + /* PendingIntent cancelconnet=null; nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, @@ -185,6 +208,8 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac private LocalServerSocket openManagmentInterface(int tries) { // Could take a while to open connection String socketname = (getCacheDir().getAbsolutePath() + "/" + "mgmtsocket"); + // The sock is transfered to the LocalServerSocket, ignore warning + @SuppressWarnings("resource") LocalSocket sock = new LocalSocket(); while(tries > 0 && !sock.isConnected()) { @@ -211,20 +236,35 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac } - void registerNetworkStateReceiver() { + void registerNetworkStateReceiver(OpenVPNMangement magnagement) { // Registers BroadcastReceiver to track network connection changes. IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); - mNetworkStateReceiver = new NetworkSateReceiver(mSocketManager); + mNetworkStateReceiver = new NetworkSateReceiver(magnagement); this.registerReceiver(mNetworkStateReceiver, filter); } - + void unregisterNetworkStateReceiver() { + if(mNetworkStateReceiver!=null) + this.unregisterReceiver(mNetworkStateReceiver); + mNetworkStateReceiver=null; + } + + @Override - public int onStartCommand(Intent intent, int flags, int startId) { - + public int onStartCommand(Intent intent, int flags, int startId) { + + if(intent != null && intent.getBooleanExtra(ALWAYS_SHOW_NOTIFICATION, false)) + mNotificationalwaysVisible=true; + + OpenVPN.addStateListener(this); + OpenVPN.addByteCountListener(this); + if(intent != null && intent.getAction() !=null &&intent.getAction().equals(START_SERVICE)) return START_NOT_STICKY; - + if(intent != null && intent.getAction() !=null &&intent.getAction().equals(START_SERVICE_STICKY)) { + return START_REDELIVER_INTENT; + } + // Extract information from the intent. String prefix = getPackageName(); @@ -234,21 +274,18 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac mProfile = ProfileManager.get(profileUUID); - showNotification("Starting VPN " + mProfile.mName,"Starting VPN " + mProfile.mName, false,0); - - - OpenVPN.addStateListener(this); + showNotification("Starting VPN " + mProfile.mName,"Starting VPN " + mProfile.mName, false,0,LEVEL_NOTCONNECTED); // Set a flag that we are starting a new VPN mStarting=true; // Stop the previous session by interrupting the thread. - if(OpenVpnManagementThread.stopOpenVPN()){ - // an old was asked to exit, wait 2s + if(mManagement!=null && mManagement.stopVPN()) + // an old was asked to exit, wait 1s try { Thread.sleep(1000); } catch (InterruptedException e) { } - } + if (mProcessThread!=null) { mProcessThread.interrupt(); @@ -262,33 +299,72 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // Open the Management Interface - LocalServerSocket mgmtsocket = openManagmentInterface(8); - - if(mgmtsocket!=null) { - // start a Thread that handles incoming messages of the managment socket - mSocketManager = new OpenVpnManagementThread(mProfile,mgmtsocket,this); - mSocketManagerThread = new Thread(mSocketManager,"OpenVPNMgmtThread"); - mSocketManagerThread.start(); - OpenVPN.logInfo("started Socket Thread"); - registerNetworkStateReceiver(); + if(!mOvpn3) { + LocalServerSocket mgmtsocket = openManagmentInterface(8); + + if(mgmtsocket!=null) { + // start a Thread that handles incoming messages of the managment socket + OpenVpnManagementThread ovpnmgmthread = new OpenVpnManagementThread(mProfile,mgmtsocket,this); + mSocketManagerThread = new Thread(ovpnmgmthread,"OpenVPNMgmtThread"); + mSocketManagerThread.start(); + mManagement= ovpnmgmthread; + OpenVPN.logInfo("started Socket Thread"); + } } - // Start a new session by creating a new thread. - OpenVPNThread processThread = new OpenVPNThread(this, argv,nativelibdir); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + + mOvpn3 = prefs.getBoolean("ovpn3", false); + + Runnable processThread; + if(mOvpn3) { + + OpenVPNMangement mOpenVPN3 = instantiateOpenVPN3Core(); + processThread = (Runnable) mOpenVPN3; + mManagement = mOpenVPN3; + + + } else { + processThread = new OpenVPNThread(this, argv,nativelibdir); + } mProcessThread = new Thread(processThread, "OpenVPNProcessThread"); mProcessThread.start(); + registerNetworkStateReceiver(mManagement); + + ProfileManager.setConnectedVpnProfile(this, mProfile); return START_NOT_STICKY; } + private OpenVPNMangement instantiateOpenVPN3Core() { + //new OpenVPNThreadv3(this,mProfile); + try { + Class cl = Class.forName("Lde/blinkt/openvpn/OpenVPNThreadv3;"); + return (OpenVPNMangement) cl.getConstructor(OpenVpnService.class,VpnProfile.class).newInstance(this,mProfile); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return null; + } + @Override public void onDestroy() { if (mProcessThread != null) { - mSocketManager.managmentCommand("signal SIGINT\n"); + mManagement.stopVPN(); mProcessThread.interrupt(); } @@ -426,6 +502,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac } + public void addRoute(CIDRIP route) + { + mRoutes.add(route ); + } public void addRoute(String dest, String mask) { CIDRIP route = new CIDRIP(dest, mask); if(route.len == 32 && !mask.equals("255.255.255.255")) { @@ -442,6 +522,15 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac mRoutesv6.add(extra); } + public void setMtu(int mtu) { + mMtu=mtu; + } + + public void setLocalIP(CIDRIP cdrip) + { + mLocalIP=cdrip; + } + public void setLocalIP(String local, String netmask,int mtu, String mode) { mLocalIP = new CIDRIP(local, netmask); @@ -451,7 +540,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // get the netmask as IP long netint = CIDRIP.getInt(netmask); if(Math.abs(netint - mLocalIP.getInt()) ==1) { - if(mode.equals("net30")) + if("net30".equals(mode)) mLocalIP.len=30; else mLocalIP.len=31; @@ -469,20 +558,23 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac public void updateState(String state,String logmessage, int resid) { // If the process is not running, ignore any state, // Notification should be invisible in this state - if(mProcessThread==null) + if(mProcessThread==null && !mNotificationalwaysVisible) return; // Display byte count only after being connected - if("BYTECOUNT".equals(state)) { - if(mDisplayBytecount) { - showNotification(logmessage,null,true,mConnecttime); - } - } else { + { + int level; if("CONNECTED".equals(state)) { mDisplayBytecount = true; mConnecttime = System.currentTimeMillis(); + level = LEVEL_CONNECTED; } else { + if ("NONETWORK".equals(state)) { + level = LEVEL_OFFLINE; + } else { + level = LEVEL_NOTCONNECTED; + } mDisplayBytecount = false; } @@ -490,12 +582,36 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // This also mean we are no longer connected, ignore bytecount messages until next // CONNECTED String ticker = getString(resid); - showNotification(getString(resid) +" " + logmessage,ticker,false,0); + showNotification(getString(resid) +" " + logmessage,ticker,false,0, level); } } @Override + public void updateByteCount(long in, long out, long diffin, long diffout) { + if(mDisplayBytecount) { + String netstat = String.format(getString(R.string.statusline_bytecount), + humanReadableByteCount(in, false), + humanReadableByteCount(diffin, false), + humanReadableByteCount(out, false), + humanReadableByteCount(diffout, false)); + + boolean lowpriority = !mNotificationalwaysVisible; + showNotification(netstat,null,lowpriority,mConnecttime, LEVEL_CONNECTED); + } + + } + + // From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java + public static String humanReadableByteCount(long bytes, boolean si) { + int unit = si ? 1000 : 1024; + if (bytes < unit) return bytes + " B"; + int exp = (int) (Math.log(bytes) / Math.log(unit)); + String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i"); + return String.format(Locale.getDefault(),"%.1f %sB", bytes / Math.pow(unit, exp), pre); + } + + @Override public boolean handleMessage(Message msg) { Runnable r = msg.getCallback(); if(r!=null){ @@ -505,4 +621,8 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac return false; } } + + public OpenVPNMangement getManagement() { + return mManagement; + } } |