diff --git a/ShadowsocksX-NG.xcodeproj/project.pbxproj b/ShadowsocksX-NG.xcodeproj/project.pbxproj index bc322f7..a072603 100644 --- a/ShadowsocksX-NG.xcodeproj/project.pbxproj +++ b/ShadowsocksX-NG.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 088EC3991D5F5BA300E40791 /* whiteiplist.pac in Resources */ = {isa = PBXBuildFile; fileRef = 088EC3981D5F5BA300E40791 /* whiteiplist.pac */; }; 08BDBB481E2361BD00C4BBC2 /* VersionChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08BDBB471E2361BD00C4BBC2 /* VersionChecker.swift */; }; 08CF21461E2A730E008F235D /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 08CF21451E2A730E008F235D /* LICENSE */; }; + 08FFAC621E437F6E00BDF137 /* PingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08FFAC611E437F6E00BDF137 /* PingTest.swift */; }; 258E511BA910B0521B24DAB8 /* Pods_ShadowsocksX_NG.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 283ED1A8E9B711AC65670031 /* Pods_ShadowsocksX_NG.framework */; }; 9B07EFA71D048BBB0052D9DF /* ss-local in Resources */ = {isa = PBXBuildFile; fileRef = 9B07EFA61D048BBB0052D9DF /* ss-local */; }; 9B07EFAC1D048E880052D9DF /* menu_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 9B07EFA81D048E880052D9DF /* menu_icon@2x.png */; }; @@ -116,6 +117,7 @@ 08AF56C01D6AFA7C00DC4F46 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/PreferencesWindowController.strings"; sourceTree = ""; }; 08BDBB471E2361BD00C4BBC2 /* VersionChecker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionChecker.swift; sourceTree = ""; }; 08CF21451E2A730E008F235D /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = SOURCE_ROOT; }; + 08FFAC611E437F6E00BDF137 /* PingTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PingTest.swift; sourceTree = ""; }; 19083CFCED87354F006967FF /* Pods_ShadowsocksX_NGUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShadowsocksX_NGUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1E7783AEDB4A3BDDC9FF16AC /* libPods-proxy_conf_helper.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-proxy_conf_helper.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 283ED1A8E9B711AC65670031 /* Pods_ShadowsocksX_NG.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShadowsocksX_NG.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -333,6 +335,7 @@ 9B3FFF201D08826E0019A709 /* PACUtils.swift */, 083BF8341D82742200831C68 /* NetWorkMonitor.swift */, 083BF8351D82742200831C68 /* PingClient.swift */, + 08FFAC611E437F6E00BDF137 /* PingTest.swift */, 9B3FFF131D0705810019A709 /* Notifications.swift */, 9B3FFF1D1D0732660019A709 /* Utils.m */, 9B3FFF1F1D0734060019A709 /* Utils.h */, @@ -694,6 +697,7 @@ 08BDBB481E2361BD00C4BBC2 /* VersionChecker.swift in Sources */, 083BF8371D82742200831C68 /* PingClient.swift in Sources */, 083BF8361D82742200831C68 /* NetWorkMonitor.swift in Sources */, + 08FFAC621E437F6E00BDF137 /* PingTest.swift in Sources */, 083BF8331D82731900831C68 /* SimplePing.m in Sources */, 9B3FFF211D08826E0019A709 /* PACUtils.swift in Sources */, 9BA04B261D24044D005AAD7F /* ProxyPreferencesController.swift in Sources */, diff --git a/ShadowsocksX-NG/PingTest.swift b/ShadowsocksX-NG/PingTest.swift new file mode 100644 index 0000000..d243132 --- /dev/null +++ b/ShadowsocksX-NG/PingTest.swift @@ -0,0 +1,166 @@ +// +// PingTest.swift +// ShadowsocksX-NG +// +// Created by 秦宇航 on 16/9/12. +// Copyright © 2016年 qiuyuzhou. All rights reserved. +// + +import Foundation + +class PingTest: NSObject, SimplePingDelegate { + static let instance = PingTest(hostName: "") + //then 写一个init函数,传入hostName来init + var hostName = "baidu.com" + + var pinger: SimplePing? + var sendTimer: Timer? + var dateReference: Date? + + /// Called by the table view selection delegate callback to start the ping. + init(hostName:String) { + self.hostName = hostName + } + func start() { + + NSLog("start ping %@",self.hostName) + + let pinger = SimplePing(hostName: self.hostName) + self.pinger = pinger + + pinger.delegate = self + pinger.start() + } + + /// Called by the table view selection delegate callback to stop the ping. + + func stop() { + NSLog("stop") + self.pinger?.stop() + self.pinger = nil + + self.sendTimer?.invalidate() + self.sendTimer = nil + } + + /// Sends a ping. + /// + /// Called to send a ping, both directly (as soon as the SimplePing object starts up) and + /// via a timer (to continue sending pings periodically). + + func sendPing() { + self.pinger!.send(with: nil) + } + + // MARK: pinger delegate callback + + func simplePing(_ pinger: SimplePing, didStartWithAddress address: Data) { + NSLog("pinging %@",hostName) + + // Send the first ping straight away. + + self.sendPing() + + // And start a timer to send the subsequent pings. + + assert(self.sendTimer == nil) + self.sendTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(PingTest.sendPing), userInfo: nil, repeats: true) + } + + func simplePing(_ pinger: SimplePing, didFailWithError error: Error) { + NSLog("failed: %@", PingTest.shortErrorFromError(error as NSError)) + + self.stop() + } + + func simplePing(_ pinger: SimplePing, didSendPacket packet: Data, sequenceNumber: UInt16) { + NSLog("#%u sent", sequenceNumber) + dateReference = Date() + } + + func simplePing(_ pinger: SimplePing, didFailToSendPacket packet: Data, sequenceNumber: UInt16, error: Error) { + NSLog("#%u send failed: %@", sequenceNumber, PingTest.shortErrorFromError(error as NSError)) + } + + func simplePing(_ pinger: SimplePing, didReceivePingResponsePacket packet: Data, sequenceNumber: UInt16) { + + pinger.stop() + + guard let dateReference = dateReference else { return } + + //timeIntervalSinceDate returns seconds, so we convert to milis + DispatchQueue.main.async(execute: { + let latency = Date().timeIntervalSince(dateReference) * 1000 + NSLog("#%u received, host=%@, size=%zu, latency=%.f", sequenceNumber, self.hostName , packet.count,latency) + let userNote = NSUserNotification() + userNote.title = "\(self.hostName) ping \(latency)".localized + userNote.subtitle = "Address can't not be recognized".localized + NSUserNotificationCenter.default + .deliver(userNote) + + }) + } + + func simplePing(_ pinger: SimplePing, didReceiveUnexpectedPacket packet: Data) { + NSLog("unexpected packet, size=%zu", packet.count) + } + + // MARK: utilities + + /// Returns the string representation of the supplied address. + /// + /// - parameter address: Contains a `(struct sockaddr)` with the address to render. + /// + /// - returns: A string representation of that address. + + static func displayAddressForAddress(_ address: Data) -> String { + var hostStr = [Int8](repeating: 0, count: Int(NI_MAXHOST)) + + let success = getnameinfo( + (address as NSData).bytes.bindMemory(to: sockaddr.self, capacity: address.count), + socklen_t(address.count), + &hostStr, + socklen_t(hostStr.count), + nil, + 0, + NI_NUMERICHOST + ) == 0 + let result: String + if success { + result = String(cString: hostStr) + } else { + result = "?" + } + return result + } + + /// Returns a short error string for the supplied error. + /// + /// - parameter error: The error to render. + /// + /// - returns: A short string representing that error. + + static func shortErrorFromError(_ error: NSError) -> String { + if error.domain == kCFErrorDomainCFNetwork as String && error.code == Int(CFNetworkErrors.cfHostErrorUnknown.rawValue) { + if let failureObj = error.userInfo[kCFGetAddrInfoFailureKey as AnyHashable] { + if let failureNum = failureObj as? NSNumber { + if failureNum.int32Value != 0 { + let f = gai_strerror(failureNum.int32Value) + if f != nil { + return String(cString: f!) + } + } + } + } + } + if let result = error.localizedFailureReason { + return result + } + return error.localizedDescription + } + class func pingArray(){//hostList : [String]) -> [[String : String]]{ +// return [["apple.com":"20"],["baidu.com":"20"]] + } +} + +