diff --git a/ShadowsocksX-NG.xcodeproj/project.pbxproj b/ShadowsocksX-NG.xcodeproj/project.pbxproj index 6fca147..a092597 100755 --- a/ShadowsocksX-NG.xcodeproj/project.pbxproj +++ b/ShadowsocksX-NG.xcodeproj/project.pbxproj @@ -36,10 +36,14 @@ 9B3FFF4C1D09D8F70019A709 /* install_helper.sh in Resources */ = {isa = PBXBuildFile; fileRef = 9B3FFF4B1D09D8F70019A709 /* install_helper.sh */; }; 9B3FFF4F1D09D9D50019A709 /* ProxyConfHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B3FFF4E1D09D9D50019A709 /* ProxyConfHelper.m */; }; 9B3FFF541D09E2D10019A709 /* proxy_conf_helper in Resources */ = {isa = PBXBuildFile; fileRef = 9B3FFF441D09CD3B0019A709 /* proxy_conf_helper */; }; - 9B9CBCAF1E263B1600FC61AA /* libpcre.1.dylib in Resources */ = {isa = PBXBuildFile; fileRef = 9B9CBCAD1E263A6600FC61AA /* libpcre.1.dylib */; }; 9B9CBCA61E25E1DB00FC61AA /* KcptunProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B9CBCA51E25E1DB00FC61AA /* KcptunProfile.swift */; }; 9B9CBCA81E26312E00FC61AA /* install_kcptun.sh in Resources */ = {isa = PBXBuildFile; fileRef = 9B9CBCA71E26310E00FC61AA /* install_kcptun.sh */; }; 9B9CBCAA1E2633CB00FC61AA /* kcptun_client in Resources */ = {isa = PBXBuildFile; fileRef = 9B9CBCA91E2633CB00FC61AA /* kcptun_client */; }; + 9B9CBCAE1E263A6600FC61AA /* libpcre.1.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B9CBCAD1E263A6600FC61AA /* libpcre.1.dylib */; }; + 9B9CBCAF1E263B1600FC61AA /* libpcre.1.dylib in Resources */ = {isa = PBXBuildFile; fileRef = 9B9CBCAD1E263A6600FC61AA /* libpcre.1.dylib */; }; + 9B9CBCB31E26452500FC61AA /* reload_conf_kcptun.sh in Resources */ = {isa = PBXBuildFile; fileRef = 9B9CBCB21E26452500FC61AA /* reload_conf_kcptun.sh */; }; + 9B9CBCB41E26453C00FC61AA /* start_kcptun.sh in Resources */ = {isa = PBXBuildFile; fileRef = 9B9CBCB01E2644DC00FC61AA /* start_kcptun.sh */; }; + 9B9CBCB51E26453C00FC61AA /* stop_kcptun.sh in Resources */ = {isa = PBXBuildFile; fileRef = 9B9CBCB11E26450D00FC61AA /* stop_kcptun.sh */; }; 9BA04B231D23D5A5005AAD7F /* ProxyConfTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BA04B221D23D5A5005AAD7F /* ProxyConfTool.m */; }; 9BA04B261D24044D005AAD7F /* ProxyPreferencesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BA04B241D24044D005AAD7F /* ProxyPreferencesController.swift */; }; 9BB706A71D1B982300551F0E /* SWBApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BB706A51D1B982300551F0E /* SWBApplication.m */; }; @@ -153,10 +157,13 @@ 9B3FFF4E1D09D9D50019A709 /* ProxyConfHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProxyConfHelper.m; sourceTree = ""; }; 9B3FFF501D09DAEA0019A709 /* proxy_conf_helper_version.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = proxy_conf_helper_version.h; sourceTree = ""; }; 9B3FFF511D09DBA20019A709 /* ShadowsocksX-NG-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ShadowsocksX-NG-Bridging-Header.h"; sourceTree = ""; }; - 9B9CBCAD1E263A6600FC61AA /* libpcre.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libpcre.1.dylib; sourceTree = ""; }; 9B9CBCA51E25E1DB00FC61AA /* KcptunProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KcptunProfile.swift; sourceTree = ""; }; 9B9CBCA71E26310E00FC61AA /* install_kcptun.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = install_kcptun.sh; sourceTree = ""; }; 9B9CBCA91E2633CB00FC61AA /* kcptun_client */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = kcptun_client; sourceTree = ""; }; + 9B9CBCAD1E263A6600FC61AA /* libpcre.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libpcre.1.dylib; sourceTree = ""; }; + 9B9CBCB01E2644DC00FC61AA /* start_kcptun.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = start_kcptun.sh; sourceTree = ""; }; + 9B9CBCB11E26450D00FC61AA /* stop_kcptun.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = stop_kcptun.sh; sourceTree = ""; }; + 9B9CBCB21E26452500FC61AA /* reload_conf_kcptun.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = reload_conf_kcptun.sh; sourceTree = ""; }; 9BA04B211D23D5A5005AAD7F /* ProxyConfTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProxyConfTool.h; sourceTree = ""; }; 9BA04B221D23D5A5005AAD7F /* ProxyConfTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProxyConfTool.m; sourceTree = ""; }; 9BA04B241D24044D005AAD7F /* ProxyPreferencesController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyPreferencesController.swift; sourceTree = ""; }; @@ -199,6 +206,7 @@ files = ( 9B3FFF3E1D08D9910019A709 /* SystemConfiguration.framework in Frameworks */, 258E511BA910B0521B24DAB8 /* Pods_ShadowsocksX_NG.framework in Frameworks */, + 9B9CBCAE1E263A6600FC61AA /* libpcre.1.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -264,6 +272,9 @@ 9BEEF0671D04CE9A00FC52B3 /* stop_ss_local.sh */, 9BEEF0681D04CFE500FC52B3 /* reload_conf_ss_local.sh */, C6D429981DA76FBC002A5711 /* privoxy.config.example */, + 9B9CBCB01E2644DC00FC61AA /* start_kcptun.sh */, + 9B9CBCB11E26450D00FC61AA /* stop_kcptun.sh */, + 9B9CBCB21E26452500FC61AA /* reload_conf_kcptun.sh */, ); name = "Support Files"; sourceTree = ""; @@ -488,6 +499,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9B9CBCB41E26453C00FC61AA /* start_kcptun.sh in Resources */, + 9B9CBCB51E26453C00FC61AA /* stop_kcptun.sh in Resources */, 9B9CBCAF1E263B1600FC61AA /* libpcre.1.dylib in Resources */, 9B9CBCA81E26312E00FC61AA /* install_kcptun.sh in Resources */, 9B9CBCAA1E2633CB00FC61AA /* kcptun_client in Resources */, @@ -514,6 +527,7 @@ 08FCA0FF1E24BE1A0070984F /* example-gui-config.json in Resources */, 9B3FFF271D0898EB0019A709 /* gfwlist.txt in Resources */, C6D429931DA75988002A5711 /* install_privoxy.sh in Resources */, + 9B9CBCB31E26452500FC61AA /* reload_conf_kcptun.sh in Resources */, 9BC70EDC1D2E3E3100EDA4CA /* Localizable.strings in Resources */, 9B0BFFEE1D0460A70040E62B /* MainMenu.xib in Resources */, 9B3FFF4C1D09D8F70019A709 /* install_helper.sh in Resources */, diff --git a/ShadowsocksX-NG/KcptunProfile.swift b/ShadowsocksX-NG/KcptunProfile.swift index bcdc6d4..844b9fb 100644 --- a/ShadowsocksX-NG/KcptunProfile.swift +++ b/ShadowsocksX-NG/KcptunProfile.swift @@ -11,11 +11,11 @@ import Foundation class KcptunProfile: NSObject { - var mode: String = "normal" + var mode: String = "fast" var key: String = "it's a secrect" var crypt: String = "aes" - var nocomp: Bool = true + var nocomp: Bool = false var datashard: uint = 10 var parityshard: uint = 3 @@ -57,7 +57,7 @@ class KcptunProfile: NSObject { func toJsonConfig() -> [String: AnyObject] { let defaults = UserDefaults.standard - let localHost = defaults.string(forKey: "Kcptun.LocalHost") + let localHost = defaults.string(forKey: "Kcptun.LocalHost")! as String let localPort = defaults.integer(forKey: "Kcptun.LocalPort") let conf: [String: AnyObject] = [ diff --git a/ShadowsocksX-NG/LaunchAgentUtils.swift b/ShadowsocksX-NG/LaunchAgentUtils.swift index d31f34c..c39dff3 100644 --- a/ShadowsocksX-NG/LaunchAgentUtils.swift +++ b/ShadowsocksX-NG/LaunchAgentUtils.swift @@ -15,6 +15,7 @@ let APP_SUPPORT_DIR = "/Library/Application Support/ShadowsocksX-NG/" let LAUNCH_AGENT_DIR = "/Library/LaunchAgents/" let LAUNCH_AGENT_CONF_SSLOCAL_NAME = "com.qiuyuzhou.shadowsocksX-NG.local.plist" let LAUNCH_AGENT_CONF_PRIVOXY_NAME = "com.qiuyuzhou.shadowsocksX-NG.http.plist" +let LAUNCH_AGENT_CONF_KCPTUN_NAME = "com.qiuyuzhou.shadowsocksX-NG.kcptun.plist" func getFileSHA1Sum(_ filepath: String) -> String { @@ -129,23 +130,6 @@ func InstallSSLocal() { } } -func InstallKcptunClient() { - let fileMgr = FileManager.default - let homeDir = NSHomeDirectory() - let appSupportDir = homeDir+APP_SUPPORT_DIR - if !fileMgr.fileExists(atPath: appSupportDir + "kcptun_\(KCPTUN_CLIENT_VERSION)/kcptun_client") { - let bundle = Bundle.main - let installerPath = bundle.path(forResource: "install_kcptun", ofType: "sh") - let task = Process.launchedProcess(launchPath: installerPath!, arguments: [""]) - task.waitUntilExit() - if task.terminationStatus == 0 { - NSLog("Install kcptun succeeded.") - } else { - NSLog("Install kcptun failed.") - } - } -} - func writeSSLocalConfFile(_ conf:[String:AnyObject]) -> Bool { do { let filepath = NSHomeDirectory() + APP_SUPPORT_DIR + "ss-local-config.json" @@ -193,8 +177,10 @@ func SyncSSLocal() { } SyncPac() SyncPrivoxy() + SyncKcptun() } +// -------------------------------------------------------------------------------- // MARK: privoxy func generatePrivoxyLauchAgentPlist() -> Bool { @@ -339,3 +325,144 @@ func SyncPrivoxy() { } } } + +// -------------------------------------------------------------------------------- +// kcptun + +func generateKcptunLauchAgentPlist() -> Bool { + let sslocalPath = NSHomeDirectory() + APP_SUPPORT_DIR + "kcptun_client" + let logFilePath = NSHomeDirectory() + "/Library/Logs/kcptun_client.log" + let launchAgentDirPath = NSHomeDirectory() + LAUNCH_AGENT_DIR + let plistFilepath = launchAgentDirPath + LAUNCH_AGENT_CONF_KCPTUN_NAME + + // Ensure launch agent directory is existed. + let fileMgr = FileManager.default + if !fileMgr.fileExists(atPath: launchAgentDirPath) { + try! fileMgr.createDirectory(atPath: launchAgentDirPath, withIntermediateDirectories: true, attributes: nil) + } + + let oldSha1Sum = getFileSHA1Sum(plistFilepath) + + let arguments = [sslocalPath, "-c", "kcptun-config.json"] + + // For a complete listing of the keys, see the launchd.plist manual page. + let dict: NSMutableDictionary = [ + "Label": "com.qiuyuzhou.shadowsocksX-NG.kcptun", + "WorkingDirectory": NSHomeDirectory() + APP_SUPPORT_DIR, + "KeepAlive": true, + "StandardOutPath": logFilePath, + "StandardErrorPath": logFilePath, + "ProgramArguments": arguments, + "EnvironmentVariables": ["DYLD_LIBRARY_PATH": NSHomeDirectory() + APP_SUPPORT_DIR] + ] + dict.write(toFile: plistFilepath, atomically: true) + let Sha1Sum = getFileSHA1Sum(plistFilepath) + if oldSha1Sum != Sha1Sum { + return true + } else { + return false + } +} + +func InstallKcptunClient() { + let fileMgr = FileManager.default + let homeDir = NSHomeDirectory() + let appSupportDir = homeDir+APP_SUPPORT_DIR + if !fileMgr.fileExists(atPath: appSupportDir + "kcptun_\(KCPTUN_CLIENT_VERSION)/kcptun_client") { + let bundle = Bundle.main + let installerPath = bundle.path(forResource: "install_kcptun", ofType: "sh") + let task = Process.launchedProcess(launchPath: installerPath!, arguments: [""]) + task.waitUntilExit() + if task.terminationStatus == 0 { + NSLog("Install kcptun succeeded.") + } else { + NSLog("Install kcptun failed.") + } + } +} + +func writeKcptunConfFile(_ conf:[String:AnyObject]) -> Bool { + do { + let filepath = NSHomeDirectory() + APP_SUPPORT_DIR + "kcptun-config.json" + let data: Data = try JSONSerialization.data(withJSONObject: conf, options: .prettyPrinted) + + let oldSum = getFileSHA1Sum(filepath) + try data.write(to: URL(fileURLWithPath: filepath), options: .atomic) + let newSum = getFileSHA1Sum(filepath) + + if oldSum == newSum { + return false + } + + return true + } catch { + NSLog("Write kcptun config file failed.") + } + return false +} + +func removeKcptunConfFile() { + do { + let filepath = NSHomeDirectory() + APP_SUPPORT_DIR + "kcptun-config.json" + try FileManager.default.removeItem(atPath: filepath) + } catch { + + } +} + + +func ReloadConfKcptun() { + let bundle = Bundle.main + let installerPath = bundle.path(forResource: "reload_conf_kcptun.sh", ofType: nil) + let task = Process.launchedProcess(launchPath: installerPath!, arguments: [""]) + task.waitUntilExit() + if task.terminationStatus == 0 { + NSLog("Start kcptun succeeded.") + } else { + NSLog("Start kcptun failed.") + } +} + +func StartKcptun() { + let bundle = Bundle.main + let installerPath = bundle.path(forResource: "start_kcptun.sh", ofType: nil) + let task = Process.launchedProcess(launchPath: installerPath!, arguments: [""]) + task.waitUntilExit() + if task.terminationStatus == 0 { + NSLog("Start kcptun succeeded.") + } else { + NSLog("Start kcptun failed.") + } +} + +func StopKcptun() { + let bundle = Bundle.main + let installerPath = bundle.path(forResource: "stop_kcptun.sh", ofType: nil) + let task = Process.launchedProcess(launchPath: installerPath!, arguments: [""]) + task.waitUntilExit() + if task.terminationStatus == 0 { + NSLog("Stop kcptun succeeded.") + } else { + NSLog("Stop kcptun failed.") + } +} + +func SyncKcptun() { + var changed: Bool = false + changed = changed || generateKcptunLauchAgentPlist() + let mgr = ServerProfileManager.instance + if let profile = mgr.getActiveProfile() { + if profile.enabledKcptun { + changed = changed || writeKcptunConfFile(profile.toKcptunJsonConfig()) + + let on = UserDefaults.standard.bool(forKey: "ShadowsocksOn") + if on { + StartKcptun() + ReloadConfKcptun() + return + } + } + } + StopKcptun() + removeKcptunConfFile() +} diff --git a/ShadowsocksX-NG/PreferencesWindowController.swift b/ShadowsocksX-NG/PreferencesWindowController.swift index 1fad2b4..d916144 100644 --- a/ShadowsocksX-NG/PreferencesWindowController.swift +++ b/ShadowsocksX-NG/PreferencesWindowController.swift @@ -90,6 +90,7 @@ class PreferencesWindowController: NSWindowController "normal", "fast", "fast2", + "fast3", ]) profilesTableView.reloadData() diff --git a/ShadowsocksX-NG/ServerProfile.swift b/ShadowsocksX-NG/ServerProfile.swift index 273f264..df89a47 100644 --- a/ShadowsocksX-NG/ServerProfile.swift +++ b/ShadowsocksX-NG/ServerProfile.swift @@ -107,6 +107,9 @@ class ServerProfile: NSObject, NSCopying { if let ota = data["OTA"] { profile.ota = ota as! Bool } + if let enabledKcptun = data["EnabledKcptun"] { + profile.enabledKcptun = enabledKcptun as! Bool + } if let kcptunData = data["KcptunProfile"] { profile.kcptunProfile = KcptunProfile.fromDictionary(kcptunData as! [String:Any?]) } @@ -132,7 +135,7 @@ class ServerProfile: NSObject, NSCopying { d["Password"] = password as AnyObject? d["Remark"] = remark as AnyObject? d["OTA"] = ota as AnyObject? - d["EnabledKcptun"] = enabledKcptun as AnyObject + d["EnabledKcptun"] = NSNumber(value: enabledKcptun) d["KcptunProfile"] = kcptunProfile.toDictionary() as AnyObject return d } diff --git a/ShadowsocksX-NG/reload_conf_kcptun.sh b/ShadowsocksX-NG/reload_conf_kcptun.sh new file mode 100755 index 0000000..183d135 --- /dev/null +++ b/ShadowsocksX-NG/reload_conf_kcptun.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# reload_conf_kcptun.sh +# ShadowsocksX-NG +# +# Created by 邱宇舟 on 2017/1/11. +# Copyright © 2017年 qiuyuzhou. All rights reserved. + +launchctl unload "$HOME/Library/LaunchAgents/com.qiuyuzhou.shadowsocksX-NG.kcptun.plist" +launchctl load "$HOME/Library/LaunchAgents/com.qiuyuzhou.shadowsocksX-NG.kcptun.plist" diff --git a/ShadowsocksX-NG/start_kcptun.sh b/ShadowsocksX-NG/start_kcptun.sh new file mode 100755 index 0000000..580d40e --- /dev/null +++ b/ShadowsocksX-NG/start_kcptun.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +# start_kcptun.sh +# ShadowsocksX-NG +# +# Created by 邱宇舟 on 2017/1/11. +# Copyright © 2017年 qiuyuzhou. All rights reserved. + +launchctl load "$HOME/Library/LaunchAgents/com.qiuyuzhou.shadowsocksX-NG.kcptun.plist" diff --git a/ShadowsocksX-NG/stop_kcptun.sh b/ShadowsocksX-NG/stop_kcptun.sh new file mode 100755 index 0000000..b192aea --- /dev/null +++ b/ShadowsocksX-NG/stop_kcptun.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +# stop_kcptun.sh +# ShadowsocksX-NG +# +# Created by 邱宇舟 on 2017/1/11. +# Copyright © 2017年 qiuyuzhou. All rights reserved. + +launchctl unload "$HOME/Library/LaunchAgents/com.qiuyuzhou.shadowsocksX-NG.kcptun.plist"