Commit 8d02a1a6 authored by Max Lv's avatar Max Lv

Merge pull request #334 from shadowsocks/android-ipc

Improve the compatibility by using IPC
parents faad9618 9f676364
...@@ -7,7 +7,7 @@ function try () { ...@@ -7,7 +7,7 @@ function try () {
try pushd src/main try pushd src/main
# Build # Build
try $ANDROID_NDK_HOME/ndk-build clean #try $ANDROID_NDK_HOME/ndk-build clean
try $ANDROID_NDK_HOME/ndk-build -j8 try $ANDROID_NDK_HOME/ndk-build -j8
# copy executables # copy executables
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.shadowsocks" package="com.github.shadowsocks"
android:versionCode="108" android:versionCode="109"
android:versionName="2.7.0"> android:versionName="2.7.1">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
......
...@@ -46,4 +46,5 @@ public class System { ...@@ -46,4 +46,5 @@ public class System {
public static native void exec(String cmd); public static native void exec(String cmd);
public static native String getABI(); public static native String getABI();
public static native int sendfd(int fd); public static native int sendfd(int fd);
public static native void jniclose(int fd);
} }
...@@ -249,13 +249,14 @@ include $(BUILD_EXECUTABLE) ...@@ -249,13 +249,14 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS) include $(CLEAR_VARS)
SHADOWSOCKS_SOURCES := local.c cache.c udprelay.c encrypt.c utils.c netutils.c json.c jconf.c acl.c SHADOWSOCKS_SOURCES := local.c cache.c udprelay.c encrypt.c utils.c netutils.c json.c jconf.c acl.c android.c
LOCAL_MODULE := ss-local LOCAL_MODULE := ss-local
LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES)) LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES))
LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DUDPRELAY_LOCAL \ LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DUDPRELAY_LOCAL \
-DUSE_CRYPTO_OPENSSL -DANDROID -DHAVE_CONFIG_H \ -DUSE_CRYPTO_OPENSSL -DANDROID -DHAVE_CONFIG_H \
-I$(LOCAL_PATH)/libev/ \ -I$(LOCAL_PATH)/libev \
-I$(LOCAL_PATH)/libancillary \
-I$(LOCAL_PATH)/openssl/include \ -I$(LOCAL_PATH)/openssl/include \
-I$(LOCAL_PATH)/shadowsocks-libev/libudns \ -I$(LOCAL_PATH)/shadowsocks-libev/libudns \
-I$(LOCAL_PATH)/shadowsocks-libev/libcork/include \ -I$(LOCAL_PATH)/shadowsocks-libev/libcork/include \
...@@ -263,7 +264,7 @@ LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DUDPRELAY_LOCAL \ ...@@ -263,7 +264,7 @@ LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DUDPRELAY_LOCAL \
-I$(LOCAL_PATH)/shadowsocks-libev/libsodium/src/libsodium/include/sodium \ -I$(LOCAL_PATH)/shadowsocks-libev/libsodium/src/libsodium/include/sodium \
-I$(LOCAL_PATH)/shadowsocks-libev/libipset/include -I$(LOCAL_PATH)/shadowsocks-libev/libipset/include
LOCAL_STATIC_LIBRARIES := libev libcrypto libipset libcork libudns libsodium LOCAL_STATIC_LIBRARIES := libev libcrypto libipset libcork libudns libsodium libancillary
LOCAL_LDLIBS := -llog LOCAL_LDLIBS := -llog
...@@ -275,20 +276,21 @@ include $(BUILD_EXECUTABLE) ...@@ -275,20 +276,21 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS) include $(CLEAR_VARS)
SHADOWSOCKS_SOURCES := tunnel.c cache.c udprelay.c encrypt.c utils.c netutils.c json.c jconf.c SHADOWSOCKS_SOURCES := tunnel.c cache.c udprelay.c encrypt.c utils.c netutils.c json.c jconf.c android.c
LOCAL_MODULE := ss-tunnel LOCAL_MODULE := ss-tunnel
LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES)) LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES))
LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DUDPRELAY_LOCAL -DUDPRELAY_TUNNEL \ LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DUDPRELAY_LOCAL -DUDPRELAY_TUNNEL \
-DUSE_CRYPTO_OPENSSL -DANDROID -DHAVE_CONFIG_H -DSSTUNNEL_JNI \ -DUSE_CRYPTO_OPENSSL -DANDROID -DHAVE_CONFIG_H -DSSTUNNEL_JNI \
-I$(LOCAL_PATH)/libev/ \ -I$(LOCAL_PATH)/libev \
-I$(LOCAL_PATH)/libancillary \
-I$(LOCAL_PATH)/shadowsocks-libev/libudns \ -I$(LOCAL_PATH)/shadowsocks-libev/libudns \
-I$(LOCAL_PATH)/shadowsocks-libev/libcork/include \ -I$(LOCAL_PATH)/shadowsocks-libev/libcork/include \
-I$(LOCAL_PATH)/shadowsocks-libev/libsodium/src/libsodium/include \ -I$(LOCAL_PATH)/shadowsocks-libev/libsodium/src/libsodium/include \
-I$(LOCAL_PATH)/shadowsocks-libev/libsodium/src/libsodium/include/sodium \ -I$(LOCAL_PATH)/shadowsocks-libev/libsodium/src/libsodium/include/sodium \
-I$(LOCAL_PATH)/openssl/include -I$(LOCAL_PATH)/openssl/include
LOCAL_STATIC_LIBRARIES := libev libcrypto libsodium libcork libudns LOCAL_STATIC_LIBRARIES := libev libcrypto libsodium libcork libudns libancillary
LOCAL_LDLIBS := -llog LOCAL_LDLIBS := -llog
......
Subproject commit 2b1eef11973de3f7380401fd20f937e84bc2b756 Subproject commit 3af591c5657c1c2c30a69cab3ca0e5d1f4e3d084
...@@ -43,6 +43,10 @@ void Java_com_github_shadowsocks_system_exec(JNIEnv *env, jobject thiz, jstring ...@@ -43,6 +43,10 @@ void Java_com_github_shadowsocks_system_exec(JNIEnv *env, jobject thiz, jstring
env->ReleaseStringUTFChars(cmd, str); env->ReleaseStringUTFChars(cmd, str);
} }
void Java_com_github_shadowsocks_system_jniclose(JNIEnv *env, jobject thiz, jint fd) {
close(fd);
}
jint Java_com_github_shadowsocks_system_sendfd(JNIEnv *env, jobject thiz, jint tun_fd) { jint Java_com_github_shadowsocks_system_sendfd(JNIEnv *env, jobject thiz, jint tun_fd) {
int fd; int fd;
struct sockaddr_un addr; struct sockaddr_un addr;
...@@ -75,6 +79,8 @@ jint Java_com_github_shadowsocks_system_sendfd(JNIEnv *env, jobject thiz, jint t ...@@ -75,6 +79,8 @@ jint Java_com_github_shadowsocks_system_sendfd(JNIEnv *env, jobject thiz, jint t
static const char *classPathName = "com/github/shadowsocks/System"; static const char *classPathName = "com/github/shadowsocks/System";
static JNINativeMethod method_table[] = { static JNINativeMethod method_table[] = {
{ "jniclose", "(I)V",
(void*) Java_com_github_shadowsocks_system_jniclose },
{ "sendfd", "(I)I", { "sendfd", "(I)I",
(void*) Java_com_github_shadowsocks_system_sendfd }, (void*) Java_com_github_shadowsocks_system_sendfd },
{ "exec", "(Ljava/lang/String;)V", { "exec", "(Ljava/lang/String;)V",
......
...@@ -61,18 +61,16 @@ import scala.concurrent.ops._ ...@@ -61,18 +61,16 @@ import scala.concurrent.ops._
class ShadowsocksVpnService extends VpnService with BaseService { class ShadowsocksVpnService extends VpnService with BaseService {
private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
val TAG = "ShadowsocksVpnService" val TAG = "ShadowsocksVpnService"
val VPN_MTU = 1500 val VPN_MTU = 1500
val PRIVATE_VLAN = "26.26.26.%s" val PRIVATE_VLAN = "26.26.26.%s"
var conn: ParcelFileDescriptor = null var conn: ParcelFileDescriptor = null
var notificationManager: NotificationManager = null var notificationManager: NotificationManager = null
var receiver: BroadcastReceiver = null var receiver: BroadcastReceiver = null
var apps: Array[ProxiedApp] = null var apps: Array[ProxiedApp] = null
var config: Config = null var config: Config = null
var vpnThread: ShadowsocksVpnThread = null
private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
def isByass(net: SubnetUtils): Boolean = { def isByass(net: SubnetUtils): Boolean = {
val info = net.getInfo val info = net.getInfo
...@@ -95,6 +93,192 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -95,6 +93,192 @@ class ShadowsocksVpnService extends VpnService with BaseService {
} }
} }
override def onBind(intent: Intent): IBinder = {
val action = intent.getAction
if (VpnService.SERVICE_INTERFACE == action) {
return super.onBind(intent)
} else if (Action.SERVICE == action) {
return binder
}
null
}
override def onDestroy() {
super.onDestroy()
if (vpnThread != null) vpnThread.stopThread()
}
override def onCreate() {
super.onCreate()
ConfigUtils.refresh(this)
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE)
.asInstanceOf[NotificationManager]
vpnThread = new ShadowsocksVpnThread(this)
vpnThread.start()
}
override def onRevoke() {
stopRunner()
}
override def stopRunner() {
// channge the state
changeState(State.STOPPING)
// send event
application.tracker.send(new HitBuilders.EventBuilder()
.setCategory(TAG)
.setAction("stop")
.setLabel(getVersionName)
.build())
// reset VPN
killProcesses()
// close connections
if (conn != null) {
conn.close()
conn = null
}
// stop the service if no callback registered
if (getCallbackCount == 0) {
stopSelf()
}
// clean up the context
if (receiver != null) {
unregisterReceiver(receiver)
receiver = null
}
// channge the state
changeState(State.STOPPED)
}
def getVersionName: String = {
var version: String = null
try {
val pi: PackageInfo = getPackageManager.getPackageInfo(getPackageName, 0)
version = pi.versionName
} catch {
case e: PackageManager.NameNotFoundException =>
version = "Package name not found"
}
version
}
def killProcesses() {
for (task <- Array("ss-local", "ss-tunnel", "pdnsd", "tun2socks")) {
try {
val pid = scala.io.Source.fromFile(Path.BASE + task + "-vpn.pid").mkString.trim.toInt
Process.killProcess(pid)
} catch {
case e: Throwable => Log.e(TAG, "unable to kill " + task)
}
}
}
override def startRunner(c: Config) {
config = c
// ensure the VPNService is prepared
if (VpnService.prepare(this) != null) {
val i = new Intent(this, classOf[ShadowsocksRunnerActivity])
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(i)
return
}
// send event
application.tracker.send(new HitBuilders.EventBuilder()
.setCategory(TAG)
.setAction("start")
.setLabel(getVersionName)
.build())
// register close receiver
val filter = new IntentFilter()
filter.addAction(Intent.ACTION_SHUTDOWN)
receiver = new BroadcastReceiver {
def onReceive(p1: Context, p2: Intent) {
Toast.makeText(p1, R.string.stopping, Toast.LENGTH_SHORT)
stopRunner()
}
}
registerReceiver(receiver, filter)
changeState(State.CONNECTING)
spawn {
if (config.proxy == "198.199.101.152") {
val holder = getApplication.asInstanceOf[ShadowsocksApplication].containerHolder
try {
config = ConfigUtils.getPublicConfig(getBaseContext, holder.getContainer, config)
} catch {
case ex: Exception =>
changeState(State.STOPPED, getString(R.string.service_failed))
stopRunner()
config = null
}
}
if (config != null) {
// reset the context
killProcesses()
// Resolve the server address
var resolved: Boolean = false
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
!InetAddressUtils.isIPv6Address(config.proxy)) {
Utils.resolve(config.proxy, enableIPv6 = true) match {
case Some(addr) =>
config.proxy = addr
resolved = true
case None => resolved = false
}
} else {
resolved = true
}
if (resolved && handleConnection) {
changeState(State.CONNECTED)
} else {
changeState(State.STOPPED, getString(R.string.service_failed))
stopRunner()
}
}
}
}
/** Called when the activity is first created. */
def handleConnection: Boolean = {
startShadowsocksDaemon()
if (!config.isUdpDns) {
startDnsDaemon()
startDnsTunnel()
}
val fd = startVpn()
if (fd == -1) {
false
} else {
Thread.sleep(1000)
if (System.sendfd(fd) == -1) {
false
} else {
true
}
}
}
def startShadowsocksDaemon() { def startShadowsocksDaemon() {
if (Utils.isLollipopOrAbove && config.route != Route.ALL) { if (Utils.isLollipopOrAbove && config.route != Route.ALL) {
...@@ -115,13 +299,13 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -115,13 +299,13 @@ class ShadowsocksVpnService extends VpnService with BaseService {
}) })
val cmd = new ArrayBuffer[String] val cmd = new ArrayBuffer[String]
cmd +=(Path.BASE + "ss-local", "-u" cmd +=(Path.BASE + "ss-local", "-V", "-u"
, "-b" , "127.0.0.1" , "-b", "127.0.0.1"
, "-t" , "600" , "-t", "600"
, "-c" , Path.BASE + "ss-local-vpn.conf" , "-c", Path.BASE + "ss-local-vpn.conf"
, "-f" , Path.BASE + "ss-local-vpn.pid") , "-f", Path.BASE + "ss-local-vpn.pid")
if (Utils.isLollipopOrAbove && config.route != Route.ALL) { if (config.route != Route.ALL) {
cmd += "--acl" cmd += "--acl"
cmd += (Path.BASE + "acl.list") cmd += (Path.BASE + "acl.list")
} }
...@@ -139,13 +323,14 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -139,13 +323,14 @@ class ShadowsocksVpnService extends VpnService with BaseService {
}) })
val cmd = new ArrayBuffer[String] val cmd = new ArrayBuffer[String]
cmd +=(Path.BASE + "ss-tunnel" cmd +=(Path.BASE + "ss-tunnel"
, "-V"
, "-u" , "-u"
, "-t" , "10" , "-t", "10"
, "-b" , "127.0.0.1" , "-b", "127.0.0.1"
, "-l" , "8163" , "-l", "8163"
, "-L" , "8.8.8.8:53" , "-L", "8.8.8.8:53"
, "-c" , Path.BASE + "ss-tunnel-vpn.conf" , "-c", Path.BASE + "ss-tunnel-vpn.conf"
, "-f" , Path.BASE + "ss-tunnel-vpn.pid") , "-f", Path.BASE + "ss-tunnel-vpn.pid")
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
Console.runCommand(cmd.mkString(" ")) Console.runCommand(cmd.mkString(" "))
...@@ -172,17 +357,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -172,17 +357,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
Console.runCommand(cmd) Console.runCommand(cmd)
} }
def getVersionName: String = { override def getContext = getBaseContext
var version: String = null
try {
val pi: PackageInfo = getPackageManager.getPackageInfo(getPackageName, 0)
version = pi.versionName
} catch {
case e: PackageManager.NameNotFoundException =>
version = "Package name not found"
}
version
}
def startVpn(): Int = { def startVpn(): Int = {
...@@ -212,89 +387,17 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -212,89 +387,17 @@ class ShadowsocksVpnService extends VpnService with BaseService {
builder.addDisallowedApplication(pkg) builder.addDisallowedApplication(pkg)
} }
} }
if (config.isBypassApps) {
builder.addDisallowedApplication(this.getPackageName)
}
} else {
builder.addDisallowedApplication(this.getPackageName)
} }
} }
if (InetAddressUtils.isIPv6Address(config.proxy)) { if (config.route == Route.ALL) {
builder.addRoute("0.0.0.0", 0) builder.addRoute("0.0.0.0", 0)
} else { } else {
if (!Utils.isLollipopOrAbove) { val privateList = getResources.getStringArray(R.array.bypass_private_route)
config.route match { privateList.foreach(cidr => {
case Route.BYPASS_LAN => val addr = cidr.split('/')
for (i <- 1 to 223) { builder.addRoute(addr(0), addr(1).toInt)
if (i != 26 && i != 127) { })
val addr = i.toString + ".0.0.0"
val cidr = addr + "/8"
val net = new SubnetUtils(cidr)
if (!isByass(net) && !isPrivateA(i)) {
builder.addRoute(addr, 8)
} else {
for (j <- 0 to 255) {
val subAddr = i.toString + "." + j.toString + ".0.0"
val subCidr = subAddr + "/16"
val subNet = new SubnetUtils(subCidr)
if (!isByass(subNet) && !isPrivateB(i, j)) {
builder.addRoute(subAddr, 16)
}
}
}
}
}
case Route.BYPASS_CHN =>
val list = {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
getResources.getStringArray(R.array.simple_route)
} else {
getResources.getStringArray(R.array.gfw_route)
}
}
list.foreach(cidr => {
val net = new SubnetUtils(cidr)
if (!isByass(net)) {
val addr = cidr.split('/')
builder.addRoute(addr(0), addr(1).toInt)
}
})
case Route.ALL =>
for (i <- 1 to 223) {
if (i != 26 && i != 127) {
val addr = i.toString + ".0.0.0"
val cidr = addr + "/8"
val net = new SubnetUtils(cidr)
if (!isByass(net)) {
builder.addRoute(addr, 8)
} else {
for (j <- 0 to 255) {
val subAddr = i.toString + "." + j.toString + ".0.0"
val subCidr = subAddr + "/16"
val subNet = new SubnetUtils(subCidr)
if (!isByass(subNet)) {
builder.addRoute(subAddr, 16)
}
}
}
}
}
}
} else {
if (config.route == Route.ALL) {
builder.addRoute("0.0.0.0", 0)
} else {
val privateList = getResources.getStringArray(R.array.bypass_private_route)
privateList.foreach(cidr => {
val addr = cidr.split('/')
builder.addRoute(addr(0), addr(1).toInt)
})
}
}
} }
builder.addRoute("8.8.0.0", 16) builder.addRoute("8.8.0.0", 16)
...@@ -330,181 +433,11 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -330,181 +433,11 @@ class ShadowsocksVpnService extends VpnService with BaseService {
else else
cmd += " --dnsgw %s:8153".formatLocal(Locale.ENGLISH, PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1")) cmd += " --dnsgw %s:8153".formatLocal(Locale.ENGLISH, PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1"))
// if (Utils.isLollipopOrAbove) {
// cmd += " --fake-proc"
// }
if (BuildConfig.DEBUG) Log.d(TAG, cmd) if (BuildConfig.DEBUG) Log.d(TAG, cmd)
Console.runCommand(cmd) Console.runCommand(cmd)
return fd; return fd
}
/** Called when the activity is first created. */
def handleConnection: Boolean = {
startShadowsocksDaemon()
if (!config.isUdpDns) {
startDnsDaemon()
startDnsTunnel()
}
val fd = startVpn()
if (fd == -1) {
false
} else {
Thread.sleep(1000)
if (System.sendfd(fd) == -1) {
false
} else {
true
}
}
}
override def onBind(intent: Intent): IBinder = {
val action = intent.getAction
if (VpnService.SERVICE_INTERFACE == action) {
return super.onBind(intent)
} else if (Action.SERVICE == action) {
return binder
}
null
}
override def onCreate() {
super.onCreate()
ConfigUtils.refresh(this)
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE)
.asInstanceOf[NotificationManager]
}
override def onRevoke() {
stopRunner()
}
def killProcesses() {
for (task <- Array("ss-local", "ss-tunnel", "pdnsd", "tun2socks")) {
try {
val pid = scala.io.Source.fromFile(Path.BASE + task + "-vpn.pid").mkString.trim.toInt
Process.killProcess(pid)
} catch {
case e: Throwable => Log.e(TAG, "unable to kill " + task)
}
}
}
override def startRunner(c: Config) {
config = c
// ensure the VPNService is prepared
if (VpnService.prepare(this) != null) {
val i = new Intent(this, classOf[ShadowsocksRunnerActivity])
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(i)
return
}
// send event
application.tracker.send(new HitBuilders.EventBuilder()
.setCategory(TAG)
.setAction("start")
.setLabel(getVersionName)
.build())
// register close receiver
val filter = new IntentFilter()
filter.addAction(Intent.ACTION_SHUTDOWN)
receiver = new BroadcastReceiver {
def onReceive(p1: Context, p2: Intent) {
Toast.makeText(p1, R.string.stopping, Toast.LENGTH_SHORT)
stopRunner()
}
}
registerReceiver(receiver, filter)
changeState(State.CONNECTING)
spawn {
if (config.proxy == "198.199.101.152") {
val holder = getApplication.asInstanceOf[ShadowsocksApplication].containerHolder
try {
config = ConfigUtils.getPublicConfig(getBaseContext, holder.getContainer, config)
} catch {
case ex: Exception =>
changeState(State.STOPPED, getString(R.string.service_failed))
stopRunner()
config = null
}
}
if (config != null) {
// reset the context
killProcesses()
// Resolve the server address
var resolved: Boolean = false
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
!InetAddressUtils.isIPv6Address(config.proxy)) {
Utils.resolve(config.proxy, enableIPv6 = true) match {
case Some(addr) =>
config.proxy = addr
resolved = true
case None => resolved = false
}
} else {
resolved = true
}
if (resolved && handleConnection) {
changeState(State.CONNECTED)
} else {
changeState(State.STOPPED, getString(R.string.service_failed))
stopRunner()
}
}
}
}
override def stopRunner() {
// channge the state
changeState(State.STOPPING)
// send event
application.tracker.send(new HitBuilders.EventBuilder()
.setCategory(TAG)
.setAction("stop")
.setLabel(getVersionName)
.build())
// reset VPN
killProcesses()
// close connections
if (conn != null) {
conn.close()
conn = null
}
// stop the service if no callback registered
if (getCallbackCount == 0) {
stopSelf()
}
// clean up the context
if (receiver != null) {
unregisterReceiver(receiver)
receiver = null
}
// channge the state
changeState(State.STOPPED)
} }
override def stopBackgroundService() { override def stopBackgroundService() {
...@@ -514,6 +447,4 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -514,6 +447,4 @@ class ShadowsocksVpnService extends VpnService with BaseService {
override def getTag = TAG override def getTag = TAG
override def getServiceMode = Mode.VPN override def getServiceMode = Mode.VPN
override def getContext = getBaseContext
} }
/*
* Shadowsocks - A shadowsocks client for Android
* Copyright (C) 2015 <max.c.lv@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* ___====-_ _-====___
* _--^^^#####// \\#####^^^--_
* _-^##########// ( ) \\##########^-_
* -############// |\^^/| \\############-
* _/############// (@::@) \\############\_
* /#############(( \\// ))#############\
* -###############\\ (oo) //###############-
* -#################\\ / VV \ //#################-
* -###################\\/ \//###################-
* _#/|##########/\######( /\ )######/\##########|\#_
* |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \|
* ` |/ V V ` V \#\| | | |/#/ V ' V V \| '
* ` ` ` ` / | | | | \ ' ' ' '
* ( | | | | )
* __\ | | | | /__
* (vvv(VVV)(VVV)vvv)
*
* HERE BE DRAGONS
*
*/
package com.github.shadowsocks
import java.io.{File, FileDescriptor, IOException}
import java.util.concurrent.Executors
import android.net.{LocalServerSocket, LocalSocket, LocalSocketAddress}
import android.util.Log
class ShadowsocksVpnThread(vpnService: ShadowsocksVpnService) extends Thread {
val TAG = "ShadowsocksVpnService"
val PATH = "/data/data/com.github.shadowsocks/protect_path"
var isRunning: Boolean = true
var serverSocket: LocalServerSocket = null
def stopThread() {
isRunning = false
if (serverSocket != null) {
serverSocket.close()
serverSocket = null
}
}
override def run(): Unit = {
try {
new File(PATH).delete()
} catch {
case _: Exception => // ignore
}
try {
val localSocket = new LocalSocket
localSocket.bind(new LocalSocketAddress(PATH, LocalSocketAddress.Namespace.FILESYSTEM))
serverSocket = new LocalServerSocket(localSocket.getFileDescriptor)
} catch {
case e: IOException =>
Log.e(TAG, "unable to bind", e)
vpnService.stopBackgroundService()
return
}
val pool = Executors.newFixedThreadPool(4)
while (isRunning) {
try {
val socket = serverSocket.accept()
pool.execute(new Runnable {
override def run() {
try {
val input = socket.getInputStream
val output = socket.getOutputStream
input.read()
val fds = socket.getAncillaryFileDescriptors
if (fds.length > 0) {
var ret = false
val getInt = classOf[FileDescriptor].getDeclaredMethod("getInt$")
val fd = getInt.invoke(fds(0)).asInstanceOf[Int]
ret = vpnService.protect(fd)
// Trick to close file decriptor
System.jniclose(fd)
if (ret) {
output.write(0)
} else {
output.write(1)
}
input.close()
output.close()
}
} catch {
case e: Exception =>
Log.e(TAG, "Error when protect socket", e)
}
// close socket
try {
socket.close()
} catch {
case _: Exception => // ignore
}
}})
} catch {
case e: IOException => Log.e(TAG, "Error when accept socket", e)
}
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment