From 74536b63a5d66a45cedf90934fd53ebb90e4b078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=20=E5=8E=9F=E9=97=AF?= Date: Fri, 16 Dec 2016 15:47:26 +0800 Subject: [PATCH] =?UTF-8?q?Coding=20=E7=9B=91=E6=8E=A7=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cartfile | 2 + Cartfile.resolved | 1 + Coding_iOS.xcodeproj/project.pbxproj | 133 ++- Coding_iOS/AppDelegate.m | 3 + .../EADeviceToServerLog/EADeviceToServerLog.h | 14 + .../EADeviceToServerLog/EADeviceToServerLog.m | 402 +++++++++ .../EADeviceToServerLog/EANetTraceRoute.h | 16 + .../EADeviceToServerLog/EANetTraceRoute.m | 67 ++ .../LDNetDiagnoService/LDNetConnect.h | 41 + .../LDNetDiagnoService/LDNetConnect.m | 182 ++++ .../LDNetDiagnoService/LDNetDiagnoService.h | 81 ++ .../LDNetDiagnoService/LDNetDiagnoService.m | 439 ++++++++++ .../LDNetDiagnoService/LDNetGetAddress.h | 58 ++ .../LDNetDiagnoService/LDNetGetAddress.m | 378 ++++++++ .../LDNetDiagnoService/LDNetPing.h | 44 + .../LDNetDiagnoService/LDNetPing.m | 325 +++++++ .../LDNetDiagnoService/LDNetTimer.h | 25 + .../LDNetDiagnoService/LDNetTimer.m | 36 + .../LDNetDiagnoService/LDNetTraceRoute.h | 61 ++ .../LDNetDiagnoService/LDNetTraceRoute.m | 247 ++++++ .../LDNetDiagnoService/LDSimplePing.h | 269 ++++++ .../LDNetDiagnoService/LDSimplePing.m | 810 ++++++++++++++++++ .../LDNetDiagnoService/Route.h | 484 +++++++++++ .../Manager/EADeviceToServerLog/NSData+gzip.h | 14 + .../Manager/EADeviceToServerLog/NSData+gzip.m | 161 ++++ bootstrap | 1 + 26 files changed, 4292 insertions(+), 2 deletions(-) create mode 100644 Cartfile create mode 100644 Cartfile.resolved create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/EADeviceToServerLog.h create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/EADeviceToServerLog.m create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/EANetTraceRoute.h create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/EANetTraceRoute.m create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetConnect.h create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetConnect.m create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetDiagnoService.h create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetDiagnoService.m create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetGetAddress.h create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetGetAddress.m create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetPing.h create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetPing.m create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTimer.h create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTimer.m create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTraceRoute.h create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTraceRoute.m create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDSimplePing.h create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDSimplePing.m create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/Route.h create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/NSData+gzip.h create mode 100644 Coding_iOS/Util/Manager/EADeviceToServerLog/NSData+gzip.m diff --git a/Cartfile b/Cartfile new file mode 100644 index 000000000..2101d38ab --- /dev/null +++ b/Cartfile @@ -0,0 +1,2 @@ + +github "libgit2/objective-git" diff --git a/Cartfile.resolved b/Cartfile.resolved new file mode 100644 index 000000000..27951505c --- /dev/null +++ b/Cartfile.resolved @@ -0,0 +1 @@ +github "libgit2/objective-git" "0.12.0" diff --git a/Coding_iOS.xcodeproj/project.pbxproj b/Coding_iOS.xcodeproj/project.pbxproj index 185b6ccbb..e7b87533f 100644 --- a/Coding_iOS.xcodeproj/project.pbxproj +++ b/Coding_iOS.xcodeproj/project.pbxproj @@ -222,6 +222,20 @@ 4E2F6A701C43CA4B00A25502 /* member_type_90@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4E2F6A6A1C43CA4B00A25502 /* member_type_90@2x.png */; }; 4E2F6A711C43CA4B00A25502 /* member_type_90@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4E2F6A6B1C43CA4B00A25502 /* member_type_90@3x.png */; }; 4E35A99F1A3EC47E00CE35F1 /* FileViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E35A99E1A3EC47E00CE35F1 /* FileViewController.m */; }; + 4E363C991E03BEB4000C08C8 /* EADeviceToServerLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E363C841E03BEB4000C08C8 /* EADeviceToServerLog.m */; }; + 4E363C9A1E03BEB4000C08C8 /* EANetTraceRoute.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E363C861E03BEB4000C08C8 /* EANetTraceRoute.m */; }; + 4E363C9B1E03BEB4000C08C8 /* LDNetConnect.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E363C891E03BEB4000C08C8 /* LDNetConnect.m */; }; + 4E363C9C1E03BEB4000C08C8 /* LDNetDiagnoService.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E363C8B1E03BEB4000C08C8 /* LDNetDiagnoService.m */; }; + 4E363C9D1E03BEB4000C08C8 /* LDNetGetAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E363C8D1E03BEB4000C08C8 /* LDNetGetAddress.m */; }; + 4E363C9E1E03BEB4000C08C8 /* LDNetPing.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E363C8F1E03BEB4000C08C8 /* LDNetPing.m */; }; + 4E363C9F1E03BEB4000C08C8 /* LDNetTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E363C911E03BEB4000C08C8 /* LDNetTimer.m */; }; + 4E363CA01E03BEB4000C08C8 /* LDNetTraceRoute.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E363C931E03BEB4000C08C8 /* LDNetTraceRoute.m */; }; + 4E363CA11E03BEB4000C08C8 /* LDSimplePing.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E363C951E03BEB4000C08C8 /* LDSimplePing.m */; }; + 4E363CA21E03BEB5000C08C8 /* NSData+gzip.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E363C981E03BEB4000C08C8 /* NSData+gzip.m */; }; + 4E363CA61E03C1DA000C08C8 /* ObjectiveGit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E363CA51E03C1DA000C08C8 /* ObjectiveGit.framework */; }; + 4E363CA91E03C48B000C08C8 /* libresolv.9.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E363CA81E03C48B000C08C8 /* libresolv.9.tbd */; }; + 4E363CAB1E03C618000C08C8 /* ObjectiveGit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E363CAA1E03C618000C08C8 /* ObjectiveGit.framework */; }; + 4E363CAC1E03C618000C08C8 /* ObjectiveGit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4E363CAA1E03C618000C08C8 /* ObjectiveGit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4E38CF5F1A7A28AF005536C0 /* CodeBranchTagButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E38CF5E1A7A28AF005536C0 /* CodeBranchTagButton.m */; }; 4E38CF621A7B7C99005536C0 /* CodeBranchOrTag.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E38CF611A7B7C99005536C0 /* CodeBranchOrTag.m */; }; 4E38CF641A7B8DD4005536C0 /* icon_triangle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4E38CF631A7B8DD4005536C0 /* icon_triangle@2x.png */; }; @@ -1213,6 +1227,20 @@ E7A046A01A47279E00528C12 /* Helper.m in Sources */ = {isa = PBXBuildFile; fileRef = E7A0469F1A47279E00528C12 /* Helper.m */; }; /* End PBXBuildFile section */ +/* Begin PBXCopyFilesBuildPhase section */ + 4E363CAD1E03C618000C08C8 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 4E363CAC1E03C618000C08C8 /* ObjectiveGit.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 0A03E6D11ABD0F690034BB8E /* LocationHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocationHelper.h; sourceTree = ""; }; 0A03E6D21ABD0F690034BB8E /* LocationHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocationHelper.m; sourceTree = ""; }; @@ -1520,6 +1548,30 @@ 4E2F6A6B1C43CA4B00A25502 /* member_type_90@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "member_type_90@3x.png"; sourceTree = ""; }; 4E35A99D1A3EC47E00CE35F1 /* FileViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileViewController.h; sourceTree = ""; }; 4E35A99E1A3EC47E00CE35F1 /* FileViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileViewController.m; sourceTree = ""; }; + 4E363C831E03BEB4000C08C8 /* EADeviceToServerLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EADeviceToServerLog.h; sourceTree = ""; }; + 4E363C841E03BEB4000C08C8 /* EADeviceToServerLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EADeviceToServerLog.m; sourceTree = ""; }; + 4E363C851E03BEB4000C08C8 /* EANetTraceRoute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EANetTraceRoute.h; sourceTree = ""; }; + 4E363C861E03BEB4000C08C8 /* EANetTraceRoute.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EANetTraceRoute.m; sourceTree = ""; }; + 4E363C881E03BEB4000C08C8 /* LDNetConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LDNetConnect.h; sourceTree = ""; }; + 4E363C891E03BEB4000C08C8 /* LDNetConnect.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LDNetConnect.m; sourceTree = ""; }; + 4E363C8A1E03BEB4000C08C8 /* LDNetDiagnoService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LDNetDiagnoService.h; sourceTree = ""; }; + 4E363C8B1E03BEB4000C08C8 /* LDNetDiagnoService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LDNetDiagnoService.m; sourceTree = ""; }; + 4E363C8C1E03BEB4000C08C8 /* LDNetGetAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LDNetGetAddress.h; sourceTree = ""; }; + 4E363C8D1E03BEB4000C08C8 /* LDNetGetAddress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LDNetGetAddress.m; sourceTree = ""; }; + 4E363C8E1E03BEB4000C08C8 /* LDNetPing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LDNetPing.h; sourceTree = ""; }; + 4E363C8F1E03BEB4000C08C8 /* LDNetPing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LDNetPing.m; sourceTree = ""; }; + 4E363C901E03BEB4000C08C8 /* LDNetTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LDNetTimer.h; sourceTree = ""; }; + 4E363C911E03BEB4000C08C8 /* LDNetTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LDNetTimer.m; sourceTree = ""; }; + 4E363C921E03BEB4000C08C8 /* LDNetTraceRoute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LDNetTraceRoute.h; sourceTree = ""; }; + 4E363C931E03BEB4000C08C8 /* LDNetTraceRoute.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LDNetTraceRoute.m; sourceTree = ""; }; + 4E363C941E03BEB4000C08C8 /* LDSimplePing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LDSimplePing.h; sourceTree = ""; }; + 4E363C951E03BEB4000C08C8 /* LDSimplePing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LDSimplePing.m; sourceTree = ""; }; + 4E363C961E03BEB4000C08C8 /* Route.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Route.h; sourceTree = ""; }; + 4E363C971E03BEB4000C08C8 /* NSData+gzip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+gzip.h"; sourceTree = ""; }; + 4E363C981E03BEB4000C08C8 /* NSData+gzip.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+gzip.m"; sourceTree = ""; }; + 4E363CA51E03C1DA000C08C8 /* ObjectiveGit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjectiveGit.framework; path = Carthage/Build/iOS/ObjectiveGit.framework; sourceTree = ""; }; + 4E363CA81E03C48B000C08C8 /* libresolv.9.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.9.tbd; path = usr/lib/libresolv.9.tbd; sourceTree = SDKROOT; }; + 4E363CAA1E03C618000C08C8 /* ObjectiveGit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjectiveGit.framework; path = Carthage/Build/iOS/ObjectiveGit.framework; sourceTree = ""; }; 4E38CF5D1A7A28AF005536C0 /* CodeBranchTagButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeBranchTagButton.h; sourceTree = ""; }; 4E38CF5E1A7A28AF005536C0 /* CodeBranchTagButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CodeBranchTagButton.m; sourceTree = ""; }; 4E38CF601A7B7C99005536C0 /* CodeBranchOrTag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeBranchOrTag.h; sourceTree = ""; }; @@ -3001,9 +3053,12 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 4E363CA91E03C48B000C08C8 /* libresolv.9.tbd in Frameworks */, + 4E363CA61E03C1DA000C08C8 /* ObjectiveGit.framework in Frameworks */, 4EDBECEB1B709EB3003E87C3 /* AVFoundation.framework in Frameworks */, 0AB591AD1AB6D51C0076C454 /* MapKit.framework in Frameworks */, 0A6E6BBF1AB180CB004C0107 /* CoreLocation.framework in Frameworks */, + 4E363CAB1E03C618000C08C8 /* ObjectiveGit.framework in Frameworks */, 4EDD8F5C1A36F52700E9E232 /* libsqlite3.0.dylib in Frameworks */, 4EDD8F5A1A36F4FA00E9E232 /* Security.framework in Frameworks */, 4EDD8F581A36F4CA00E9E232 /* CoreTelephony.framework in Frameworks */, @@ -3401,6 +3456,42 @@ path = member_type; sourceTree = ""; }; + 4E363C821E03BEB4000C08C8 /* EADeviceToServerLog */ = { + isa = PBXGroup; + children = ( + 4E363C871E03BEB4000C08C8 /* LDNetDiagnoService */, + 4E363C831E03BEB4000C08C8 /* EADeviceToServerLog.h */, + 4E363C841E03BEB4000C08C8 /* EADeviceToServerLog.m */, + 4E363C851E03BEB4000C08C8 /* EANetTraceRoute.h */, + 4E363C861E03BEB4000C08C8 /* EANetTraceRoute.m */, + 4E363C971E03BEB4000C08C8 /* NSData+gzip.h */, + 4E363C981E03BEB4000C08C8 /* NSData+gzip.m */, + ); + path = EADeviceToServerLog; + sourceTree = ""; + }; + 4E363C871E03BEB4000C08C8 /* LDNetDiagnoService */ = { + isa = PBXGroup; + children = ( + 4E363C881E03BEB4000C08C8 /* LDNetConnect.h */, + 4E363C891E03BEB4000C08C8 /* LDNetConnect.m */, + 4E363C8A1E03BEB4000C08C8 /* LDNetDiagnoService.h */, + 4E363C8B1E03BEB4000C08C8 /* LDNetDiagnoService.m */, + 4E363C8C1E03BEB4000C08C8 /* LDNetGetAddress.h */, + 4E363C8D1E03BEB4000C08C8 /* LDNetGetAddress.m */, + 4E363C8E1E03BEB4000C08C8 /* LDNetPing.h */, + 4E363C8F1E03BEB4000C08C8 /* LDNetPing.m */, + 4E363C901E03BEB4000C08C8 /* LDNetTimer.h */, + 4E363C911E03BEB4000C08C8 /* LDNetTimer.m */, + 4E363C921E03BEB4000C08C8 /* LDNetTraceRoute.h */, + 4E363C931E03BEB4000C08C8 /* LDNetTraceRoute.m */, + 4E363C941E03BEB4000C08C8 /* LDSimplePing.h */, + 4E363C951E03BEB4000C08C8 /* LDSimplePing.m */, + 4E363C961E03BEB4000C08C8 /* Route.h */, + ); + path = LDNetDiagnoService; + sourceTree = ""; + }; 4E4972E51BB5446900F3AC15 /* tips_menu */ = { isa = PBXGroup; children = ( @@ -4201,6 +4292,7 @@ 4ECE8AEA1A3946C10021E29C /* Manager */ = { isa = PBXGroup; children = ( + 4E363C821E03BEB4000C08C8 /* EADeviceToServerLog */, 4ECE8AEB1A3946C10021E29C /* AddressManager.h */, 4ECE8AEC1A3946C10021E29C /* AddressManager.m */, 4ECE8AED1A3946C10021E29C /* Coding_FileManager.h */, @@ -4481,6 +4573,7 @@ 8E477007198770E700997D05 = { isa = PBXGroup; children = ( + 4E363CAA1E03C618000C08C8 /* ObjectiveGit.framework */, 8EA6CF1319E240C40076D59C /* Coding_iOS */, 8E477012198770E700997D05 /* Frameworks */, 8E477011198770E700997D05 /* Products */, @@ -4501,6 +4594,8 @@ 8E477012198770E700997D05 /* Frameworks */ = { isa = PBXGroup; children = ( + 4E363CA81E03C48B000C08C8 /* libresolv.9.tbd */, + 4E363CA51E03C1DA000C08C8 /* ObjectiveGit.framework */, 4EDBECEA1B709EB3003E87C3 /* AVFoundation.framework */, 4EF818231B09D8D8005F974B /* WebP.framework */, 0A6E6BBE1AB180CB004C0107 /* CoreLocation.framework */, @@ -5912,6 +6007,8 @@ 8E47700E198770E700997D05 /* Resources */, B52B540CD39100358CEE8516 /* [CP] Embed Pods Frameworks */, B7C390DEFD2073480C56FD88 /* [CP] Copy Pods Resources */, + 4E363CA71E03C240000C08C8 /* ShellScript */, + 4E363CAD1E03C618000C08C8 /* Embed Frameworks */, ); buildRules = ( ); @@ -6611,6 +6708,20 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 4E363CA71E03C240000C08C8 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework", + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks"; + }; B52B540CD39100358CEE8516 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -6698,6 +6809,7 @@ D0C447B91C02C63000DC1C4B /* UserSearchCell.m in Sources */, 4E83AE7B1CF30F1A006BA3BB /* SettingEmailViewController.m in Sources */, 8EF643BA19FF7E2900F7EEB0 /* MemberCell.m in Sources */, + 4E363C9F1E03BEB4000C08C8 /* LDNetTimer.m in Sources */, 4ECE8B021A3946C10021E29C /* JobManager.m in Sources */, 4E0BD8561B6C7DFD0061CAA6 /* UIView+Frame.m in Sources */, 4ECE8B031A3946C10021E29C /* TagsManager.m in Sources */, @@ -6713,6 +6825,7 @@ 4E996BE21ABA957B00C704F1 /* ProjectListViewController.m in Sources */, 4E743E6D1A88A3CC00DADDE5 /* EaseMarkdownTextView.m in Sources */, 8EA6D1B519E240C40076D59C /* ListGroupItem.m in Sources */, + 4E363C9A1E03BEB4000C08C8 /* EANetTraceRoute.m in Sources */, 4E80E93C1E02353900DE1BC6 /* CodingSearchDisplayView.m in Sources */, 8EA6D13919E240C40076D59C /* MyTask_RootViewController.m in Sources */, 8E1C3E0A19E8DFE300EF3032 /* SettingAccountViewController.m in Sources */, @@ -6736,6 +6849,7 @@ 4E2ECEAD1BD4D51000CB6EC9 /* ProjectTransferSettingViewController.m in Sources */, 4EABD2571AD3CAAC005E515F /* UIMessageInputView_Add.m in Sources */, 7EB02FCE1B6CF5D500D2166C /* UIMessageInputView_Voice.m in Sources */, + 4E363C9B1E03BEB4000C08C8 /* LDNetConnect.m in Sources */, 8E59F0E21A0098BA009A905F /* UIScrollView+SVInfiniteScrolling.m in Sources */, 4E0022831B72095E005308DE /* PointRecord.m in Sources */, 927AFF3E1BFF608700AAE593 /* ShopGoodsCCell.m in Sources */, @@ -6848,6 +6962,7 @@ 4E72F82D1B144778001B6CE6 /* NSMutableString+Common.m in Sources */, 4E25271A1C327FAE0032A7F4 /* UIViewController+BackButtonHandler.m in Sources */, 4EBD7FB41CE4833D00B3AF49 /* CountryCodeCell.m in Sources */, + 4E363C9E1E03BEB4000C08C8 /* LDNetPing.m in Sources */, 13C8FE7F1CA79B90001E30FA /* DynamicActivityCell.m in Sources */, 4E4D6A791B1C6C7800FD2E49 /* MRPRDetailCell.m in Sources */, 8EF643CA19FF7E2900F7EEB0 /* TopicContentCell.m in Sources */, @@ -6954,6 +7069,7 @@ 8EF643C219FF7E2900F7EEB0 /* TaskCommentTopCell.m in Sources */, 4E4D6A611B1C65C100FD2E49 /* MRPRCommitsViewController.m in Sources */, 8E64ED7D19ED0CE3006E99DA /* QBAssetsCollectionOverlayView.m in Sources */, + 4E363CA21E03BEB5000C08C8 /* NSData+gzip.m in Sources */, 4E0BD86B1B6C7E3D0061CAA6 /* CSLikesVC.m in Sources */, 8EA6D14919E240C40076D59C /* UserOrProjectTweetsViewController.m in Sources */, 4E4D6AA01B1D89D400FD2E49 /* CommitDetail.m in Sources */, @@ -6964,6 +7080,7 @@ 8EA6D1B319E240C40076D59C /* File.m in Sources */, 923399751C00ABDE00F29E04 /* ShopOrderViewController.m in Sources */, 4E8D5D7D1B462ADB00B70936 /* OTPTableViewCell.m in Sources */, + 4E363C9C1E03BEB4000C08C8 /* LDNetDiagnoService.m in Sources */, 4EABD25A1AD3CB4A005E515F /* UIMessageInputView_CCell.m in Sources */, 134E1BA61CA41671002A3E0D /* DemoModel.m in Sources */, 8EF643C019FF7E2900F7EEB0 /* TaskCommentBlankCell.m in Sources */, @@ -7067,6 +7184,7 @@ 8EF643CB19FF7E2900F7EEB0 /* TweetCell.m in Sources */, 4ECE8ADF1A3943E80021E29C /* UIBarButtonItem+Common.m in Sources */, 4E5D12FE1C0C5EE600985AEB /* RRFPSBar.m in Sources */, + 4E363C991E03BEB4000C08C8 /* EADeviceToServerLog.m in Sources */, 4E996BD01ABA774800C704F1 /* EaseUserHeaderView.m in Sources */, 4E0022921B721973005308DE /* PointRecordCell.m in Sources */, 4E5A66951B268D160007A0AD /* UIView+PressMenu.m in Sources */, @@ -7088,6 +7206,7 @@ 8EA6D1C919E240C40076D59C /* UICustomCollectionView.m in Sources */, 4ECE8ADC1A3943E80021E29C /* NSObject+Common.m in Sources */, 8E97CEBF1A0CB7E3006F9AD7 /* SMPageControl.m in Sources */, + 4E363C9D1E03BEB4000C08C8 /* LDNetGetAddress.m in Sources */, 8EA6D12A19E240C40076D59C /* Coding_iOS.xcdatamodeld in Sources */, 8EA6D12D19E240C40076D59C /* ConversationViewController.m in Sources */, 4EDC33CE1AFB4DCC00698315 /* EaseInputTipsView.m in Sources */, @@ -7121,6 +7240,7 @@ 4ECF70461B18557E000280FF /* MRPRS.m in Sources */, 4ECE8AE41A3943E80021E29C /* UIImage+Common.m in Sources */, 8EF643D619FF7E9F00F7EEB0 /* ProjectTopicCell.m in Sources */, + 4E363CA11E03BEB4000C08C8 /* LDSimplePing.m in Sources */, 4E4D6A8B1B1C6E3100FD2E49 /* TextCheckMarkCell.m in Sources */, 4E6BA2DA1A1EE6AF005FD721 /* AFHTTPSessionManager.m in Sources */, 4E94C5121B4E0C0300EB668A /* XHRealTimeBlur.m in Sources */, @@ -7199,6 +7319,7 @@ 4E715A351BB1279D00A5D24B /* LocalFileCell.m in Sources */, 1309B9FA1CA2D3960034C7A3 /* MRReviewerListCell.m in Sources */, 8EA6D1CB19E240C40076D59C /* UITapImageView.m in Sources */, + 4E363CA01E03BEB4000C08C8 /* LDNetTraceRoute.m in Sources */, 4E8D5D5D1B45295D00B70936 /* NSURL+OTPURLArguments.m in Sources */, 4EAE06AB1B7B23EA00179F4B /* FileActivitiesViewController.m in Sources */, 4E715A321BB1278200A5D24B /* LocalFolderCell.m in Sources */, @@ -7320,6 +7441,8 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", + "$(SRCROOT)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/iOS", ); GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -7329,9 +7452,11 @@ /usr/include/libxml2, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "Pods/evernote-cloud-sdk-ios/**", + "$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/", ); INFOPLIST_FILE = "Coding_iOS/Coding_iOS-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 7.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Coding_iOS/Vendor/XGPush", @@ -7360,6 +7485,8 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", + "$(SRCROOT)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Carthage/Build/iOS", ); GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -7369,9 +7496,11 @@ /usr/include/libxml2, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "Pods/evernote-cloud-sdk-ios/**", + "$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/", ); INFOPLIST_FILE = "Coding_iOS/Coding_iOS-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 7.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Coding_iOS/Vendor/XGPush", diff --git a/Coding_iOS/AppDelegate.m b/Coding_iOS/AppDelegate.m index de3206709..1bf8975b2 100644 --- a/Coding_iOS/AppDelegate.m +++ b/Coding_iOS/AppDelegate.m @@ -38,6 +38,7 @@ #import #import "UMSocialSinaSSOHandler.h" #import "Coding_NetAPIManager.h" +#import "EADeviceToServerLog.h" #import "Tweet.h" #import "sys/utsname.h" @@ -203,6 +204,8 @@ - (void)applicationDidBecomeActive:(UIApplication *)application #pragma clang diagnostic pop } } + // Coding 监控信息 + [[EADeviceToServerLog shareManager] tryToStart]; } - (void)applicationWillTerminate:(UIApplication *)application diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/EADeviceToServerLog.h b/Coding_iOS/Util/Manager/EADeviceToServerLog/EADeviceToServerLog.h new file mode 100644 index 000000000..4caeff494 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/EADeviceToServerLog.h @@ -0,0 +1,14 @@ +// +// EADeviceToServerLog.h +// CodingMart +// +// Created by Ease on 2016/11/28. +// Copyright © 2016年 net.coding. All rights reserved. +// + +#import + +@interface EADeviceToServerLog : NSObject ++ (instancetype)shareManager; +- (void)tryToStart; +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/EADeviceToServerLog.m b/Coding_iOS/Util/Manager/EADeviceToServerLog/EADeviceToServerLog.m new file mode 100644 index 000000000..3963806a4 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/EADeviceToServerLog.m @@ -0,0 +1,402 @@ +// +// EADeviceToServerLog.m +// CodingMart +// +// Created by Ease on 2016/11/28. +// Copyright © 2016年 net.coding. All rights reserved. +// + +//MinIntervalDutation 单位(秒) +#define kEALogKey_PostServerPath @"https://tracker.coding.net/v1" +#define kEALogKey_MinIntervalDutation (60 * 30 * 0) +#define kEALogKey_LogFileName @"deviceLog" +#define kEALogKey_LastTimeLogDate @"ealastTimeLogDate" +#define kEALogKey_StartTime @"startTime" +#define kEALogKey_FinishTime @"finishTime" +#define kEALogKey_LogInfo @"log" + +#import +#import +#import +#import //https://github.com/libgit2/objective-git +#import "EADeviceToServerLog.h" +#import "EANetTraceRoute.h" +#import "LDNetGetAddress.h" +#import "Login.h" +#import "AFNetworkReachabilityManager.h" +#import "NSData+gzip.h" + +@interface EADeviceToServerLog () +@property (strong, nonatomic) NSMutableDictionary *logDict; +@property (strong, nonatomic) NSArray *hostStrList, *portList; +@property (assign, nonatomic) BOOL isRunning; +@end + +@implementation EADeviceToServerLog + ++ (instancetype)shareManager{ + static EADeviceToServerLog *shared_manager = nil; + static dispatch_once_t pred; + dispatch_once(&pred, ^{ + shared_manager = [[self alloc] init]; + }); + return shared_manager; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _hostStrList = @[@"coding.net", + @"git.coding.net", + @"mart.coding.net"]; + _portList = @[@(80), + @(443)]; + } + return self; +} + +- (void)p_resetLog{ + if (!_logDict) { + _logDict = @{}.mutableCopy; + }else{ + [_logDict removeAllObjects]; + } + _logDict[kEALogKey_StartTime] = [self p_curTime]; +// 添加 App 信息 + _logDict[@"userAgent"] = [NSString userAgentStr]; + _logDict[@"globalKey"] = [Login curLoginUser].global_key ?: @"user_tourist"; +} + +- (void)p_addLog:(NSDictionary *)dict{ + for (NSString *key in dict) { + _logDict[key] = dict[key]; + } +} + +- (NSNumber *)p_curTime{ + return @((long)(1000 *[[NSDate date] timeIntervalSince1970])); +} + +- (NSString*)p_dictionaryToJson:(NSDictionary *)dict{ + NSError *parseError = nil; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&parseError]; + return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; +} + +- (void)p_updateLogDate{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setObject:[NSDate date] forKey:kEALogKey_LastTimeLogDate]; + [defaults synchronize]; +} + +- (NSDate *)p_lastTimeLogDate{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + return [defaults objectForKey:kEALogKey_LastTimeLogDate]; +} + +- (BOOL)p_canStartLog{ + if (_isRunning) { + return NO; + } + NSDate *lastTimeLogDate = [self p_lastTimeLogDate]; + if (!lastTimeLogDate) { + return YES; + }else{ + return [[NSDate date] timeIntervalSinceDate:lastTimeLogDate] > kEALogKey_MinIntervalDutation; + } +} + +- (void)tryToStart{ + if ([self p_canStartLog]) { + [self startLog]; + }else{ + [self tryToPostToServer]; + } +} + +- (void)tryToPostToServer{ + if (_isRunning) { + return; + } + _isRunning = YES; + NSString *logStr = [self p_readLog]; + if (logStr.length > 0) { + NSURL *url = [NSURL URLWithString:kEALogKey_PostServerPath]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + request.HTTPMethod = @"POST"; + request.HTTPBody = [self p_gzipStr:logStr]; + [request setValue:@"text/plain" forHTTPHeaderField:@"Content-Type"]; + [request setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"]; + __weak typeof(self) weakSelf = self; + NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + [weakSelf handlePostToServerSuccess:!error]; + }]; + [task resume]; + }else{ + _isRunning = NO; + } +} + +- (NSData *)p_gzipStr:(NSString *)string{ + NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; + data = [NSData gzipData:data]; + return data; +} + +- (void)handlePostToServerSuccess:(BOOL)isSuccess{ + _isRunning = NO; + if (isSuccess) { + NSString *logFilePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingFormat:@"/%@", kEALogKey_LogFileName]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:logFilePath]) { + [fileManager removeItemAtPath:logFilePath error:nil]; + } + } +} + +- (void)startLog{ + if (_isRunning) { + return; + } + _isRunning = YES; + [self p_resetLog]; + __weak typeof(self) weakSelf = self; + [self getLocalIPBlock:^(NSDictionary *dictLocalIP) { + if (!dictLocalIP) {//第一步获取 ip 不能完成的话,默认原因为连不上外网,取消截下来的监控步骤 + [weakSelf handleCancel]; + }else{ + [weakSelf p_addLog:dictLocalIP]; + [weakSelf getHostIPsBlock:^(NSDictionary *dictHostIPs) { + [weakSelf p_addLog:dictHostIPs]; + [weakSelf getHostPortsBlock:^(NSDictionary *dictHostPorts) { + [weakSelf p_addLog:dictHostPorts]; + [weakSelf getHostMtrsBlock:^(NSDictionary *dictHostMtrs) { + [weakSelf p_addLog:dictHostMtrs]; + [weakSelf getGitsBlock:^(NSDictionary *dictGits) { + [weakSelf p_addLog:dictGits]; + [weakSelf handleFinish]; + }]; + }]; + }]; + }]; + } + }]; +} + +- (void)handleFinish{ + _isRunning = NO; + _logDict[kEALogKey_FinishTime] = [self p_curTime]; + _logDict[@"logDuration"] = [NSString stringWithFormat:@"%ldms", ([_logDict[kEALogKey_FinishTime] longValue] - [_logDict[kEALogKey_StartTime] longValue])] ; + //写文件 + [self p_writeLog]; + [self p_resetLog]; + [self tryToPostToServer]; +} + + +- (void)handleCancel{ + _isRunning = NO; + [self p_resetLog]; +} + +- (void)p_writeLog{ + if (!_logDict) { + return; + } + NSData *logData = [NSJSONSerialization dataWithJSONObject:_logDict options:NSJSONWritingPrettyPrinted error:nil]; + NSString *logStr = [[NSString alloc] initWithData:logData encoding:NSUTF8StringEncoding]; + if (logStr.length <= 0) { + return; + } + NSString *logFilePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingFormat:@"/%@", kEALogKey_LogFileName]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:logFilePath]) { + logStr = [NSString stringWithFormat:@"\n--------------------------------------------------\n%@", logStr]; + NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:logFilePath]; + [fileHandle seekToEndOfFile]; + [fileHandle writeData:[logStr dataUsingEncoding:NSUTF8StringEncoding]]; + [fileHandle closeFile]; + }else{ + [logStr writeToFile:logFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; + } + [self p_updateLogDate]; +} + +- (NSString *)p_readLog{ + NSString *logFilePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingFormat:@"/%@", kEALogKey_LogFileName]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:logFilePath]) { + NSString *logStr = [[NSString alloc] initWithContentsOfFile:logFilePath encoding:NSUTF8StringEncoding error:nil]; + return logStr; + }else{ + return nil; + } +} + +- (void)getLocalIPBlock:(void(^)(NSDictionary *dictLocalIP))block{ + NSURL *url = [NSURL URLWithString:@"http://ip.cn"]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + request.HTTPMethod = @"GET"; + [request setValue:@"curl/7.41.0" forHTTPHeaderField:@"User-Agent"]; + NSMutableDictionary *dictLocalIP = @{kEALogKey_StartTime: [self p_curTime]}.mutableCopy; + __weak typeof(self) weakSelf = self; + NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + dictLocalIP[@"log"] = dataStr; + dictLocalIP[@"dns"] = [LDNetGetAddress outPutDNSServers]; + dictLocalIP[kEALogKey_FinishTime] = [weakSelf p_curTime]; + if (error) { + block(nil);//需要中断监控 + }else{ + block(@{@"localIp": dictLocalIP}); + } + }]; + [task resume]; +} + +- (void)getHostIPsBlock:(void(^)(NSDictionary *dictHostIPs))block{ + static NSMutableArray *dictHostIPList; + if (dictHostIPList.count == _hostStrList.count){ + block(@{@"hostIp": dictHostIPList}); + dictHostIPList = nil; + }else{ + if (!dictHostIPList) { + dictHostIPList = @[].mutableCopy; + } + __weak typeof(self) weakSelf = self; + [self getHost:_hostStrList[dictHostIPList.count] ipBlock:^(NSDictionary *dictHostIP) { + [dictHostIPList addObject:dictHostIP]; + [weakSelf getHostIPsBlock:block]; + }]; + } +} + +- (void)getHost:(NSString *)hostStr ipBlock:(void(^)(NSDictionary *dictHostIP))block{ + NSMutableDictionary *dictHostIP = @{kEALogKey_StartTime: [self p_curTime]}.mutableCopy; + dictHostIP[@"host"] = hostStr; + dictHostIP[@"ip"] = [self p_getIPWithHostName:hostStr]; + dictHostIP[kEALogKey_FinishTime] = [self p_curTime]; + block(dictHostIP); +} + +- (NSString *)p_getIPWithHostName:(NSString *)hostName{ + struct hostent *hs; + struct sockaddr_in server; + if ((hs = gethostbyname([hostName UTF8String])) != NULL) { + server.sin_addr = *((struct in_addr*)hs->h_addr_list[0]); + return [NSString stringWithUTF8String:inet_ntoa(server.sin_addr)]; + } + return nil; +} + +- (void)getHostPortsBlock:(void(^)(NSDictionary *dictHostPorts))block{ + static NSMutableArray *dictHostPortList; + if (dictHostPortList.count == _hostStrList.count * _portList.count){ + block(@{@"portScan": dictHostPortList}); + dictHostPortList = nil; + }else{ + if (!dictHostPortList) { + dictHostPortList = @[].mutableCopy; + } + __weak typeof(self) weakSelf = self; + [self getHost:_hostStrList[dictHostPortList.count / _portList.count] port:_portList[dictHostPortList.count % _portList.count] block:^(NSDictionary *dictHostPort) { + [dictHostPortList addObject:dictHostPort]; + [weakSelf getHostPortsBlock:block]; + }]; + } +} + +- (void)getHost:(NSString *)hostStr port:(NSNumber *)port block:(void(^)(NSDictionary *dictHostPort))block{ + NSMutableDictionary *dictHostPort = @{kEALogKey_StartTime: [self p_curTime]}.mutableCopy; + dictHostPort[@"host"] = hostStr; + dictHostPort[@"port"] = port; + NSString *errorStr = nil; + dictHostPort[@"result"] = @([self p_canLinkToHost:hostStr port:port errorStr:&errorStr]); + dictHostPort[kEALogKey_FinishTime] = [self p_curTime]; + block(dictHostPort); +} + +- (BOOL)p_canLinkToHost:(NSString *)hostStr port:(NSNumber *)port errorStr:(NSString **)errorStr{ + int socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0); + struct hostent *hs; + if (socketFileDescriptor == -1) { + *errorStr = @"创建 socket 失败"; + return NO; + }else if ((hs = gethostbyname([hostStr UTF8String])) == NULL){ + *errorStr = @"IP 地址解析失败"; + return NO; + }else{ + struct sockaddr_in socketParameters; + socketParameters.sin_family = AF_INET; + socketParameters.sin_addr = *((struct in_addr*)hs->h_addr_list[0]); + socketParameters.sin_port = htons(port.intValue); + int ret = connect(socketFileDescriptor, (struct sockaddr *) &socketParameters, sizeof(socketParameters)); + close(socketFileDescriptor); + if (ret == -1) { + *errorStr = @"socket 连接失败"; + return NO; + }else{//链接成功 + return YES; + } + } +} + +- (void)getHostMtrsBlock:(void(^)(NSDictionary *dictHostMtrs))block{ + NSString *dnsStr = [self.logDict[@"localIp"][@"dns"] firstObject]; + if (dnsStr.length > 0 && [dnsStr componentsSeparatedByString:@"."].count != 4) {//不是 ipv4 的暂时不处理 + block(nil); + return; + } + static NSMutableArray *dictHostMtrList; + if (!dictHostMtrList) { + dictHostMtrList = @[].mutableCopy; + } + if (dictHostMtrList.count == _hostStrList.count){ + block(@{@"mtr": dictHostMtrList}); + dictHostMtrList = nil; + }else{ + __weak typeof(self) weakSelf = self; + [self getHost:_hostStrList[dictHostMtrList.count] mtrBlock:^(NSDictionary *dictHostMtr) { + [dictHostMtrList addObject:dictHostMtr]; + [weakSelf getHostMtrsBlock:block]; + }]; + } +} + +- (void)getHost:(NSString *)hostStr mtrBlock:(void(^)(NSDictionary *dictHostMtr))block{ + NSMutableDictionary *dictHostMtr = @{kEALogKey_StartTime: [self p_curTime]}.mutableCopy; + dictHostMtr[@"host"] = hostStr; + [EANetTraceRoute getTraceRouteOfHost:hostStr block:^(NSArray *traceRouteList) { + dictHostMtr[@"pings"] = traceRouteList; + dictHostMtr[kEALogKey_FinishTime] = [self p_curTime]; + block(dictHostMtr); + }]; +} + +- (void)getGitsBlock:(void(^)(NSDictionary *dictGits))block{ + NSURL *repoURL = [NSURL URLWithString:@"https://git.coding.net/coding/test-point.git"]; + + NSFileManager* fileManager = [NSFileManager defaultManager]; + NSURL *appDocsDir = [fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask].lastObject; + NSURL *localURL = [NSURL URLWithString:repoURL.lastPathComponent relativeToURL:appDocsDir]; + if ([fileManager fileExistsAtPath:localURL.path isDirectory:nil]) {//已经存在的话,就先删掉 + [fileManager removeItemAtURL:localURL error:nil]; + } + + NSMutableDictionary *dictGits = @{kEALogKey_StartTime: [self p_curTime]}.mutableCopy; + dictGits[@"url"] = repoURL.absoluteString; + NSError* error = nil; + GTRepository *repo = [GTRepository cloneFromURL:repoURL toWorkingDirectory:localURL options:@{GTRepositoryCloneOptionsCheckout: @NO} error:&error transferProgressBlock:^(const git_transfer_progress *progress, BOOL *stop) { + DebugLog(@"received_objects_count: %d", progress->received_objects); + } checkoutProgressBlock:^(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps) {//{Checkout: @NO},所以这里不会执行 + DebugLog(@"checkout_progress:%.2f", (float)completedSteps/totalSteps); + }]; + + dictGits[kEALogKey_FinishTime] = [self p_curTime]; + dictGits[@"result"] = repo? @YES: @NO; + dictGits[kEALogKey_LogInfo] = error.description ?: @""; + block(@{@"git": dictGits}); +} + +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/EANetTraceRoute.h b/Coding_iOS/Util/Manager/EADeviceToServerLog/EANetTraceRoute.h new file mode 100644 index 000000000..5e53d4346 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/EANetTraceRoute.h @@ -0,0 +1,16 @@ +// +// EANetTraceRoute.h +// CodingMart +// +// Created by Ease on 2016/11/29. +// Copyright © 2016年 net.coding. All rights reserved. +// + +//libresolv.9.tbd +//CoreTelephony.framework + +#import + +@interface EANetTraceRoute : NSObject ++ (void)getTraceRouteOfHost:(NSString *)hostStr block:(void(^)(NSArray *traceRouteList))block; +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/EANetTraceRoute.m b/Coding_iOS/Util/Manager/EADeviceToServerLog/EANetTraceRoute.m new file mode 100644 index 000000000..6b74f9e84 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/EANetTraceRoute.m @@ -0,0 +1,67 @@ +// +// EANetTraceRoute.m +// CodingMart +// +// Created by Ease on 2016/11/29. +// Copyright © 2016年 net.coding. All rights reserved. +// + +#import "EANetTraceRoute.h" +#import "LDNetTraceRoute.h" + +@interface EANetTraceRoute () +@property (strong, nonatomic) LDNetTraceRoute *ldNTR; +@property (strong, nonatomic) NSString *hostStr; +@property (strong, nonatomic) NSMutableArray *traceRouteList; +@property (copy, nonatomic) void(^finishBlock)(NSArray *traceRouteList); + +@end + +@implementation EANetTraceRoute + ++ (instancetype)shareManager{ + static EANetTraceRoute *shared_manager = nil; + static dispatch_once_t pred; + dispatch_once(&pred, ^{ + shared_manager = [[self alloc] init]; + }); + return shared_manager; +} + ++ (void)getTraceRouteOfHost:(NSString *)hostStr block:(void(^)(NSArray *traceRouteList))block{ + EANetTraceRoute *eaNTR = [self shareManager]; + if ([eaNTR.ldNTR isRunning]) {//中断上一个 + [eaNTR.ldNTR stopTrace]; + [eaNTR traceRouteDidEnd]; + } + eaNTR.finishBlock = block; + [eaNTR doTraceRouteOfHost:hostStr]; +} + +- (void)doTraceRouteOfHost:(NSString *)hostStr{ + if (hostStr.length > 0) { + _hostStr = hostStr; + _traceRouteList = @[].mutableCopy; + if (!_ldNTR) { + _ldNTR = [[LDNetTraceRoute alloc] initWithMaxTTL:TRACEROUTE_MAX_TTL timeout:TRACEROUTE_TIMEOUT maxAttempts:5 port:TRACEROUTE_PORT]; + _ldNTR.delegate = self; + } + [NSThread detachNewThreadSelector:@selector(doTraceRoute:) + toTarget:_ldNTR + withObject:hostStr]; + }else{ + [self traceRouteDidEnd]; + } +} + +#pragma LDNetTraceRouteDelegate +- (void)appendRouteLog:(NSString *)routeLog{ + [_traceRouteList addObject:routeLog]; +} + +- (void)traceRouteDidEnd{ + if (_finishBlock) { + _finishBlock(_traceRouteList); + } +} +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetConnect.h b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetConnect.h new file mode 100644 index 000000000..72cd0523d --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetConnect.h @@ -0,0 +1,41 @@ +// +// LDNetConnect.h +// LDNetDiagnoServiceDemo +// +// Created by ZhangHaiyang on 15-8-5. +// Copyright (c) 2015年 庞辉. All rights reserved. +// + +#import + +/* + * @protocal LDNetConnectDelegate监测connect命令的的输出到日志变量; + * + */ +@protocol LDNetConnectDelegate +- (void)appendSocketLog:(NSString *)socketLog; +- (void)connectDidEnd:(BOOL)success; +@end + + +/* + * @class LDNetConnect ping监控 + * 主要是通过建立socket连接的过程,监控目标主机是否连通 + * 连续执行五次,因为每次的速度不一致,可以观察其平均速度来判断网络情况 + */ +@interface LDNetConnect : NSObject { +} + +@property (nonatomic, weak) id delegate; + +/** + * 通过hostaddress和port 进行connect诊断 + */ +- (void)runWithHostAddress:(NSString *)hostAddress port:(int)port; + +/** + * 停止connect + */ +- (void)stopConnect; + +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetConnect.m b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetConnect.m new file mode 100644 index 000000000..3307e24b6 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetConnect.m @@ -0,0 +1,182 @@ +// +// LDNetConnect.m +// LDNetDiagnoServiceDemo +// +// Created by ZhangHaiyang on 15-8-5. +// Copyright (c) 2015年 庞辉. All rights reserved. +// + +#import +#import +#import +#import + +#import "LDNetConnect.h" +#import "LDNetTimer.h" + +#define MAXCOUNT_CONNECT 4 + +@interface LDNetConnect () { + BOOL _isExistSuccess; //监测是否有connect成功 + int _connectCount; //当前执行次数 + + int tcpPort; //执行端口 + NSString *_hostAddress; //目标域名的IP地址 + BOOL _isIPV6; + NSString *_resultLog; + NSInteger _sumTime; + CFSocketRef _socket; +} + +@property (nonatomic, assign) long _startTime; //每次执行的开始时间 + +@end + +@implementation LDNetConnect +@synthesize _startTime; + +/** + * 停止connect + */ +- (void)stopConnect +{ + _connectCount = MAXCOUNT_CONNECT + 1; +} + +/** + * 通过hostaddress和port 进行connect诊断 + */ +- (void)runWithHostAddress:(NSString *)hostAddress port:(int)port +{ + _hostAddress = hostAddress; + _isIPV6 = [_hostAddress rangeOfString:@":"].location == NSNotFound?NO:YES; + tcpPort = port; + _isExistSuccess = FALSE; + _connectCount = 0; + _sumTime = 0; + _resultLog = @""; + if (self.delegate && [self.delegate respondsToSelector:@selector(appendSocketLog:)]) { + [self.delegate + appendSocketLog:[NSString stringWithFormat:@"connect to host %@ ...", _hostAddress]]; + } + _startTime = [LDNetTimer getMicroSeconds]; + [self connect]; + do { + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + } while (_connectCount < MAXCOUNT_CONNECT); +} + +/** + * 建立socket对hostaddress进行连接 + */ +- (void)connect +{ + NSData *addrData = nil; + + //设置地址 + if (!_isIPV6) { + struct sockaddr_in nativeAddr4; + memset(&nativeAddr4, 0, sizeof(nativeAddr4)); + nativeAddr4.sin_len = sizeof(nativeAddr4); + nativeAddr4.sin_family = AF_INET; + nativeAddr4.sin_port = htons(tcpPort); + inet_pton(AF_INET, _hostAddress.UTF8String, &nativeAddr4.sin_addr.s_addr); + addrData = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)]; + } else { + struct sockaddr_in6 nativeAddr6; + memset(&nativeAddr6, 0, sizeof(nativeAddr6)); + nativeAddr6.sin6_len = sizeof(nativeAddr6); + nativeAddr6.sin6_family = AF_INET6; + nativeAddr6.sin6_port = htons(tcpPort); + inet_pton(AF_INET6, _hostAddress.UTF8String, &nativeAddr6.sin6_addr); + addrData = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)]; + } + + if (addrData != nil) { + [self connectWithAddress:addrData]; + } +} + +-(void)connectWithAddress:(NSData *)addr{ + struct sockaddr *pSockAddr = (struct sockaddr *)[addr bytes]; + int addressFamily = pSockAddr->sa_family; + + //创建套接字 + CFSocketContext CTX = {0, (__bridge_retained void *)(self), NULL, NULL, NULL}; + _socket = CFSocketCreate(kCFAllocatorDefault, addressFamily, SOCK_STREAM, IPPROTO_TCP, + kCFSocketConnectCallBack, TCPServerConnectCallBack, &CTX); + + //执行连接 + CFSocketConnectToAddress(_socket, (__bridge CFDataRef)addr, 3); + CFRunLoopRef cfrl = CFRunLoopGetCurrent(); // 获取当前运行循环 + CFRunLoopSourceRef source = + CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket, _connectCount); //定义循环对象 + CFRunLoopAddSource(cfrl, source, kCFRunLoopDefaultMode); //将循环对象加入当前循环中 + CFRelease(source); +} + + +/** + * connect回调函数 + */ +static void TCPServerConnectCallBack(CFSocketRef socket, CFSocketCallBackType type, + CFDataRef address, const void *data, void *info) +{ + if (data != NULL) { + printf("connect"); + LDNetConnect *con = (__bridge_transfer LDNetConnect *)info; + [con readStream:FALSE]; + } else { + + LDNetConnect *con = (__bridge_transfer LDNetConnect *)info; + [con readStream:TRUE]; + } +} + +/** + * 返回之后的一系列操作 + */ +- (void)readStream:(BOOL)success +{ + // NSString *errorLog = @""; + if (success) { + _isExistSuccess = TRUE; + NSInteger interval = [LDNetTimer computeDurationSince:_startTime] / 1000; + _sumTime += interval; + NSLog(@"connect success %ld", (long)interval); + _resultLog = [_resultLog + stringByAppendingString:[NSString stringWithFormat:@"%d's time=%ldms, ", + _connectCount + 1, (long)interval]]; + } else { + _sumTime = 99999; + _resultLog = + [_resultLog stringByAppendingString:[NSString stringWithFormat:@"%d's time=TimeOut, ", + _connectCount + 1]]; + } + if (_connectCount == MAXCOUNT_CONNECT - 1) { + if (_sumTime >= 99999) { + _resultLog = [_resultLog substringToIndex:[_resultLog length] - 1]; + } else { + _resultLog = [_resultLog + stringByAppendingString:[NSString stringWithFormat:@"average=%ldms", + (long)(_sumTime / 4)]]; + } + if (self.delegate && [self.delegate respondsToSelector:@selector(appendSocketLog:)]) { + [self.delegate appendSocketLog:_resultLog]; + } + } + + CFRelease(_socket); + _connectCount++; + if (_connectCount < MAXCOUNT_CONNECT) { + _startTime = [LDNetTimer getMicroSeconds]; + [self connect]; + + } else { + if (self.delegate && [self.delegate respondsToSelector:@selector(connectDidEnd:)]) { + [self.delegate connectDidEnd:_isExistSuccess]; + } + } +} + +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetDiagnoService.h b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetDiagnoService.h new file mode 100644 index 000000000..02447c9c6 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetDiagnoService.h @@ -0,0 +1,81 @@ +// +// LDNetDiagnoService.h +// LDNetDiagnoServieDemo +// +// Created by 庞辉 on 14-10-29. +// Copyright (c) 2014年 庞辉. All rights reserved. +// + +#import + +/** + * @protocol 监控网络诊断的过程信息 + * + */ +@protocol LDNetDiagnoServiceDelegate +/** + * 告诉调用者诊断开始 + */ +- (void)netDiagnosisDidStarted; + + +/** + * 逐步返回监控信息, + * 如果需要实时显示诊断数据,实现此接口方法 + */ +- (void)netDiagnosisStepInfo:(NSString *)stepInfo; + + +/** + * 因为监控过程是一个异步过程,当监控结束后告诉调用者; + * 在监控结束的时候,对监控字符串进行处理 + */ +- (void)netDiagnosisDidEnd:(NSString *)allLogInfo; + +@end + + +/** + * @class 网络诊断服务 + * 通过对指定域名进行ping诊断和traceRoute诊断收集诊断日志 + */ +@interface LDNetDiagnoService : NSObject { +} +@property (nonatomic, weak, readwrite) + id delegate; //向调用者输出诊断信息接口 +@property (nonatomic, retain) NSString *dormain; //接口域名 + +/** + * 初始化网络诊断服务 + * theAppCode,theUID, theDormain为必填项 + */ +- (id)initWithAppCode:(NSString *)theAppCode + appName:(NSString *)theAppName + appVersion:(NSString *)theAppVersion + userID:(NSString *)theUID + deviceID:(NSString *)theDeviceID + dormain:(NSString *)theDormain + carrierName:(NSString *)theCarrierName + ISOCountryCode:(NSString *)theISOCountryCode + MobileCountryCode:(NSString *)theMobileCountryCode + MobileNetCode:(NSString *)theMobileNetCode; + + +/** + * 开始诊断网络 + */ +- (void)startNetDiagnosis; + + +/** + * 停止诊断网络 + */ +- (void)stopNetDialogsis; + + +/** + * 打印整体loginInfo; + */ +- (void)printLogInfo; + +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetDiagnoService.m b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetDiagnoService.m new file mode 100644 index 000000000..7dc8fb446 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetDiagnoService.m @@ -0,0 +1,439 @@ +// +// LDNetDiagnoService.m +// LDNetDiagnoServieDemo +// +// Created by 庞辉 on 14-10-29. +// Copyright (c) 2014年 庞辉. All rights reserved. +// +#import +#import +#import +#import "LDNetDiagnoService.h" +#import "LDNetPing.h" +#import "LDNetTraceRoute.h" +#import "LDNetGetAddress.h" +#import "LDNetTimer.h" +#import "LDNetConnect.h" + +static NSString *const kPingOpenServerIP = @""; +static NSString *const kCheckOutIPURL = @""; + +@interface LDNetDiagnoService () { + NSString *_appCode; //客户端标记 + NSString *_appName; + NSString *_appVersion; + NSString *_UID; //用户ID + NSString *_deviceID; //客户端机器ID,如果不传入会默认取API提供的机器ID + NSString *_carrierName; + NSString *_ISOCountryCode; + NSString *_MobileCountryCode; + NSString *_MobileNetCode; + + NETWORK_TYPE _curNetType; + NSString *_localIp; + NSString *_gatewayIp; + NSArray *_dnsServers; + NSArray *_hostAddress; + + NSMutableString *_logInfo; //记录网络诊断log日志 + BOOL _isRunning; + BOOL _connectSuccess; //记录连接是否成功 + LDNetPing *_netPinger; + LDNetTraceRoute *_traceRouter; + LDNetConnect *_netConnect; +} + +@end + +@implementation LDNetDiagnoService +#pragma mark - public method +/** + * 初始化网络诊断服务 + */ +- (id)initWithAppCode:(NSString *)theAppCode + appName:(NSString *)theAppName + appVersion:(NSString *)theAppVersion + userID:(NSString *)theUID + deviceID:(NSString *)theDeviceID + dormain:(NSString *)theDormain + carrierName:(NSString *)theCarrierName + ISOCountryCode:(NSString *)theISOCountryCode + MobileCountryCode:(NSString *)theMobileCountryCode + MobileNetCode:(NSString *)theMobileNetCode +{ + self = [super init]; + if (self) { + _appCode = theAppCode; + _appName = theAppName; + _appVersion = theAppVersion; + _UID = theUID; + _deviceID = theDeviceID; + _dormain = theDormain; + _carrierName = theCarrierName; + _ISOCountryCode = theISOCountryCode; + _MobileCountryCode = theMobileCountryCode; + _MobileNetCode = theMobileNetCode; + + _logInfo = [[NSMutableString alloc] initWithCapacity:20]; + _isRunning = NO; + } + + return self; +} + + +/** + * 开始诊断网络 + */ +- (void)startNetDiagnosis +{ + if (!_dormain || [_dormain isEqualToString:@""]) return; + + _isRunning = YES; + [_logInfo setString:@""]; + [self recordStepInfo:@"开始诊断..."]; + [self recordCurrentAppVersion]; + [self recordLocalNetEnvironment]; + + //未联网不进行任何检测 + if (_curNetType == 0) { + _isRunning = NO; + [self recordStepInfo:@"\n当前主机未联网,请检查网络!"]; + [self recordStepInfo:@"\n网络诊断结束\n"]; + if (self.delegate && [self.delegate respondsToSelector:@selector(netDiagnosisDidEnd:)]) { + [self.delegate netDiagnosisDidEnd:_logInfo]; + } + return; + } + + if (_isRunning) { +// [self recordOutIPInfo]; + } + + if (_isRunning) { + // connect诊断,同步过程, 如果TCP无法连接,检查本地网络环境 + _connectSuccess = NO; + [self recordStepInfo:@"\n开始TCP连接测试..."]; + if ([_hostAddress count] > 0) { + _netConnect = [[LDNetConnect alloc] init]; + _netConnect.delegate = self; + for (int i = 0; i < [_hostAddress count]; i++) { + [_netConnect runWithHostAddress:[_hostAddress objectAtIndex:i] port:80]; + } + } else { + [self recordStepInfo:@"DNS解析失败,主机地址不可达"]; + } + if (_isRunning) { + [self pingDialogsis:!_connectSuccess]; + } + } + + + if (_isRunning) { + //开始诊断traceRoute + [self recordStepInfo:@"\n开始traceroute..."]; + _traceRouter = [[LDNetTraceRoute alloc] initWithMaxTTL:TRACEROUTE_MAX_TTL + timeout:TRACEROUTE_TIMEOUT + maxAttempts:TRACEROUTE_ATTEMPTS + port:TRACEROUTE_PORT]; + _traceRouter.delegate = self; + if (_traceRouter) { + [NSThread detachNewThreadSelector:@selector(doTraceRoute:) + toTarget:_traceRouter + withObject:_dormain]; + } + } +} + + +/** + * 停止诊断网络, 清空诊断状态 + */ +- (void)stopNetDialogsis +{ + if (_isRunning) { + if (_netConnect != nil) { + [_netConnect stopConnect]; + _netConnect = nil; + } + + if (_netPinger != nil) { + [_netPinger stopPing]; + _netPinger = nil; + } + + if (_traceRouter != nil) { + [_traceRouter stopTrace]; + _traceRouter = nil; + } + + _isRunning = NO; + } +} + + +/** + * 打印整体loginInfo; + */ +- (void)printLogInfo +{ + NSLog(@"\n%@\n", _logInfo); +} + + +#pragma mark - +#pragma mark - private method + +/*! + * @brief 获取App相关信息 + */ +- (void)recordCurrentAppVersion +{ + //输出应用版本信息和用户ID + [self recordStepInfo:[NSString stringWithFormat:@"应用code: %@", _appCode]]; + NSDictionary *dicBundle = [[NSBundle mainBundle] infoDictionary]; + + if (!_appName || [_appName isEqualToString:@""]) { + _appName = [dicBundle objectForKey:@"CFBundleDisplayName"]; + } + [self recordStepInfo:[NSString stringWithFormat:@"应用名称: %@", _appName]]; + + if (!_appVersion || [_appVersion isEqualToString:@""]) { + _appVersion = [dicBundle objectForKey:@"CFBundleShortVersionString"]; + } + [self recordStepInfo:[NSString stringWithFormat:@"应用版本: %@", _appVersion]]; + [self recordStepInfo:[NSString stringWithFormat:@"用户id: %@", _UID]]; + + //输出机器信息 + UIDevice *device = [UIDevice currentDevice]; + [self recordStepInfo:[NSString stringWithFormat:@"机器类型: %@", [device systemName]]]; + [self recordStepInfo:[NSString stringWithFormat:@"系统版本: %@", [device systemVersion]]]; + if (!_deviceID || [_deviceID isEqualToString:@""]) { + _deviceID = [self uniqueAppInstanceIdentifier]; + } + [self recordStepInfo:[NSString stringWithFormat:@"机器ID: %@", _deviceID]]; + + + //运营商信息 + if (!_carrierName || [_carrierName isEqualToString:@""]) { + CTTelephonyNetworkInfo *netInfo = [[CTTelephonyNetworkInfo alloc] init]; + CTCarrier *carrier = [netInfo subscriberCellularProvider]; + if (carrier != NULL) { + _carrierName = [carrier carrierName]; + _ISOCountryCode = [carrier isoCountryCode]; + _MobileCountryCode = [carrier mobileCountryCode]; + _MobileNetCode = [carrier mobileNetworkCode]; + } else { + _carrierName = @""; + _ISOCountryCode = @""; + _MobileCountryCode = @""; + _MobileNetCode = @""; + } + } + + [self recordStepInfo:[NSString stringWithFormat:@"运营商: %@", _carrierName]]; + [self recordStepInfo:[NSString stringWithFormat:@"ISOCountryCode: %@", _ISOCountryCode]]; + [self recordStepInfo:[NSString stringWithFormat:@"MobileCountryCode: %@", _MobileCountryCode]]; + [self recordStepInfo:[NSString stringWithFormat:@"MobileNetworkCode: %@", _MobileNetCode]]; +} + + +/*! + * @brief 获取本地网络环境信息 + */ +- (void)recordLocalNetEnvironment +{ + [self recordStepInfo:[NSString stringWithFormat:@"\n\n诊断域名 %@...\n", _dormain]]; + //判断是否联网以及获取网络类型 + NSArray *typeArr = [NSArray arrayWithObjects:@"2G", @"3G", @"4G", @"5G", @"wifi", nil]; + _curNetType = [LDNetGetAddress getNetworkTypeFromStatusBar]; + if (_curNetType == 0) { + [self recordStepInfo:[NSString stringWithFormat:@"当前是否联网: 未联网"]]; + } else { + [self recordStepInfo:[NSString stringWithFormat:@"当前是否联网: 已联网"]]; + if (_curNetType > 0 && _curNetType < 6) { + [self + recordStepInfo:[NSString stringWithFormat:@"当前联网类型: %@", + [typeArr objectAtIndex:_curNetType - 1]]]; + } + } + + //本地ip信息 + _localIp = [LDNetGetAddress deviceIPAdress]; + [self recordStepInfo:[NSString stringWithFormat:@"当前本机IP: %@", _localIp]]; + + if (_curNetType == NETWORK_TYPE_WIFI) { + _gatewayIp = [LDNetGetAddress getGatewayIPAddress]; + [self recordStepInfo:[NSString stringWithFormat:@"本地网关: %@", _gatewayIp]]; + } else { + _gatewayIp = @""; + } + + + _dnsServers = [NSArray arrayWithArray:[LDNetGetAddress outPutDNSServers]]; + [self recordStepInfo:[NSString stringWithFormat:@"本地DNS: %@", + [_dnsServers componentsJoinedByString:@", "]]]; + + [self recordStepInfo:[NSString stringWithFormat:@"远端域名: %@", _dormain]]; + + // host地址IP列表 + long time_start = [LDNetTimer getMicroSeconds]; + _hostAddress = [NSArray arrayWithArray:[LDNetGetAddress getDNSsWithDormain:_dormain]]; + long time_duration = [LDNetTimer computeDurationSince:time_start] / 1000; + if ([_hostAddress count] == 0) { + [self recordStepInfo:[NSString stringWithFormat:@"DNS解析结果: 解析失败"]]; + } else { + [self + recordStepInfo:[NSString stringWithFormat:@"DNS解析结果: %@ (%ldms)", + [_hostAddress componentsJoinedByString:@", "], + time_duration]]; + } +} + +/** + * 使用接口获取用户的出口IP和DNS信息 + */ +- (void)recordOutIPInfo +{ + [self recordStepInfo:@"\n开始获取运营商信息..."]; + // 初始化请求, 这里是变长的, 方便扩展 + NSMutableURLRequest *request = + [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:kCheckOutIPURL] + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:10]; + + // 发送同步请求, data就是返回的数据 + NSError *error = nil; + NSData *data = + [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error]; + if (error != nil) { + NSLog(@"error = %@", error); + [self recordStepInfo:@"\n获取超时"]; + return; + } + NSString *response = [[NSString alloc] initWithData:data encoding:0x80000632]; + NSLog(@"response: %@", response); + [self recordStepInfo:response]; +} + + +/** + * 构建ping列表并进行ping诊断 + */ +- (void)pingDialogsis:(BOOL)pingLocal +{ + //诊断ping信息, 同步过程 + NSMutableArray *pingAdd = [[NSMutableArray alloc] init]; + NSMutableArray *pingInfo = [[NSMutableArray alloc] init]; + if (pingLocal) { + [pingAdd addObject:@"127.0.0.1"]; + [pingInfo addObject:@"本机"]; + [pingAdd addObject:_localIp]; + [pingInfo addObject:@"本机IP"]; + if (_gatewayIp && ![_gatewayIp isEqualToString:@""]) { + [pingAdd addObject:_gatewayIp]; + [pingInfo addObject:@"本地网关"]; + } + if ([_dnsServers count] > 0) { + [pingAdd addObject:[_dnsServers objectAtIndex:0]]; + [pingInfo addObject:@"DNS服务器"]; + } + } + + //不管服务器解析DNS是否可达,均需要ping指定ip地址 + if([_localIp rangeOfString:@":"].location == NSNotFound){ + [pingAdd addObject:kPingOpenServerIP]; + [pingInfo addObject:@"开放服务器"]; + } + + [self recordStepInfo:@"\n开始ping..."]; + _netPinger = [[LDNetPing alloc] init]; + _netPinger.delegate = self; + for (int i = 0; i < [pingAdd count]; i++) { + [self recordStepInfo:[NSString stringWithFormat:@"ping: %@ %@ ...", + [pingInfo objectAtIndex:i], + [pingAdd objectAtIndex:i]]]; + if ([[pingAdd objectAtIndex:i] isEqualToString:kPingOpenServerIP]) { + [_netPinger runWithHostName:[pingAdd objectAtIndex:i] normalPing:YES]; + } else { + [_netPinger runWithHostName:[pingAdd objectAtIndex:i] normalPing:YES]; + } + } +} + + +#pragma mark - +#pragma mark - netPingDelegate + +- (void)appendPingLog:(NSString *)pingLog +{ + [self recordStepInfo:pingLog]; +} + +- (void)netPingDidEnd +{ + // net +} + +#pragma mark - traceRouteDelegate +- (void)appendRouteLog:(NSString *)routeLog +{ + [self recordStepInfo:routeLog]; +} + +- (void)traceRouteDidEnd +{ + _isRunning = NO; + [self recordStepInfo:@"\n网络诊断结束\n"]; + if (self.delegate && [self.delegate respondsToSelector:@selector(netDiagnosisDidEnd:)]) { + [self.delegate netDiagnosisDidEnd:_logInfo]; + } +} + +#pragma mark - connectDelegate +- (void)appendSocketLog:(NSString *)socketLog +{ + [self recordStepInfo:socketLog]; +} + +- (void)connectDidEnd:(BOOL)success +{ + if (success) { + _connectSuccess = YES; + } +} + + +#pragma mark - common method +/** + * 如果调用者实现了stepInfo接口,输出信息 + */ +- (void)recordStepInfo:(NSString *)stepInfo +{ + if (stepInfo == nil) stepInfo = @""; + [_logInfo appendString:stepInfo]; + [_logInfo appendString:@"\n"]; + + if (self.delegate && [self.delegate respondsToSelector:@selector(netDiagnosisStepInfo:)]) { + [self.delegate netDiagnosisStepInfo:[NSString stringWithFormat:@"%@\n", stepInfo]]; + } +} + + +/** + * 获取deviceID + */ +- (NSString *)uniqueAppInstanceIdentifier +{ + NSString *app_uuid = @""; + CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault); + CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef); + app_uuid = [NSString stringWithString:(__bridge NSString *)uuidString]; + CFRelease(uuidString); + CFRelease(uuidRef); + return app_uuid; +} + + +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetGetAddress.h b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetGetAddress.h new file mode 100644 index 000000000..c359a4772 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetGetAddress.h @@ -0,0 +1,58 @@ +// +// LDNetGetAddress.h +// LDNetDiagnoServiceDemo +// +// Created by ZhangHaiyang on 15-8-5. +// Copyright (c) 2015年 庞辉. All rights reserved. +// + +#import +#import + +@interface LDNetGetAddress : NSObject + +//网络类型 +typedef enum { + NETWORK_TYPE_NONE = 0, + NETWORK_TYPE_2G = 1, + NETWORK_TYPE_3G = 2, + NETWORK_TYPE_4G = 3, + NETWORK_TYPE_5G = 4, // 5G目前为猜测结果 + NETWORK_TYPE_WIFI = 5, +} NETWORK_TYPE; + +/*! + * 获取当前设备ip地址 + */ ++ (NSString *)deviceIPAdress; + + +/*! + * 获取当前设备网关地址 + */ ++ (NSString *)getGatewayIPAddress; + + +/*! + * 通过域名获取服务器DNS地址 + */ ++ (NSArray *)getDNSsWithDormain:(NSString *)hostName; + + +/*! + * 获取本地网络的DNS地址 + */ ++ (NSArray *)outPutDNSServers; + + +/*! + * 获取当前网络类型 + */ ++ (NETWORK_TYPE)getNetworkTypeFromStatusBar; + +/** + * 格式化IPV6地址 + */ ++(NSString *)formatIPV6Address:(struct in6_addr)ipv6Addr; + +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetGetAddress.m b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetGetAddress.m new file mode 100644 index 000000000..0cf9800de --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetGetAddress.m @@ -0,0 +1,378 @@ +// +// LDNetGetAddress.m +// LDNetDiagnoServiceDemo +// +// Created by ZhangHaiyang on 15-8-5. +// Copyright (c) 2015年 庞辉. All rights reserved. +// + +#import "LDNetGetAddress.h" +#include +#include +#include +#include + +#include +#include + +#import +#import + +#if TARGET_IPHONE_SIMULATOR +#include +#else +#include "Route.h" +#endif /*the very same from google-code*/ + +#define ROUNDUP(a) ((a) > 0 ? (1 + (((a)-1) | (sizeof(long) - 1))) : sizeof(long)) + +@implementation LDNetGetAddress + + +/*! + * 获取当前设备ip地址 + */ ++ (NSString *)deviceIPAdress +{ + NSString *address = @""; + struct ifaddrs *interfaces = NULL; + struct ifaddrs *temp_addr = NULL; + int success = 0; + + success = getifaddrs(&interfaces); + + if (success == 0) { // 0 表示获取成功 + + temp_addr = interfaces; + while (temp_addr != NULL) { + NSLog(@"ifa_name===%@",[NSString stringWithUTF8String:temp_addr->ifa_name]); + // Check if interface is en0 which is the wifi connection on the iPhone + if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"] || [[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"pdp_ip0"]) + { + //如果是IPV4地址,直接转化 + if (temp_addr->ifa_addr->sa_family == AF_INET){ + // Get NSString from C String + address = [self formatIPV4Address:((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr]; + } + + //如果是IPV6地址 + else if (temp_addr->ifa_addr->sa_family == AF_INET6){ + address = [self formatIPV6Address:((struct sockaddr_in6 *)temp_addr->ifa_addr)->sin6_addr]; + if (address && ![address isEqualToString:@""] && ![address.uppercaseString hasPrefix:@"FE80"]) break; + } + } + + temp_addr = temp_addr->ifa_next; + } + } + + freeifaddrs(interfaces); + + //以FE80开始的地址是单播地址 + if (address && ![address isEqualToString:@""] && ![address.uppercaseString hasPrefix:@"FE80"]) { + return address; + } else { + return @"127.0.0.1"; + } +} + +/*! + * 获取当前设备网关地址 + */ ++ (NSString *)getGatewayIPAddress{ + NSString *address = nil; + + NSString *gatewayIPV4 = [self getGatewayIPV4Address]; + NSString *gatewayIPV6 = [self getGatewayIPV6Address]; + + if (gatewayIPV6 != nil) { + address = gatewayIPV6; + } else { + address = gatewayIPV4; + } + + return address; +} + + ++ (NSString *)getGatewayIPV4Address +{ + + NSString *address = nil; + + /* net.route.0.inet.flags.gateway */ + int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY}; + + size_t l; + char *buf, *p; + struct rt_msghdr *rt; + struct sockaddr *sa; + struct sockaddr *sa_tab[RTAX_MAX]; + int i; + + if (sysctl(mib, sizeof(mib) / sizeof(int), 0, &l, 0, 0) < 0) { + address = @"192.168.0.1"; + } + + if (l > 0) { + buf = malloc(l); + if (sysctl(mib, sizeof(mib) / sizeof(int), buf, &l, 0, 0) < 0) { + address = @"192.168.0.1"; + } + + for (p = buf; p < buf + l; p += rt->rtm_msglen) { + rt = (struct rt_msghdr *)p; + sa = (struct sockaddr *)(rt + 1); + for (i = 0; i < RTAX_MAX; i++) { + if (rt->rtm_addrs & (1 << i)) { + sa_tab[i] = sa; + sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len)); + } else { + sa_tab[i] = NULL; + } + } + + if (((rt->rtm_addrs & (RTA_DST | RTA_GATEWAY)) == (RTA_DST | RTA_GATEWAY)) && + sa_tab[RTAX_DST]->sa_family == AF_INET && + sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) { + unsigned char octet[4] = {0, 0, 0, 0}; + int i; + for (i = 0; i < 4; i++) { + octet[i] = (((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr >> + (i * 8)) & + 0xFF; + } + if (((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) { + in_addr_t addr = + ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr; + address = [self formatIPV4Address:*((struct in_addr *)&addr)]; + NSLog(@"IPV4address%@", address); + break; + } + } + } + free(buf); + } + + return address; +} + ++ (NSString *)getGatewayIPV6Address +{ + + NSString *address = nil; + + /* net.route.0.inet.flags.gateway */ + int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY}; + + size_t l; + char *buf, *p; + struct rt_msghdr *rt; + struct sockaddr_in6 *sa; + struct sockaddr_in6 *sa_tab[RTAX_MAX]; + int i; + + if (sysctl(mib, sizeof(mib) / sizeof(int), 0, &l, 0, 0) < 0) { + address = @"192.168.0.1"; + } + + if (l > 0) { + buf = malloc(l); + if (sysctl(mib, sizeof(mib) / sizeof(int), buf, &l, 0, 0) < 0) { + address = @"192.168.0.1"; + } + + for (p = buf; p < buf + l; p += rt->rtm_msglen) { + rt = (struct rt_msghdr *)p; + sa = (struct sockaddr_in6 *)(rt + 1); + for (i = 0; i < RTAX_MAX; i++) { + if (rt->rtm_addrs & (1 << i)) { + sa_tab[i] = sa; + sa = (struct sockaddr_in6 *)((char *)sa + sa->sin6_len); + } else { + sa_tab[i] = NULL; + } + } + + if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) + && sa_tab[RTAX_DST]->sin6_family == AF_INET6 + && sa_tab[RTAX_GATEWAY]->sin6_family == AF_INET6) + { + address = [self formatIPV6Address:((struct sockaddr_in6 *)(sa_tab[RTAX_GATEWAY]))->sin6_addr]; + NSLog(@"IPV6address%@", address); + break; + } + } + free(buf); + } + + return address; +} + + +/*! + * 通过hostname获取ip列表 DNS解析地址 + */ ++ (NSArray *)getDNSsWithDormain:(NSString *)hostName{ + NSMutableArray *result = [[NSMutableArray alloc] init]; + NSArray *IPV4DNSs = [self getIPV4DNSWithHostName:hostName]; + if (IPV4DNSs && IPV4DNSs.count > 0) { + [result addObjectsFromArray:IPV4DNSs]; + } + + //由于在IPV6环境下不能用IPV4的地址进行连接监测 + //所以只返回IPV6的服务器DNS地址 + NSArray *IPV6DNSs = [self getIPV6DNSWithHostName:hostName]; + if (IPV6DNSs && IPV6DNSs.count > 0) { + [result removeAllObjects]; + [result addObjectsFromArray:IPV6DNSs]; + } + + return [NSArray arrayWithArray:result]; +} + + ++ (NSArray *)getIPV4DNSWithHostName:(NSString *)hostName +{ + const char *hostN = [hostName UTF8String]; + struct hostent *phot; + + @try { + phot = gethostbyname(hostN); + } @catch (NSException *exception) { + return nil; + } + + NSMutableArray *result = [[NSMutableArray alloc] init]; + int j = 0; + while (phot && phot->h_addr_list && phot->h_addr_list[j]) { + struct in_addr ip_addr; + memcpy(&ip_addr, phot->h_addr_list[j], 4); + char ip[20] = {0}; + inet_ntop(AF_INET, &ip_addr, ip, sizeof(ip)); + + NSString *strIPAddress = [NSString stringWithUTF8String:ip]; + [result addObject:strIPAddress]; + j++; + } + + return [NSArray arrayWithArray:result]; +} + + ++ (NSArray *)getIPV6DNSWithHostName:(NSString *)hostName +{ + const char *hostN = [hostName UTF8String]; + struct hostent *phot; + + @try { + /** + * 只有在IPV6的网络下才会有返回值 + */ + phot = gethostbyname2(hostN, AF_INET6); + } @catch (NSException *exception) { + return nil; + } + + NSMutableArray *result = [[NSMutableArray alloc] init]; + int j = 0; + while (phot && phot->h_addr_list && phot->h_addr_list[j]) { + struct in6_addr ip6_addr; + memcpy(&ip6_addr, phot->h_addr_list[j], sizeof(struct in6_addr)); + NSString *strIPAddress = [self formatIPV6Address: ip6_addr]; + [result addObject:strIPAddress]; + j++; + } + + return [NSArray arrayWithArray:result]; +} + + +/*! + * 获取当前网络DNS服务器地址 + */ ++(NSArray *)outPutDNSServers{ + res_state res = malloc(sizeof(struct __res_state)); + int result = res_ninit(res); + + NSMutableArray *servers = [[NSMutableArray alloc] init]; + if (result == 0) { + union res_9_sockaddr_union *addr_union = malloc(res->nscount * sizeof(union res_9_sockaddr_union)); + res_getservers(res, addr_union, res->nscount); + + for (int i = 0; i < res->nscount; i++) { + if (addr_union[i].sin.sin_family == AF_INET) { + char ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(addr_union[i].sin.sin_addr), ip, INET_ADDRSTRLEN); + NSString *dnsIP = [NSString stringWithUTF8String:ip]; + [servers addObject:dnsIP]; + NSLog(@"IPv4 DNS IP: %@", dnsIP); + } else if (addr_union[i].sin6.sin6_family == AF_INET6) { + char ip[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &(addr_union[i].sin6.sin6_addr), ip, INET6_ADDRSTRLEN); + NSString *dnsIP = [NSString stringWithUTF8String:ip]; + [servers addObject:dnsIP]; + NSLog(@"IPv6 DNS IP: %@", dnsIP); + } else { + NSLog(@"Undefined family."); + } + } + } + res_nclose(res); + free(res); + + return [NSArray arrayWithArray:servers]; +} + + +/*! + * 获取当前网络类型 + * 通过statusBar的网络subview获取具体类型 + */ ++ (NETWORK_TYPE)getNetworkTypeFromStatusBar +{ + NSArray *subviews = [[[[UIApplication sharedApplication] valueForKey:@"statusBar"] + valueForKey:@"foregroundView"] subviews]; + NSNumber *dataNetworkItemView = nil; + for (id subview in subviews) { + if ([subview isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]]) { + dataNetworkItemView = subview; + break; + } + } + NETWORK_TYPE nettype = NETWORK_TYPE_NONE; + NSNumber *num = [dataNetworkItemView valueForKey:@"dataNetworkType"]; + nettype = [num intValue]; + return nettype; +} + + ++(NSString *)formatIPV6Address:(struct in6_addr)ipv6Addr{ + NSString *address = nil; + + char dstStr[INET6_ADDRSTRLEN]; + char srcStr[INET6_ADDRSTRLEN]; + memcpy(srcStr, &ipv6Addr, sizeof(struct in6_addr)); + if(inet_ntop(AF_INET6, srcStr, dstStr, INET6_ADDRSTRLEN) != NULL){ + address = [NSString stringWithUTF8String:dstStr]; + } + + return address; +} + + ++(NSString *)formatIPV4Address:(struct in_addr)ipv4Addr{ + NSString *address = nil; + + char dstStr[INET_ADDRSTRLEN]; + char srcStr[INET_ADDRSTRLEN]; + memcpy(srcStr, &ipv4Addr, sizeof(struct in_addr)); + if(inet_ntop(AF_INET, srcStr, dstStr, INET_ADDRSTRLEN) != NULL){ + address = [NSString stringWithUTF8String:dstStr]; + } + + return address; +} + + +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetPing.h b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetPing.h new file mode 100644 index 000000000..076ad1c01 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetPing.h @@ -0,0 +1,44 @@ +// +// LDNetPing.h +// LDNetCheckServiceDemo +// +// Created by 庞辉 on 14-10-29. +// Copyright (c) 2014年 庞辉. All rights reserved. +// + +#import +#import "LDSimplePing.h" + + +/* + * @protocal LDNetPingDelegate监测Ping命令的的输出到日志变量; + * + */ +@protocol LDNetPingDelegate +- (void)appendPingLog:(NSString *)pingLog; +- (void)netPingDidEnd; +@end + + +/* + * @class LDNetPing ping监控 + * 主要是通过模拟shell命令ping的过程,监控目标主机是否连通 + * 连续执行五次,因为每次的速度不一致,可以观察其平均速度来判断网络情况 + */ +@protocol LDSimplePingDelegate; +@interface LDNetPing : NSObject { +} + +@property (nonatomic, weak, readwrite) id delegate; + +/** + * 通过hostname 进行ping诊断 + */ +- (void)runWithHostName:(NSString *)hostName normalPing:(BOOL)normalPing; + +/** + * 停止当前ping动作 + */ +- (void)stopPing; + +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetPing.m b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetPing.m new file mode 100644 index 000000000..5d6e22d57 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetPing.m @@ -0,0 +1,325 @@ +// +// LDNetPing.m +// LDNetCheckServiceDemo +// +// Created by 庞辉 on 14-10-29. +// Copyright (c) 2014年 庞辉. All rights reserved. +// +#include +#include + +#import "LDNetPing.h" +#import "LDNetTimer.h" + +#define MAXCOUNT_PING 4 + +@interface LDNetPing () { + BOOL _isStartSuccess; //监测第一次ping是否成功 + int _sendCount; //当前执行次数 + long _startTime; //每次执行的开始时间 + NSString *_hostAddress; //目标域名的IP地址 + BOOL _isLargePing; + NSTimer *timer; +} + +@property (nonatomic, strong, readwrite) LDSimplePing *pinger; + +@end + + +@implementation LDNetPing +@synthesize pinger = _pinger; + + +- (void)dealloc +{ + [self->_pinger stop]; +} + + +/** + * 停止当前ping动作 + */ +- (void)stopPing +{ + [self->_pinger stop]; + self.pinger = nil; + _sendCount = MAXCOUNT_PING + 1; +} + + +/* + * 调用pinger解析指定域名 + * @param hostName 指定域名 + */ +- (void)runWithHostName:(NSString *)hostName normalPing:(BOOL)normalPing{ + assert(self.pinger == nil); + self.pinger = [[LDSimplePing alloc] initWithHostName:hostName]; + assert(self.pinger != nil); + + _isLargePing = !normalPing; + self.pinger.delegate = self; + [self.pinger start]; + + //在当前线程一直执行 + _sendCount = 1; + do { + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + } while (self.pinger != nil || _sendCount <= MAXCOUNT_PING); +} + + +/* + * 发送Ping数据,pinger会组装一个ICMP控制报文的数据发送过去 + * + */ +- (void)sendPing +{ + if (timer) { + [timer invalidate]; + } + if (_sendCount > MAXCOUNT_PING) { + _sendCount++; + self.pinger = nil; + if (self.delegate && [self.delegate respondsToSelector:@selector(netPingDidEnd)]) { + [self.delegate netPingDidEnd]; + } + } + + else { + assert(self.pinger != nil); + _sendCount++; + _startTime = [LDNetTimer getMicroSeconds]; + if (_isLargePing) { + NSString *testStr = @""; + for (int i=0; i<408; i++) { + testStr = [testStr stringByAppendingString:@"abcdefghi "]; + } + testStr = [testStr stringByAppendingString:@"abcdefgh"]; + NSData *data = [testStr dataUsingEncoding:NSASCIIStringEncoding]; + [self.pinger sendPingWithData:data]; + } else { + [self.pinger sendPingWithData:nil]; + } + timer = [NSTimer scheduledTimerWithTimeInterval:3.0 + target:self + selector:@selector(pingTimeout:) + userInfo:[NSNumber numberWithInt:_sendCount] + repeats:NO]; + } +} + +- (void)pingTimeout:(NSTimer *)index +{ + if ([[index userInfo] intValue] == _sendCount && _sendCount <= MAXCOUNT_PING + 1 && + _sendCount > 1) { + NSString *timeoutLog = + [NSString stringWithFormat:@"ping: cannot resolve %@: TimeOut", _hostAddress]; + if (self.delegate && [self.delegate respondsToSelector:@selector(appendPingLog:)]) { + [self.delegate appendPingLog:timeoutLog]; + } + [self sendPing]; + } +} + + +#pragma mark - Pingdelegate +/* + * PingDelegate: 套接口开启之后发送ping数据,并开启一个timer(1s间隔发送数据) + * + */ +- (void)simplePing:(LDSimplePing *)pinger didStartWithAddress:(NSData *)address +{ +#pragma unused(pinger) + assert(pinger == self.pinger); + assert(address != nil); + _hostAddress = [self DisplayAddressForAddress:address]; + NSLog(@"pinging %@", _hostAddress); + + // Send the first ping straight away. + _isStartSuccess = YES; + [self sendPing]; +} + +/* + * PingDelegate: ping命令发生错误之后,立即停止timer和线程 + * + */ +- (void)simplePing:(LDSimplePing *)pinger didFailWithError:(NSError *)error +{ +#pragma unused(pinger) + assert(pinger == self.pinger); +#pragma unused(error) + NSString *failCreateLog = [NSString stringWithFormat:@"#%u try create failed: %@", _sendCount, + [self shortErrorFromError:error]]; + if (self.delegate && [self.delegate respondsToSelector:@selector(appendPingLog:)]) { + [self.delegate appendPingLog:failCreateLog]; + } + + //如果不是创建套接字失败,都是发送数据过程中的错误,可以继续try发送数据 + if (_isStartSuccess) { + [self sendPing]; + } else { + [self stopPing]; + } +} + +/* + * PingDelegate: 发送ping数据成功 + * + */ +- (void)simplePing:(LDSimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber; +{ +#pragma unused(pinger) + assert(pinger == self.pinger); +#pragma unused(packet) + NSLog(@"#%u sent success",sequenceNumber); +} + + +/* + * PingDelegate: 发送ping数据失败 + */ +- (void)simplePing:(LDSimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error +{ +#pragma unused(pinger) + assert(pinger == self.pinger); +#pragma unused(packet) +#pragma unused(error) + NSString *sendFailLog = + [NSString stringWithFormat:@"#%u send failed: %@",sequenceNumber, + [self shortErrorFromError:error]]; + //记录 + if (self.delegate && [self.delegate respondsToSelector:@selector(appendPingLog:)]) { + [self.delegate appendPingLog:sendFailLog]; + } + + [self sendPing]; +} + + +/* + * PingDelegate: 成功接收到PingResponse数据 + */ +- (void)simplePing:(LDSimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber +{ +#pragma unused(pinger) + assert(pinger == self.pinger); +#pragma unused(packet) + //由于IPV6在IPheader中不返回TTL数据,所以这里不返回TTL,改为返回Type + //http://blog.sina.com.cn/s/blog_6a1837e901012ds8.html + NSString *icmpReplyType = [NSString stringWithFormat:@"%@", [LDSimplePing icmpInPacket:packet]->type == 129 ? @"ICMPv6TypeEchoReply" : @"ICMPv4TypeEchoReply"]; + NSString *successLog = [NSString + stringWithFormat:@"%lu bytes from %@ icmp_seq=#%u type=%@ time=%ldms", + (unsigned long)[packet length], _hostAddress, + sequenceNumber, + icmpReplyType, + [LDNetTimer computeDurationSince:_startTime] / 1000]; + //记录ping成功的数据 + if (self.delegate && [self.delegate respondsToSelector:@selector(appendPingLog:)]) { + [self.delegate appendPingLog:successLog]; + } + + [self sendPing]; +} + + +/* + * PingDelegate: 接收到错误的pingResponse数据 + */ +- (void)simplePing:(LDSimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet +{ + const ICMPHeader *icmpPtr; + if (self.pinger && pinger == self.pinger) { + icmpPtr = [LDSimplePing icmpInPacket:packet]; + NSString *errorLog = @""; + if (icmpPtr != NULL) { + errorLog = [NSString + stringWithFormat:@"#%u unexpected ICMP type=%u, code=%u, identifier=%u", + (unsigned int)OSSwapBigToHostInt16(icmpPtr->sequenceNumber), + (unsigned int)icmpPtr->type, (unsigned int)icmpPtr->code, + (unsigned int)OSSwapBigToHostInt16(icmpPtr->identifier)]; + } else { + errorLog = [NSString stringWithFormat:@"#%u try unexpected packet size=%zu", _sendCount, + (size_t)[packet length]]; + } + //记录 + if (self.delegate && [self.delegate respondsToSelector:@selector(appendPingLog:)]) { + [self.delegate appendPingLog:errorLog]; + } + } + + //当检测到错误数据的时候,再次发送 + [self sendPing]; +} + +/** + * 将ping接收的数据转换成ip地址 + * @param address 接受的ping数据 + */ +-(NSString *)DisplayAddressForAddress:(NSData *)address +{ + int err; + NSString *result; + char hostStr[NI_MAXHOST]; + + result = nil; + + if (address != nil) { + err = getnameinfo([address bytes], (socklen_t)[address length], hostStr, sizeof(hostStr), + NULL, 0, NI_NUMERICHOST); + if (err == 0) { + result = [NSString stringWithCString:hostStr encoding:NSASCIIStringEncoding]; + assert(result != nil); + } + } + + return result; +} + +/* + * 解析错误数据并翻译 + */ +- (NSString *)shortErrorFromError:(NSError *)error +{ + NSString *result; + NSNumber *failureNum; + int failure; + const char *failureStr; + + assert(error != nil); + + result = nil; + + // Handle DNS errors as a special case. + + if ([[error domain] isEqual:(NSString *)kCFErrorDomainCFNetwork] && + ([error code] == kCFHostErrorUnknown)) { + failureNum = [[error userInfo] objectForKey:(id)kCFGetAddrInfoFailureKey]; + if ([failureNum isKindOfClass:[NSNumber class]]) { + failure = [failureNum intValue]; + if (failure != 0) { + failureStr = gai_strerror(failure); + if (failureStr != NULL) { + result = [NSString stringWithUTF8String:failureStr]; + assert(result != nil); + } + } + } + } + + // Otherwise try various properties of the error object. + + if (result == nil) { + result = [error localizedFailureReason]; + } + if (result == nil) { + result = [error localizedDescription]; + } + if (result == nil) { + result = [error description]; + } + assert(result != nil); + return result; +} +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTimer.h b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTimer.h new file mode 100644 index 000000000..438d1d3fe --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTimer.h @@ -0,0 +1,25 @@ +// +// LDNetTimer.h +// LDNetDiagnoServieDemo +// +// Created by 庞辉 on 14-10-29. +// Copyright (c) 2014年 庞辉. All rights reserved. +// + +#import + +@interface LDNetTimer : NSObject { +} + + +/** + * Retourne un timestamp en microsecondes. + */ ++ (long)getMicroSeconds; + + +/** + * Calcule une durée en millisecondes par rapport au timestamp passé en paramètre. + */ ++ (long)computeDurationSince:(long)uTime; +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTimer.m b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTimer.m new file mode 100644 index 000000000..4e5c62657 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTimer.m @@ -0,0 +1,36 @@ +// +// LDNetTimer.m +// LDNetDiagnoServieDemo +// +// Created by 庞辉 on 14-10-29. +// Copyright (c) 2014年 庞辉. All rights reserved. +// +#include +#import "LDNetTimer.h" + +@implementation LDNetTimer + +/** + * Retourne un timestamp en microsecondes. + */ ++ (long)getMicroSeconds +{ + struct timeval time; + gettimeofday(&time, NULL); + return time.tv_usec; +} + +/** + * Calcule une durée en millisecondes par rapport au timestamp passé en paramètre. + */ ++ (long)computeDurationSince:(long)uTime +{ + long now = [LDNetTimer getMicroSeconds]; + if (now < uTime) { + return 1000000 - uTime + now; + } + return now - uTime; +} + + +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTraceRoute.h b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTraceRoute.h new file mode 100644 index 000000000..a9abdf9ba --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTraceRoute.h @@ -0,0 +1,61 @@ +// +// TraceRoute.h +// LDNetCheckServiceDemo +// +// Created by 庞辉 on 14-10-29. +// Copyright (c) 2014年 庞辉. All rights reserved. +// + +#import + +static const int TRACEROUTE_PORT = 30001; +static const int TRACEROUTE_MAX_TTL = 30; +static const int TRACEROUTE_ATTEMPTS = 3; +static const int TRACEROUTE_TIMEOUT = 5000000; + +/* + * @protocal LDNetTraceRouteDelegate监测TraceRoute命令的的输出到日志变量; + * + */ +@protocol LDNetTraceRouteDelegate +- (void)appendRouteLog:(NSString *)routeLog; +- (void)traceRouteDidEnd; +@end + + +/* + * @class LDNetTraceRoute TraceRoute网络监控 + * 主要是通过模拟shell命令traceRoute的过程,监控网络站点间的跳转 + * 默认执行20转,每转进行三次发送测速 + */ +@interface LDNetTraceRoute : NSObject { + int udpPort; //执行端口 + int maxTTL; //执行转数 + int readTimeout; //每次发送时间的timeout + int maxAttempts; //每转的发送次数 + NSString *running; + bool isrunning; +} + +@property (nonatomic, weak) id delegate; + +/** + * 初始化 + */ +- (LDNetTraceRoute *)initWithMaxTTL:(int)ttl + timeout:(int)timeout + maxAttempts:(int)attempts + port:(int)port; + +/** + * 监控tranceroute 路径 + */ +- (Boolean)doTraceRoute:(NSString *)host; + +/** + * 停止traceroute + */ +- (void)stopTrace; +- (bool)isRunning; + +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTraceRoute.m b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTraceRoute.m new file mode 100644 index 000000000..817124915 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDNetTraceRoute.m @@ -0,0 +1,247 @@ +// +// TraceRoute.m +// LDNetCheckServiceDemo +// +// Created by 庞辉 on 14-10-29. +// Copyright (c) 2014年 庞辉. All rights reserved. +// + +#include +#include +#include + +#import "LDNetTraceRoute.h" +#import "LDNetTimer.h" +#import "LDNetGetAddress.h" + +@implementation LDNetTraceRoute + +/** + * 初始化 + */ +- (LDNetTraceRoute *)initWithMaxTTL:(int)ttl + timeout:(int)timeout + maxAttempts:(int)attempts + port:(int)port +{ + self = [super init]; + if (self) { + maxTTL = ttl; + udpPort = port; + readTimeout = timeout; + maxAttempts = attempts; + } + + return self; +} + + +/** + * 监控tranceroute 路径 + */ +- (Boolean)doTraceRoute:(NSString *)host +{ + //从name server获取server主机的地址 + NSArray *serverDNSs = [LDNetGetAddress getDNSsWithDormain:host]; + if (!serverDNSs || serverDNSs.count <= 0) { + if (_delegate != nil) { + [_delegate appendRouteLog:@"TraceRoute>>> Could not get host address"]; + [_delegate traceRouteDidEnd]; + } + return false; + } + + NSString *ipAddr0 = [serverDNSs objectAtIndex:0]; + //设置server主机的套接口地址 + NSData *addrData = nil; + BOOL isIPV6 = NO; + if ([ipAddr0 rangeOfString:@":"].location == NSNotFound) { + isIPV6 = NO; + struct sockaddr_in nativeAddr4; + memset(&nativeAddr4, 0, sizeof(nativeAddr4)); + nativeAddr4.sin_len = sizeof(nativeAddr4); + nativeAddr4.sin_family = AF_INET; + nativeAddr4.sin_port = htons(udpPort); + inet_pton(AF_INET, ipAddr0.UTF8String, &nativeAddr4.sin_addr.s_addr); + addrData = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)]; + } else { + isIPV6 = YES; + struct sockaddr_in6 nativeAddr6; + memset(&nativeAddr6, 0, sizeof(nativeAddr6)); + nativeAddr6.sin6_len = sizeof(nativeAddr6); + nativeAddr6.sin6_family = AF_INET6; + nativeAddr6.sin6_port = htons(udpPort); + inet_pton(AF_INET6, ipAddr0.UTF8String, &nativeAddr6.sin6_addr); + addrData = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)]; + } + + struct sockaddr *destination; + destination = (struct sockaddr *)[addrData bytes]; + + //初始化套接口 + struct sockaddr fromAddr; + int recv_sock; + int send_sock; + Boolean error = false; + + isrunning = true; + //创建一个支持ICMP协议的UDP网络套接口(用于接收) + + if ((recv_sock = socket(destination->sa_family, SOCK_DGRAM, isIPV6?IPPROTO_ICMPV6:IPPROTO_ICMP)) < 0) { + if (_delegate != nil) { + [_delegate appendRouteLog:@"TraceRoute>>> Could not create recv socket"]; + [_delegate traceRouteDidEnd]; + } + return false; + } + + //创建一个UDP套接口(用于发送) + if ((send_sock = socket(destination->sa_family, SOCK_DGRAM, 0)) < 0) { + if (_delegate != nil) { + [_delegate appendRouteLog:@"TraceRoute>>> Could not create xmit socket"]; + [_delegate traceRouteDidEnd]; + } + return false; + } + + + char *cmsg = "GET / HTTP/1.1\r\n\r\n"; + socklen_t n = sizeof(fromAddr); + char buf[100]; + + int ttl = 1; // index sur le TTL en cours de traitement. + int timeoutTTL = 0; + bool icmp = false; // Positionné à true lorsqu'on reçoit la trame ICMP en retour. + long startTime; // Timestamp lors de l'émission du GET HTTP + long delta; // Durée de l'aller-retour jusqu'au hop. + + // On progresse jusqu'à un nombre de TTLs max. + while (ttl <= maxTTL) { + memset(&fromAddr, 0, sizeof(fromAddr)); + //设置sender 套接字的ttl + if ((isIPV6? setsockopt(send_sock,IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)):setsockopt(send_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) < 0) { + error = true; + if (_delegate != nil) { + [_delegate appendRouteLog:@"TraceRoute>>> setsockopt failled"]; + } + } + + + //每一步连续发送maxAttenpts报文 + icmp = false; + NSMutableString *traceTTLLog = [[NSMutableString alloc] initWithCapacity:20]; + [traceTTLLog appendFormat:@"%d\t", ttl]; + NSString *hostAddress = @"***"; + for (int try = 0; try < maxAttempts; try ++) { + startTime = [LDNetTimer getMicroSeconds]; + //发送成功返回值等于发送消息的长度 + ssize_t sentLen = sendto(send_sock, cmsg, sizeof(cmsg), 0, (struct sockaddr *)destination, isIPV6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)); + if (sentLen != sizeof(cmsg)) { + NSLog(@"Error sending to server: %d %d", errno, (int)sentLen); + error = true; + [traceTTLLog appendFormat:@"?\t"]; + } + + long res = 0; + //从(已连接)套接口上接收数据,并捕获数据发送源的地址。 + if (-1 == fcntl(recv_sock, F_SETFL, O_NONBLOCK)) { + printf("fcntl socket error!\n"); + return -1; + } + /* set recvfrom from server timeout */ + struct timeval tv; + fd_set readfds; + tv.tv_sec = 1; + tv.tv_usec = 0; //设置了1s的延迟 + FD_ZERO(&readfds); + FD_SET(recv_sock, &readfds); + select(recv_sock + 1, &readfds, NULL, NULL, &tv); + if (FD_ISSET(recv_sock, &readfds) > 0) { + timeoutTTL = 0; + if ((res = recvfrom(recv_sock, buf, 100, 0, (struct sockaddr *)&fromAddr, &n)) < + 0) { + error = true; + [traceTTLLog appendFormat:@"?\t"]; + } else { + icmp = true; + delta = [LDNetTimer computeDurationSince:startTime]; + + //将“二进制整数” -> “点分十进制,获取hostAddress和hostName + if (fromAddr.sa_family == AF_INET) { + char display[INET_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET, &((struct sockaddr_in *)&fromAddr)->sin_addr.s_addr, display, sizeof(display)); + hostAddress = [NSString stringWithFormat:@"%s", display]; + } + + else if (fromAddr.sa_family == AF_INET6) { + char ip[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&fromAddr)->sin6_addr, ip, INET6_ADDRSTRLEN); + hostAddress = [NSString stringWithUTF8String:ip]; + } + + if (try == 0) { + [traceTTLLog appendFormat:@"%@\t", hostAddress]; + } + [traceTTLLog appendFormat:@"%0.2fms\t", (float)delta / 1000]; + } + } else { + timeoutTTL++; + break; + } + + // On teste si l'utilisateur a demandé l'arrêt du traceroute + @synchronized(running) + { + if (!isrunning) { + ttl = maxTTL; + // On force le statut d'icmp pour ne pas générer un Hop en sortie de boucle; + icmp = true; + break; + } + } + } + + //输出报文,如果三次都无法监控接收到报文,跳转结束 + if (icmp) { + [self.delegate appendRouteLog:traceTTLLog]; + } else { + //如果连续三次接收不到icmp回显报文 + if (timeoutTTL >= 4) { + break; + } else { + [self.delegate appendRouteLog:[NSString stringWithFormat:@"%d\t???", ttl]]; + } + } + + if ([hostAddress isEqualToString:ipAddr0]) { + break; + } + ttl++; + } + + isrunning = false; + // On averti le delegate que le traceroute est terminé. + [_delegate traceRouteDidEnd]; + return error; +} + +/** + * 停止traceroute + */ +- (void)stopTrace +{ + @synchronized(running) + { + isrunning = false; + } +} + + +/** + * 检测traceroute是否在运行 + */ +- (bool)isRunning +{ + return isrunning; +} +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDSimplePing.h b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDSimplePing.h new file mode 100644 index 000000000..42fd24717 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDSimplePing.h @@ -0,0 +1,269 @@ +/* + Copyright (C) 2016 Apple Inc. All Rights Reserved. + See LICENSE.txt for this sample’s licensing information + + Abstract: + An object wrapper around the low-level BSD Sockets ping function. + */ + +#import + +#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR +#import +#else +#import +#endif + +#include + +NS_ASSUME_NONNULL_BEGIN +// The SimplePing class is a very simple class that lets you send and receive pings. + +@protocol LDSimplePingDelegate; + +/*! Controls the IP address version used by SimplePing instances. + */ + +typedef NS_ENUM(NSInteger, SimplePingAddressStyle) { + SimplePingAddressStyleAny, ///< Use the first IPv4 or IPv6 address found; the default. + SimplePingAddressStyleICMPv4, ///< Use the first IPv4 address found. + SimplePingAddressStyleICMPv6 ///< Use the first IPv6 address found. +}; + + +@interface LDSimplePing : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/*! Initialise the object to ping the specified host. + * \param hostName The DNS name of the host to ping; an IPv4 or IPv6 address in string form will + * work here. + * \returns The initialised object. + */ +- (instancetype)initWithHostName:(NSString *)hostName NS_DESIGNATED_INITIALIZER; + +/*! A copy of the value passed to `-initWithHostName:`. + */ +@property (nonatomic, copy, readonly) NSString *hostName; + +/*! The delegate for this object. + * \details Delegate callbacks are schedule in the default run loop mode of the run loop of the + * thread that calls `-start`. + */ + +@property (nonatomic, weak, readwrite, nullable) id delegate; + +/*! Controls the IP address version used by the object. + * \details You should set this value before starting the object. + */ + +@property (nonatomic, assign, readwrite) SimplePingAddressStyle addressStyle; + +/*! The address being pinged. + * \details The contents of the NSData is a (struct sockaddr) of some form. The + * value is nil while the object is stopped and remains nil on start until + * `-simplePing:didStartWithAddress:` is called. + */ + +@property (nonatomic, copy, readonly, nullable) NSData * hostAddress; + +/*! The address family for `hostAddress`, or `AF_UNSPEC` if that's nil. + */ + +@property (nonatomic, assign, readonly) sa_family_t hostAddressFamily; + +/*! The identifier used by pings by this object. + * \details When you create an instance of this object it generates a random identifier + * that it uses to identify its own pings. + */ + +@property (nonatomic, assign, readonly) uint16_t identifier; + +/*! The next sequence number to be used by this object. + * \details This value starts at zero and increments each time you send a ping (safely + * wrapping back to zero if necessary). The sequence number is included in the ping, + * allowing you to match up requests and responses, and thus calculate ping times and + * so on. + */ + +@property (nonatomic, assign, readonly) uint16_t nextSequenceNumber; + +/*! Starts the object. + * \details You should set up the delegate and any ping parameters before calling this. + * + * If things go well you'll soon get the `-simplePing:didStartWithAddress:` delegate + * callback, at which point you can start sending pings (via `-sendPingWithData:`) and + * will start receiving ICMP packets (either ping responses, via the + * `-simplePing:didReceivePingResponsePacket:sequenceNumber:` delegate callback, or + * unsolicited ICMP packets, via the `-simplePing:didReceiveUnexpectedPacket:` delegate + * callback). + * + * If the object fails to start, typically because `hostName` doesn't resolve, you'll get + * the `-simplePing:didFailWithError:` delegate callback. + * + * It is not correct to start an already started object. + */ + +- (void)start; + +/*! Sends a ping packet containing the specified data. + * \details Sends an actual ping. + * + * The object must be started when you call this method and, on starting the object, you must + * wait for the `-simplePing:didStartWithAddress:` delegate callback before calling it. + * \param data Some data to include in the ping packet, after the ICMP header, or nil if you + * want the packet to include a standard 56 byte payload (resulting in a standard 64 byte + * ping). + */ + +- (void)sendPingWithData:(nullable NSData *)data; + +/*! Stops the object. + * \details You should call this when you're done pinging. + * + * It's safe to call this on an object that's stopped. + */ + +- (void)stop; + +#pragma mark - tofix support IPV6 ++ (const struct ICMPHeader *)icmpInPacket:(NSData *)packet; + +@end + + + +@protocol LDSimplePingDelegate + +@optional + + +/*! A SimplePing delegate callback, called once the object has started up. + * \details This is called shortly after you start the object to tell you that the + * object has successfully started. On receiving this callback, you can call + * `-sendPingWithData:` to send pings. + * + * If the object didn't start, `-simplePing:didFailWithError:` is called instead. + * \param pinger The object issuing the callback. + * \param address The address that's being pinged; at the time this delegate callback + * is made, this will have the same value as the `hostAddress` property. + */ + +- (void)simplePing:(LDSimplePing *)pinger didStartWithAddress:(NSData *)address; + + +/*! A SimplePing delegate callback, called if the object fails to start up. + * \details This is called shortly after you start the object to tell you that the + * object has failed to start. The most likely cause of failure is a problem + * resolving `hostName`. + * + * By the time this callback is called, the object has stopped (that is, you don't + * need to call `-stop` yourself). + * \param pinger The object issuing the callback. + * \param error Describes the failure. + */ +- (void)simplePing:(LDSimplePing *)pinger didFailWithError:(NSError *)error; + + +/*! A SimplePing delegate callback, called when the object has successfully sent a ping packet. + * \details Each call to `-sendPingWithData:` will result in either a + * `-simplePing:didSendPacket:sequenceNumber:` delegate callback or a + * `-simplePing:didFailToSendPacket:sequenceNumber:error:` delegate callback (unless you + * stop the object before you get the callback). These callbacks are currently delivered + * synchronously from within `-sendPingWithData:`, but this synchronous behaviour is not + * considered API. + * \param pinger The object issuing the callback. + * \param packet The packet that was sent; this includes the ICMP header (`ICMPHeader`) and the + * data you passed to `-sendPingWithData:` but does not include any IP-level headers. + * \param sequenceNumber The ICMP sequence number of that packet. + */ + +- (void)simplePing:(LDSimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber; + +/*! A SimplePing delegate callback, called when the object fails to send a ping packet. + * \details Each call to `-sendPingWithData:` will result in either a + * `-simplePing:didSendPacket:sequenceNumber:` delegate callback or a + * `-simplePing:didFailToSendPacket:sequenceNumber:error:` delegate callback (unless you + * stop the object before you get the callback). These callbacks are currently delivered + * synchronously from within `-sendPingWithData:`, but this synchronous behaviour is not + * considered API. + * \param pinger The object issuing the callback. + * \param packet The packet that was not sent; see `-simplePing:didSendPacket:sequenceNumber:` + * for details. + * \param sequenceNumber The ICMP sequence number of that packet. + * \param error Describes the failure. + */ +- (void)simplePing:(LDSimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error; + + +/*! A SimplePing delegate callback, called when the object receives a ping response. + * \details If the object receives an ping response that matches a ping request that it + * sent, it informs the delegate via this callback. Matching is primarily done based on + * the ICMP identifier, although other criteria are used as well. + * \param pinger The object issuing the callback. + * \param packet The packet received; this includes the ICMP header (`ICMPHeader`) and any data that + * follows that in the ICMP message but does not include any IP-level headers. + * \param sequenceNumber The ICMP sequence number of that packet. + */ +- (void)simplePing:(LDSimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber; + +/*! A SimplePing delegate callback, called when the object receives an unmatched ICMP message. + * \details If the object receives an ICMP message that does not match a ping request that it + * sent, it informs the delegate via this callback. The nature of ICMP handling in a + * BSD kernel makes this a common event because, when an ICMP message arrives, it is + * delivered to all ICMP sockets. + * + * IMPORTANT: This callback is especially common when using IPv6 because IPv6 uses ICMP + * for important network management functions. For example, IPv6 routers periodically + * send out Router Advertisement (RA) packets via Neighbor Discovery Protocol (NDP), which + * is implemented on top of ICMP. + * + * For more on matching, see the discussion associated with + * `-simplePing:didReceivePingResponsePacket:sequenceNumber:`. + * \param pinger The object issuing the callback. + * \param packet The packet received; this includes the ICMP header (`ICMPHeader`) and any data that + * follows that in the ICMP message but does not include any IP-level headers. + */ +- (void)simplePing:(LDSimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet; + +@end + + +#pragma mark * ICMP On-The-Wire Format + +/*! Describes the on-the-wire header format for an ICMP ping. + * \details This defines the header structure of ping packets on the wire. Both IPv4 and + * IPv6 use the same basic structure. + * + * This is declared in the header because clients of SimplePing might want to use + * it parse received ping packets. + */ + +struct ICMPHeader { + uint8_t type; + uint8_t code; + uint16_t checksum; + uint16_t identifier; + uint16_t sequenceNumber; + // data... +}; +typedef struct ICMPHeader ICMPHeader; + +__Check_Compile_Time(sizeof(ICMPHeader) == 8); +__Check_Compile_Time(offsetof(ICMPHeader, type) == 0); +__Check_Compile_Time(offsetof(ICMPHeader, code) == 1); +__Check_Compile_Time(offsetof(ICMPHeader, checksum) == 2); +__Check_Compile_Time(offsetof(ICMPHeader, identifier) == 4); +__Check_Compile_Time(offsetof(ICMPHeader, sequenceNumber) == 6); + +enum { + ICMPv4TypeEchoRequest = 8, ///< The ICMP `type` for a ping request; in this case `code` is always 0. + ICMPv4TypeEchoReply = 0 ///< The ICMP `type` for a ping response; in this case `code` is always 0. +}; + +enum { + ICMPv6TypeEchoRequest = 128, ///< The ICMP `type` for a ping request; in this case `code` is always 0. + ICMPv6TypeEchoReply = 129 ///< The ICMP `type` for a ping response; in this case `code` is always 0. +}; + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDSimplePing.m b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDSimplePing.m new file mode 100644 index 000000000..cfbbeb17c --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/LDSimplePing.m @@ -0,0 +1,810 @@ +/* + Copyright (C) 2016 Apple Inc. All Rights Reserved. + See LICENSE.txt for this sample’s licensing information + + Abstract: + An object wrapper around the low-level BSD Sockets ping function. + */ + +#import "LDSimplePing.h" + +#include +#include +#include + +#pragma mark * IPv4 and ICMPv4 On-The-Wire Format + +/*! Describes the on-the-wire header format for an IPv4 packet. + * \details This defines the header structure of IPv4 packets on the wire. We need + * this in order to skip this header in the IPv4 case, where the kernel passes + * it to us for no obvious reason. + */ + +struct IPv4Header { + uint8_t versionAndHeaderLength; + uint8_t differentiatedServices; + uint16_t totalLength; + uint16_t identification; + uint16_t flagsAndFragmentOffset; + uint8_t timeToLive; + uint8_t protocol; + uint16_t headerChecksum; + uint8_t sourceAddress[4]; + uint8_t destinationAddress[4]; + // options... + // data... +}; +typedef struct IPv4Header IPv4Header; + +__Check_Compile_Time(sizeof(IPv4Header) == 20); +__Check_Compile_Time(offsetof(IPv4Header, versionAndHeaderLength) == 0); +__Check_Compile_Time(offsetof(IPv4Header, differentiatedServices) == 1); +__Check_Compile_Time(offsetof(IPv4Header, totalLength) == 2); +__Check_Compile_Time(offsetof(IPv4Header, identification) == 4); +__Check_Compile_Time(offsetof(IPv4Header, flagsAndFragmentOffset) == 6); +__Check_Compile_Time(offsetof(IPv4Header, timeToLive) == 8); +__Check_Compile_Time(offsetof(IPv4Header, protocol) == 9); +__Check_Compile_Time(offsetof(IPv4Header, headerChecksum) == 10); +__Check_Compile_Time(offsetof(IPv4Header, sourceAddress) == 12); +__Check_Compile_Time(offsetof(IPv4Header, destinationAddress) == 16); + + +/*! Calculates an IP checksum. + * \details This is the standard BSD checksum code, modified to use modern types. + * \param buffer A pointer to the data to checksum. + * \param bufferLen The length of that data. + * \returns The checksum value, in network byte order. + */ + +static uint16_t in_cksum(const void *buffer, size_t bufferLen) { + // + size_t bytesLeft; + int32_t sum; + const uint16_t * cursor; + union { + uint16_t us; + uint8_t uc[2]; + } last; + uint16_t answer; + + bytesLeft = bufferLen; + sum = 0; + cursor = buffer; + + /* + * Our algorithm is simple, using a 32 bit accumulator (sum), we add + * sequential 16 bit words to it, and at the end, fold back all the + * carry bits from the top 16 bits into the lower 16 bits. + */ + while (bytesLeft > 1) { + sum += *cursor; + cursor += 1; + bytesLeft -= 2; + } + + /* mop up an odd byte, if necessary */ + if (bytesLeft == 1) { + last.uc[0] = * (const uint8_t *) cursor; + last.uc[1] = 0; + sum += last.us; + } + + /* add back carry outs from top 16 bits to low 16 bits */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = (uint16_t) ~sum; /* truncate to 16 bits */ + + return answer; +} + +#pragma mark * SimplePing + +@interface LDSimplePing () + +// read/write versions of public properties + +@property (nonatomic, copy, readwrite, nullable) NSData *hostAddress; +@property (nonatomic, assign, readwrite) uint16_t nextSequenceNumber; + +// private properties + +/*! True if nextSequenceNumber has wrapped from 65535 to 0. + */ + +@property (nonatomic, assign, readwrite) BOOL nextSequenceNumberHasWrapped; + +/*! A host object for name-to-address resolution. + */ + +@property (nonatomic, strong, readwrite, nullable) CFHostRef host __attribute__ ((NSObject)); + +/*! A socket object for ICMP send and receive. + */ + +@property (nonatomic, strong, readwrite, nullable) CFSocketRef socket __attribute__ ((NSObject)); + +@end + + +@implementation LDSimplePing + +- (instancetype)initWithHostName:(NSString *)hostName { + NSParameterAssert(hostName != nil); + self = [super init]; + if (self != nil) { + self->_hostName = [hostName copy]; + self->_identifier = (uint16_t) arc4random(); + } + return self; +} + +- (void)dealloc { + [self stop]; + // Double check that -stop took care of _host and _socket. + assert(self->_host == NULL); + assert(self->_socket == NULL); +} + +- (sa_family_t)hostAddressFamily { + sa_family_t result; + + result = AF_UNSPEC; + if ( (self.hostAddress != nil) && (self.hostAddress.length >= sizeof(struct sockaddr)) ) { + result = ((const struct sockaddr *) self.hostAddress.bytes)->sa_family; + } + return result; +} + +/*! Shuts down the pinger object and tell the delegate about the error. + * \param error Describes the failure. + */ + +- (void)didFailWithError:(NSError *)error { + id strongDelegate; + + assert(error != nil); + + // We retain ourselves temporarily because it's common for the delegate method + // to release its last reference to us, which causes -dealloc to be called here. + // If we then reference self on the return path, things go badly. I don't think + // that happens currently, but I've got into the habit of doing this as a + // defensive measure. + + CFAutorelease( CFBridgingRetain( self )); + + [self stop]; + strongDelegate = self.delegate; + if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didFailWithError:)] ) { + [strongDelegate simplePing:self didFailWithError:error]; + } +} + +/*! Shuts down the pinger object and tell the delegate about the error. + * \details This converts the CFStreamError to an NSError and then call through to + * -didFailWithError: to do the real work. + * \param streamError Describes the failure. + */ + +- (void)didFailWithHostStreamError:(CFStreamError)streamError { + NSDictionary * userInfo; + NSError * error; + + if (streamError.domain == kCFStreamErrorDomainNetDB) { + userInfo = @{(id) kCFGetAddrInfoFailureKey: @(streamError.error)}; + } else { + userInfo = nil; + } + error = [NSError errorWithDomain:(NSString *) kCFErrorDomainCFNetwork code:kCFHostErrorUnknown userInfo:userInfo]; + + [self didFailWithError:error]; +} + +/*! Builds a ping packet from the supplied parameters. + * \param type The packet type, which is different for IPv4 and IPv6. + * \param payload Data to place after the ICMP header. + * \param requiresChecksum Determines whether a checksum is calculated (IPv4) or not (IPv6). + * \returns A ping packet suitable to be passed to the kernel. + */ + +- (NSData *)pingPacketWithType:(uint8_t)type payload:(NSData *)payload requiresChecksum:(BOOL)requiresChecksum { + NSMutableData * packet; + ICMPHeader * icmpPtr; + + packet = [NSMutableData dataWithLength:sizeof(*icmpPtr) + payload.length]; + assert(packet != nil); + + icmpPtr = packet.mutableBytes; + icmpPtr->type = type; + icmpPtr->code = 0; + icmpPtr->checksum = 0; + icmpPtr->identifier = OSSwapHostToBigInt16(self.identifier); + icmpPtr->sequenceNumber = OSSwapHostToBigInt16(self.nextSequenceNumber); + memcpy(&icmpPtr[1], [payload bytes], [payload length]); + + if (requiresChecksum) { + // The IP checksum routine returns a 16-bit number that's already in correct byte order + // (due to wacky 1's complement maths), so we just put it into the packet as a 16-bit unit. + + icmpPtr->checksum = in_cksum(packet.bytes, packet.length); + } + + return packet; +} + +/** + * 通过ping的套接口发送数据 + */ +- (void)sendPingWithData:(NSData *)data { + int err; + NSData * payload; + NSData * packet; + ssize_t bytesSent; + id strongDelegate; + + // data may be nil + NSParameterAssert(self.hostAddress != nil); // gotta wait for -simplePing:didStartWithAddress: + + // Construct the ping packet. + + payload = data; + if (payload == nil) { + payload = [[NSString stringWithFormat:@"%28zd bottles of beer on the wall", (ssize_t) 99 - (size_t) (self.nextSequenceNumber % 100) ] dataUsingEncoding:NSASCIIStringEncoding]; + assert(payload != nil); + + // Our dummy payload is sized so that the resulting ICMP packet, including the ICMPHeader, is + // 64-bytes, which makes it easier to recognise our packets on the wire. + + assert([payload length] == 56); + } + + switch (self.hostAddressFamily) { + case AF_INET: { + packet = [self pingPacketWithType:ICMPv4TypeEchoRequest payload:payload requiresChecksum:YES]; + } break; + case AF_INET6: { + packet = [self pingPacketWithType:ICMPv6TypeEchoRequest payload:payload requiresChecksum:NO]; + } break; + default: { + assert(NO); + } break; + } + assert(packet != nil); + + // Send the packet. + + if (self.socket == NULL) { + bytesSent = -1; + err = EBADF; + } else { + bytesSent = sendto( + CFSocketGetNative(self.socket), + packet.bytes, + packet.length, + 0, + self.hostAddress.bytes, + (socklen_t) self.hostAddress.length + ); + err = 0; + if (bytesSent < 0) { + err = errno; + } + } + + // Handle the results of the send. + + strongDelegate = self.delegate; + if ( (bytesSent > 0) && (((NSUInteger) bytesSent) == packet.length) ) { + + // Complete success. Tell the client. + + if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didSendPacket:sequenceNumber:)] ) { + [strongDelegate simplePing:self didSendPacket:packet sequenceNumber:self.nextSequenceNumber]; + } + } else { + NSError * error; + + // Some sort of failure. Tell the client. + + if (err == 0) { + err = ENOBUFS; // This is not a hugely descriptor error, alas. + } + error = [NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]; + if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didFailToSendPacket:sequenceNumber:error:)] ) { + [strongDelegate simplePing:self didFailToSendPacket:packet sequenceNumber:self.nextSequenceNumber error:error]; + } + } + + self.nextSequenceNumber += 1; + if (self.nextSequenceNumber == 0) { + self.nextSequenceNumberHasWrapped = YES; + } +} + + +/*! Calculates the offset of the ICMP header within an IPv4 packet. + * \details In the IPv4 case the kernel returns us a buffer that includes the + * IPv4 header. We're not interested in that, so we have to skip over it. + * This code does a rough check of the IPv4 header and, if it looks OK, + * returns the offset of the ICMP header. + * \param packet The IPv4 packet, as returned to us by the kernel. + * \returns The offset of the ICMP header, or NSNotFound. + */ + ++ (NSUInteger)icmpHeaderOffsetInIPv4Packet:(NSData *)packet { + // Returns the offset of the ICMPv4Header within an IP packet. + NSUInteger result; + const struct IPv4Header * ipPtr; + size_t ipHeaderLength; + + result = NSNotFound; + if (packet.length >= (sizeof(IPv4Header) + sizeof(ICMPHeader))) { + ipPtr = (const IPv4Header *) packet.bytes; + if ( ((ipPtr->versionAndHeaderLength & 0xF0) == 0x40) && // IPv4 + ( ipPtr->protocol == IPPROTO_ICMP ) ) { + ipHeaderLength = (ipPtr->versionAndHeaderLength & 0x0F) * sizeof(uint32_t); + if (packet.length >= (ipHeaderLength + sizeof(ICMPHeader))) { + result = ipHeaderLength; + } + } + } + return result; +} + +/*! Checks whether the specified sequence number is one we sent. + * \param sequenceNumber The incoming sequence number. + * \returns YES if the sequence number looks like one we sent. + */ + +- (BOOL)validateSequenceNumber:(uint16_t)sequenceNumber { + if (self.nextSequenceNumberHasWrapped) { + // If the sequence numbers have wrapped that we can't reliably check + // whether this is a sequence number we sent. Rather, we check to see + // whether the sequence number is within the last 120 sequence numbers + // we sent. Note that the uint16_t subtraction here does the right + // thing regardless of the wrapping. + // + // Why 120? Well, if we send one ping per second, 120 is 2 minutes, which + // is the standard "max time a packet can bounce around the Internet" value. + return ((uint16_t) (self.nextSequenceNumber - sequenceNumber)) < (uint16_t) 120; + } else { + return sequenceNumber < self.nextSequenceNumber; + } +} + +/*! Checks whether an incoming IPv4 packet looks like a ping response. + * \details This routine modifies this `packet` data! It does this for two reasons: + * + * * It needs to zero out the `checksum` field of the ICMPHeader in order to do + * its checksum calculation. + * + * * It removes the IPv4 header from the front of the packet. + * \param packet The IPv4 packet, as returned to us by the kernel. + * \param sequenceNumberPtr A pointer to a place to start the ICMP sequence number. + * \returns YES if the packet looks like a reasonable IPv4 ping response. + */ + +- (BOOL)validatePing4ResponsePacket:(NSMutableData *)packet sequenceNumber:(uint16_t *)sequenceNumberPtr { + BOOL result; + NSUInteger icmpHeaderOffset; + ICMPHeader * icmpPtr; + uint16_t receivedChecksum; + uint16_t calculatedChecksum; + + result = NO; + + icmpHeaderOffset = [[self class] icmpHeaderOffsetInIPv4Packet:packet]; + if (icmpHeaderOffset != NSNotFound) { + icmpPtr = (struct ICMPHeader *) (((uint8_t *) packet.mutableBytes) + icmpHeaderOffset); + + receivedChecksum = icmpPtr->checksum; + icmpPtr->checksum = 0; + calculatedChecksum = in_cksum(icmpPtr, packet.length - icmpHeaderOffset); + icmpPtr->checksum = receivedChecksum; + + if (receivedChecksum == calculatedChecksum) { + if ( (icmpPtr->type == ICMPv4TypeEchoReply) && (icmpPtr->code == 0) ) { + if ( OSSwapBigToHostInt16(icmpPtr->identifier) == self.identifier ) { + uint16_t sequenceNumber; + + sequenceNumber = OSSwapBigToHostInt16(icmpPtr->sequenceNumber); + if ([self validateSequenceNumber:sequenceNumber]) { + + // Remove the IPv4 header off the front of the data we received, leaving us with + // just the ICMP header and the ping payload. + [packet replaceBytesInRange:NSMakeRange(0, icmpHeaderOffset) withBytes:NULL length:0]; + + *sequenceNumberPtr = sequenceNumber; + result = YES; + } + } + } + } + } + + return result; +} + +/*! Checks whether an incoming IPv6 packet looks like a ping response. + * \param packet The IPv6 packet, as returned to us by the kernel; note that this routine + * could modify this data but does not need to in the IPv6 case. + * \param sequenceNumberPtr A pointer to a place to start the ICMP sequence number. + * \returns YES if the packet looks like a reasonable IPv4 ping response. + */ + +- (BOOL)validatePing6ResponsePacket:(NSMutableData *)packet sequenceNumber:(uint16_t *)sequenceNumberPtr { + BOOL result; + const ICMPHeader * icmpPtr; + + result = NO; + + if (packet.length >= sizeof(*icmpPtr)) { + icmpPtr = packet.bytes; + + // In the IPv6 case we don't check the checksum because that's hard (we need to + // cook up an IPv6 pseudo header and we don't have the ingredients) and unnecessary + // (the kernel has already done this check). + + if ( (icmpPtr->type == ICMPv6TypeEchoReply) && (icmpPtr->code == 0) ) { + if ( OSSwapBigToHostInt16(icmpPtr->identifier) == self.identifier ) { + uint16_t sequenceNumber; + + sequenceNumber = OSSwapBigToHostInt16(icmpPtr->sequenceNumber); + if ([self validateSequenceNumber:sequenceNumber]) { + *sequenceNumberPtr = sequenceNumber; + result = YES; + } + } + } + } + return result; +} + +/*! Checks whether an incoming packet looks like a ping response. + * \param packet The packet, as returned to us by the kernel; note that may end up modifying + * this data. + * \param sequenceNumberPtr A pointer to a place to start the ICMP sequence number. + * \returns YES if the packet looks like a reasonable IPv4 ping response. + */ + +- (BOOL)validatePingResponsePacket:(NSMutableData *)packet sequenceNumber:(uint16_t *)sequenceNumberPtr { + BOOL result; + + switch (self.hostAddressFamily) { + case AF_INET: { + result = [self validatePing4ResponsePacket:packet sequenceNumber:sequenceNumberPtr]; + } break; + case AF_INET6: { + result = [self validatePing6ResponsePacket:packet sequenceNumber:sequenceNumberPtr]; + } break; + default: { + assert(NO); + result = NO; + } break; + } + return result; +} + +/*! Reads data from the ICMP socket. + * \details Called by the socket handling code (SocketReadCallback) to process an ICMP + * message waiting on the socket. + */ + +- (void)readData { + int err; + struct sockaddr_storage addr; + socklen_t addrLen; + ssize_t bytesRead; + void * buffer; + enum { kBufferSize = 65535 }; + + // 65535 is the maximum IP packet size, which seems like a reasonable bound + // here (plus it's what uses). + + buffer = malloc(kBufferSize); + assert(buffer != NULL); + + // Actually read the data. We use recvfrom(), and thus get back the source address, + // but we don't actually do anything with it. It would be trivial to pass it to + // the delegate but we don't need it in this example. + + addrLen = sizeof(addr); + bytesRead = recvfrom(CFSocketGetNative(self.socket), buffer, kBufferSize, 0, (struct sockaddr *) &addr, &addrLen); + err = 0; + if (bytesRead < 0) { + err = errno; + } + + // Process the data we read. + + if (bytesRead > 0) { + NSMutableData * packet; + id strongDelegate; + uint16_t sequenceNumber; + + packet = [NSMutableData dataWithBytes:buffer length:(NSUInteger) bytesRead]; + assert(packet != nil); + + // We got some data, pass it up to our client. + + strongDelegate = self.delegate; + if ( [self validatePingResponsePacket:packet sequenceNumber:&sequenceNumber] ) { + if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didReceivePingResponsePacket:sequenceNumber:)] ) { + [strongDelegate simplePing:self didReceivePingResponsePacket:packet sequenceNumber:sequenceNumber]; + } + } else { + if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didReceiveUnexpectedPacket:)] ) { + [strongDelegate simplePing:self didReceiveUnexpectedPacket:packet]; + } + } + } else { + + // We failed to read the data, so shut everything down. + + if (err == 0) { + err = EPIPE; + } + [self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]]; + } + + free(buffer); + + // Note that we don't loop back trying to read more data. Rather, we just + // let CFSocket call us again. +} + +/*! The callback for our CFSocket object. + * \details This simply routes the call to our `-readData` method. + * \param s See the documentation for CFSocketCallBack. + * \param type See the documentation for CFSocketCallBack. + * \param address See the documentation for CFSocketCallBack. + * \param data See the documentation for CFSocketCallBack. + * \param info See the documentation for CFSocketCallBack; this is actually a pointer to the + * 'owning' object. + */ + +static void SocketReadCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) { + // This C routine is called by CFSocket when there's data waiting on our + // ICMP socket. It just redirects the call to Objective-C code. + LDSimplePing * obj; + + obj = (__bridge LDSimplePing *) info; + assert([obj isKindOfClass:[LDSimplePing class]]); + +#pragma unused(s) + assert(s == obj.socket); +#pragma unused(type) + assert(type == kCFSocketReadCallBack); +#pragma unused(address) + assert(address == nil); +#pragma unused(data) + assert(data == nil); + + [obj readData]; +} + +/*! Starts the send and receive infrastructure. + * \details This is called once we've successfully resolved `hostName` in to + * `hostAddress`. It's responsible for setting up the socket for sending and + * receiving pings. + */ + +- (void)startWithHostAddress { + int err; + int fd; + + assert(self.hostAddress != nil); + + // Open the socket. + + fd = -1; + err = 0; + switch (self.hostAddressFamily) { + case AF_INET: { + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); + if (fd < 0) { + err = errno; + } + } break; + case AF_INET6: { + fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); + if (fd < 0) { + err = errno; + } + } break; + default: { + err = EPROTONOSUPPORT; + } break; + } + + if (err != 0) { + [self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]]; + } else { + CFSocketContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; + CFRunLoopSourceRef rls; + id strongDelegate; + + // Wrap it in a CFSocket and schedule it on the runloop. + + self.socket = (CFSocketRef) CFAutorelease( CFSocketCreateWithNative(NULL, fd, kCFSocketReadCallBack, SocketReadCallback, &context) ); + assert(self.socket != NULL); + + // The socket will now take care of cleaning up our file descriptor. + + assert( CFSocketGetSocketFlags(self.socket) & kCFSocketCloseOnInvalidate ); + fd = -1; + + rls = CFSocketCreateRunLoopSource(NULL, self.socket, 0); + assert(rls != NULL); + + CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); + + CFRelease(rls); + + strongDelegate = self.delegate; + if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didStartWithAddress:)] ) { + [strongDelegate simplePing:self didStartWithAddress:self.hostAddress]; + } + } + assert(fd == -1); +} + +/*! Processes the results of our name-to-address resolution. + * \details Called by our CFHost resolution callback (HostResolveCallback) when host + * resolution is complete. We just latch the first appropriate address and kick + * off the send and receive infrastructure. + */ + +- (void)hostResolutionDone { + Boolean resolved; + NSArray * addresses; + + // Find the first appropriate address. + + addresses = (__bridge NSArray *) CFHostGetAddressing(self.host, &resolved); + if ( resolved && (addresses != nil) ) { + resolved = false; + for (NSData * address in addresses) { + const struct sockaddr * addrPtr; + + addrPtr = (const struct sockaddr *) address.bytes; + if ( address.length >= sizeof(struct sockaddr) ) { + switch (addrPtr->sa_family) { + case AF_INET: { + if (self.addressStyle != SimplePingAddressStyleICMPv6) { + self.hostAddress = address; + resolved = true; + } + } break; + case AF_INET6: { + if (self.addressStyle != SimplePingAddressStyleICMPv4) { + self.hostAddress = address; + resolved = true; + } + } break; + } + } + if (resolved) { + break; + } + } + } + + // We're done resolving, so shut that down. + + [self stopHostResolution]; + + // If all is OK, start the send and receive infrastructure, otherwise stop. + + if (resolved) { + [self startWithHostAddress]; + } else { + [self didFailWithError:[NSError errorWithDomain:(NSString *)kCFErrorDomainCFNetwork code:kCFHostErrorHostNotFound userInfo:nil]]; + } +} + +/*! The callback for our CFHost object. + * \details This simply routes the call to our `-hostResolutionDone` or + * `-didFailWithHostStreamError:` methods. + * \param theHost See the documentation for CFHostClientCallBack. + * \param typeInfo See the documentation for CFHostClientCallBack. + * \param error See the documentation for CFHostClientCallBack. + * \param info See the documentation for CFHostClientCallBack; this is actually a pointer to + * the 'owning' object. + */ + +static void HostResolveCallback(CFHostRef theHost, CFHostInfoType typeInfo, const CFStreamError *error, void *info) { + // This C routine is called by CFHost when the host resolution is complete. + // It just redirects the call to the appropriate Objective-C method. + LDSimplePing * obj; + + obj = (__bridge LDSimplePing *) info; + assert([obj isKindOfClass:[LDSimplePing class]]); + +#pragma unused(theHost) + assert(theHost == obj.host); +#pragma unused(typeInfo) + assert(typeInfo == kCFHostAddresses); + + if ( (error != NULL) && (error->domain != 0) ) { + [obj didFailWithHostStreamError:*error]; + } else { + [obj hostResolutionDone]; + } +} + +/** + * 开启ping命令 + * 如果用户直接提供了一个ip地址,就可以直接开始执行ping命令 + * 否则需要创建socket获取host + */ + +- (void)start { + Boolean success; + CFHostClientContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; + CFStreamError streamError; + + assert(self.host == NULL); + assert(self.hostAddress == nil); + + self.host = (CFHostRef) CFAutorelease( CFHostCreateWithName(NULL, (__bridge CFStringRef) self.hostName) ); + assert(self.host != NULL); + + CFHostSetClient(self.host, HostResolveCallback, &context); + + CFHostScheduleWithRunLoop(self.host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + + success = CFHostStartInfoResolution(self.host, kCFHostAddresses, &streamError); + if ( ! success ) { + [self didFailWithHostStreamError:streamError]; + } +} + +/*! Stops the name-to-address resolution infrastructure. + */ + +- (void)stopHostResolution { + // Shut down the CFHost. + if (self.host != NULL) { + CFHostSetClient(self.host, NULL, NULL); + CFHostUnscheduleFromRunLoop(self.host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + self.host = NULL; + } +} + +/*! Stops the send and receive infrastructure. + */ + +- (void)stopSocket { + if (self.socket != NULL) { + CFSocketInvalidate(self.socket); + self.socket = NULL; + } +} + +- (void)stop { + [self stopHostResolution]; + [self stopSocket]; + + // Junk the host address on stop. If the client calls -start again, we'll + // re-resolve the host name. + + self.hostAddress = NULL; +} + + +/** + * IPV4的返回包直接将IPV4的头去掉了 + */ ++(const struct ICMPHeader *)icmpInPacket:(NSData *)packet +{ + const struct ICMPHeader *result; + result = nil; + + if (packet.length >= sizeof(*result)) { + result = packet.bytes; + } + + return result; +} + +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/Route.h b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/Route.h new file mode 100644 index 000000000..6ae553b38 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/LDNetDiagnoService/Route.h @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2000-2008 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1980, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)route.h 8.3 (Berkeley) 4/19/94 + * $FreeBSD: src/sys/net/route.h,v 1.36.2.1 2000/08/16 06:14:23 jayanth Exp $ + */ + +#ifndef _NET_ROUTE_H_ +#define _NET_ROUTE_H_ +#include +#include +#include +#include + +/* + * Kernel resident routing tables. + * + * The routing tables are initialized when interface addresses + * are set by making entries for all directly connected interfaces. + */ + +/* + * A route consists of a destination address and a reference + * to a routing entry. These are often held by protocols + * in their control blocks, e.g. inpcb. + */ +#ifdef PRIVATE +struct rtentry; +struct route { + /* + * N.B: struct route must begin with ro_rt and ro_flags + * because the code does some casts of a 'struct route_in6 *' + * to a 'struct route *'. + */ + struct rtentry *ro_rt; + uint32_t ro_flags; /* route flags (see below) */ + struct sockaddr ro_dst; +}; + +#define ROF_SRCIF_SELECTED 0x1 /* source interface was selected */ + +#else +struct route; +#endif /* PRIVATE */ + +/* + * These numbers are used by reliable protocols for determining + * retransmission behavior and are included in the routing structure. + */ +struct rt_metrics { + u_int32_t rmx_locks; /* Kernel must leave these values alone */ + u_int32_t rmx_mtu; /* MTU for this path */ + u_int32_t rmx_hopcount; /* max hops expected */ + int32_t rmx_expire; /* lifetime for route, e.g. redirect */ + u_int32_t rmx_recvpipe; /* inbound delay-bandwidth product */ + u_int32_t rmx_sendpipe; /* outbound delay-bandwidth product */ + u_int32_t rmx_ssthresh; /* outbound gateway buffer limit */ + u_int32_t rmx_rtt; /* estimated round trip time */ + u_int32_t rmx_rttvar; /* estimated rtt variance */ + u_int32_t rmx_pksent; /* packets sent using this route */ + u_int32_t rmx_filler[4]; /* will be used for T/TCP later */ +}; + +/* + * rmx_rtt and rmx_rttvar are stored as microseconds; + */ +#define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */ + +/* + * We distinguish between routes to hosts and routes to networks, + * preferring the former if available. For each route we infer + * the interface to use from the gateway address supplied when + * the route was entered. Routes that forward packets through + * gateways are marked so that the output routines know to address the + * gateway rather than the ultimate destination. + */ +#ifdef KERNEL_PRIVATE +#include +#ifndef RNF_NORMAL +#include +#endif +/* + * Kernel routing entry structure (private). + */ +struct rtentry { + struct radix_node rt_nodes[2]; /* tree glue, and other values */ +#define rt_key(r) ((struct sockaddr *)((r)->rt_nodes->rn_key)) +#define rt_mask(r) ((struct sockaddr *)((r)->rt_nodes->rn_mask)) + struct sockaddr *rt_gateway; /* value */ + int32_t rt_refcnt; /* # held references */ + uint32_t rt_flags; /* up/down?, host/net */ + struct ifnet *rt_ifp; /* the answer: interface to use */ + struct ifaddr *rt_ifa; /* the answer: interface addr to use */ + struct sockaddr *rt_genmask; /* for generation of cloned routes */ + void *rt_llinfo; /* pointer to link level info cache */ + void (*rt_llinfo_free)(void *); /* link level info free function */ + struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */ + struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */ + struct rtentry *rt_parent; /* cloning parent of this route */ + uint32_t generation_id; /* route generation id */ + /* + * See bsd/net/route.c for synchronization notes. + */ + decl_lck_mtx_data(, rt_lock); /* lock for routing entry */ +}; +#endif /* KERNEL_PRIVATE */ + +#ifdef KERNEL_PRIVATE +#define rt_use rt_rmx.rmx_pksent +#endif /* KERNEL_PRIVATE */ + +#define RTF_UP 0x1 /* route usable */ +#define RTF_GATEWAY 0x2 /* destination is a gateway */ +#define RTF_HOST 0x4 /* host entry (net otherwise) */ +#define RTF_REJECT 0x8 /* host or net unreachable */ +#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */ +#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ +#define RTF_DONE 0x40 /* message confirmed */ +#define RTF_DELCLONE 0x80 /* delete cloned route */ +#define RTF_CLONING 0x100 /* generate new routes on use */ +#define RTF_XRESOLVE 0x200 /* external daemon resolves name */ +#define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */ +#define RTF_STATIC 0x800 /* manually added */ +#define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */ +#define RTF_PROTO2 0x4000 /* protocol specific routing flag */ +#define RTF_PROTO1 0x8000 /* protocol specific routing flag */ + +#define RTF_PRCLONING 0x10000 /* protocol requires cloning */ +#define RTF_WASCLONED 0x20000 /* route generated through cloning */ +#define RTF_PROTO3 0x40000 /* protocol specific routing flag */ +/* 0x80000 unused */ +#define RTF_PINNED 0x100000 /* future use */ +#define RTF_LOCAL 0x200000 /* route represents a local address */ +#define RTF_BROADCAST 0x400000 /* route represents a bcast address */ +#define RTF_MULTICAST 0x800000 /* route represents a mcast address */ +#define RTF_IFSCOPE 0x1000000 /* has valid interface scope */ +#define RTF_CONDEMNED 0x2000000 /* defunct; no longer modifiable */ + /* 0x4000000 and up unassigned */ + +/* + * Routing statistics. + */ +struct rtstat { + short rts_badredirect; /* bogus redirect calls */ + short rts_dynamic; /* routes created by redirects */ + short rts_newgateway; /* routes modified by redirects */ + short rts_unreach; /* lookups which failed */ + short rts_wildcard; /* lookups satisfied by a wildcard */ +}; + +/* + * Structures for routing messages. + */ +struct rt_msghdr { + u_short rtm_msglen; /* to skip over non-understood messages */ + u_char rtm_version; /* future binary compatibility */ + u_char rtm_type; /* message type */ + u_short rtm_index; /* index for associated ifp */ + int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ + int rtm_addrs; /* bitmask identifying sockaddrs in msg */ + pid_t rtm_pid; /* identify sender */ + int rtm_seq; /* for sender to identify action */ + int rtm_errno; /* why failed */ + int rtm_use; /* from rtentry */ + u_int32_t rtm_inits; /* which metrics we are initializing */ + struct rt_metrics rtm_rmx; /* metrics themselves */ +}; + +struct rt_msghdr2 { + u_short rtm_msglen; /* to skip over non-understood messages */ + u_char rtm_version; /* future binary compatibility */ + u_char rtm_type; /* message type */ + u_short rtm_index; /* index for associated ifp */ + int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ + int rtm_addrs; /* bitmask identifying sockaddrs in msg */ + int32_t rtm_refcnt; /* reference count */ + int rtm_parentflags; /* flags of the parent route */ + int rtm_reserved; /* reserved field set to 0 */ + int rtm_use; /* from rtentry */ + u_int32_t rtm_inits; /* which metrics we are initializing */ + struct rt_metrics rtm_rmx; /* metrics themselves */ +}; + + +#define RTM_VERSION 5 /* Up the ante and ignore older versions */ + +/* + * Message types. + */ +#define RTM_ADD 0x1 /* Add Route */ +#define RTM_DELETE 0x2 /* Delete Route */ +#define RTM_CHANGE 0x3 /* Change Metrics or flags */ +#define RTM_GET 0x4 /* Report Metrics */ +#define RTM_LOSING 0x5 /* Kernel Suspects Partitioning */ +#define RTM_REDIRECT 0x6 /* Told to use different route */ +#define RTM_MISS 0x7 /* Lookup failed on this address */ +#define RTM_LOCK 0x8 /* fix specified metrics */ +#define RTM_OLDADD 0x9 /* caused by SIOCADDRT */ +#define RTM_OLDDEL 0xa /* caused by SIOCDELRT */ +#define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */ +#define RTM_NEWADDR 0xc /* address being added to iface */ +#define RTM_DELADDR 0xd /* address being removed from iface */ +#define RTM_IFINFO 0xe /* iface going up/down etc. */ +#define RTM_NEWMADDR 0xf /* mcast group membership being added to if */ +#define RTM_DELMADDR 0x10 /* mcast group membership being deleted */ +#ifdef PRIVATE +#define RTM_GET_SILENT 0x11 +#endif /* PRIVATE */ +#define RTM_IFINFO2 0x12 /* */ +#define RTM_NEWMADDR2 0x13 /* */ +#define RTM_GET2 0x14 /* */ + +/* + * Bitmask values for rtm_inits and rmx_locks. + */ +#define RTV_MTU 0x1 /* init or lock _mtu */ +#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */ +#define RTV_EXPIRE 0x4 /* init or lock _expire */ +#define RTV_RPIPE 0x8 /* init or lock _recvpipe */ +#define RTV_SPIPE 0x10 /* init or lock _sendpipe */ +#define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */ +#define RTV_RTT 0x40 /* init or lock _rtt */ +#define RTV_RTTVAR 0x80 /* init or lock _rttvar */ + +/* + * Bitmask values for rtm_addrs. + */ +#define RTA_DST 0x1 /* destination sockaddr present */ +#define RTA_GATEWAY 0x2 /* gateway sockaddr present */ +#define RTA_NETMASK 0x4 /* netmask sockaddr present */ +#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */ +#define RTA_IFP 0x10 /* interface name sockaddr present */ +#define RTA_IFA 0x20 /* interface addr sockaddr present */ +#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */ +#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */ + +/* + * Index offsets for sockaddr array for alternate internal encoding. + */ +#define RTAX_DST 0 /* destination sockaddr present */ +#define RTAX_GATEWAY 1 /* gateway sockaddr present */ +#define RTAX_NETMASK 2 /* netmask sockaddr present */ +#define RTAX_GENMASK 3 /* cloning mask sockaddr present */ +#define RTAX_IFP 4 /* interface name sockaddr present */ +#define RTAX_IFA 5 /* interface addr sockaddr present */ +#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */ +#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */ +#define RTAX_MAX 8 /* size of array to allocate */ + +struct rt_addrinfo { + int rti_addrs; + struct sockaddr *rti_info[RTAX_MAX]; +}; + +struct route_cb { + int ip_count; + int ip6_count; + int ipx_count; + int ns_count; + int iso_count; + int any_count; +}; + +#ifdef PRIVATE +/* + * For scoped routing; a zero interface scope value means nil/no scope. + */ +#define IFSCOPE_NONE 0 +#endif /* PRIVATE */ + +#ifdef KERNEL_PRIVATE +/* + * Generic call trace used by some subsystems (e.g. route, ifaddr) + */ +#define CTRACE_STACK_SIZE 8 /* depth of stack trace */ +#define CTRACE_HIST_SIZE 4 /* refcnt history size */ +typedef struct ctrace { + void *th; /* thread ptr */ + void *pc[CTRACE_STACK_SIZE]; /* PC stack trace */ +} ctrace_t; + +extern void ctrace_record(ctrace_t *); + +#define RT_LOCK_ASSERT_HELD(_rt) +lck_mtx_assert(&(_rt)->rt_lock, LCK_MTX_ASSERT_OWNED) + +#define RT_LOCK_ASSERT_NOTHELD(_rt) + lck_mtx_assert(&(_rt)->rt_lock, LCK_MTX_ASSERT_NOTOWNED) + +#define RT_LOCK(_rt) do { + if (!rte_debug) lck_mtx_lock(&(_rt)->rt_lock); +else rt_lock(_rt, FALSE); +} +while (0) + +#define RT_LOCK_SPIN(_rt) do { + if (!rte_debug) + lck_mtx_lock_spin(&(_rt)->rt_lock); + else + rt_lock(_rt, TRUE); +} +while (0) + +#define RT_CONVERT_LOCK(_rt) do { + RT_LOCK_ASSERT_HELD(_rt); +lck_mtx_convert_spin(&(_rt)->rt_lock); +} +while (0) + +#define RT_UNLOCK(_rt) do { + if (!rte_debug) + lck_mtx_unlock(&(_rt)->rt_lock); + else + rt_unlock(_rt); +} +while (0) + +#define RT_ADDREF_LOCKED(_rt) do { + if (!rte_debug) { + RT_LOCK_ASSERT_HELD(_rt); + if (++(_rt)->rt_refcnt == 0) + panic("RT_ADDREF(%p) bad refcnt + ", _rt); + } else { + rtref(_rt); + } +} +while (0) + +/* + * Spin variant mutex is used here; caller is responsible for + * converting any previously-held similar lock to full mutex. + */ +#define RT_ADDREF(_rt) do { + RT_LOCK_SPIN(_rt); +RT_ADDREF_LOCKED(_rt); +RT_UNLOCK(_rt); +} +while (0) + +#define RT_REMREF_LOCKED(_rt) do { + if (!rte_debug) { + RT_LOCK_ASSERT_HELD(_rt); + if ((_rt)->rt_refcnt == 0) + panic("RT_REMREF(%p) bad refcnt + ", _rt); + --(_rt)->rt_refcnt; + } else { + (void)rtunref(_rt); + } +} +while (0) + +/* + * Spin variant mutex is used here; caller is responsible for + * converting any previously-held similar lock to full mutex. + */ +#define RT_REMREF(_rt) do { + RT_LOCK_SPIN(_rt); +RT_REMREF_LOCKED(_rt); +RT_UNLOCK(_rt); +} +while (0) + +#define RTFREE(_rt) rtfree(_rt) +#define RTFREE_LOCKED(_rt) rtfree_locked(_rt) + + extern struct route_cb route_cb; +extern struct radix_node_head *rt_tables[AF_MAX + 1]; +__private_extern__ lck_mtx_t *rnh_lock; +__private_extern__ int use_routegenid; +__private_extern__ uint32_t route_generation; +__private_extern__ int rttrash; +__private_extern__ unsigned int rte_debug; + +struct ifmultiaddr; +struct proc; + +extern void route_init(void) __attribute__((section("__TEXT, initcode"))); +extern void routegenid_update(void); +extern void rt_ifmsg(struct ifnet *); +extern void rt_missmsg(int, struct rt_addrinfo *, int, int); +extern void rt_newaddrmsg(int, struct ifaddr *, int, struct rtentry *); +extern void rt_newmaddrmsg(int, struct ifmultiaddr *); +extern int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *); +extern void set_primary_ifscope(unsigned int); +extern unsigned int get_primary_ifscope(void); +extern boolean_t rt_inet_default(struct rtentry *, struct sockaddr *); +extern struct rtentry *rt_lookup(boolean_t, struct sockaddr *, struct sockaddr *, + struct radix_node_head *, unsigned int); +extern void rtalloc(struct route *); +extern void rtalloc_ign(struct route *, uint32_t); +extern void rtalloc_ign_locked(struct route *, uint32_t); +extern void rtalloc_scoped_ign(struct route *, uint32_t, unsigned int); +extern void rtalloc_scoped_ign_locked(struct route *, uint32_t, unsigned int); +extern struct rtentry *rtalloc1(struct sockaddr *, int, uint32_t); +extern struct rtentry *rtalloc1_locked(struct sockaddr *, int, uint32_t); +extern struct rtentry *rtalloc1_scoped(struct sockaddr *, int, uint32_t, unsigned int); +extern struct rtentry *rtalloc1_scoped_locked(struct sockaddr *, int, uint32_t, unsigned int); +extern void rtfree(struct rtentry *); +extern void rtfree_locked(struct rtentry *); +extern void rtref(struct rtentry *); +/* + * rtunref will decrement the refcount, rtfree will decrement and free if + * the refcount has reached zero and the route is not up. + * Unless you have good reason to do otherwise, use rtfree. + */ +extern int rtunref(struct rtentry *); +extern void rtsetifa(struct rtentry *, struct ifaddr *); +extern int rtinit(struct ifaddr *, int, int); +extern int rtinit_locked(struct ifaddr *, int, int); +extern int rtioctl(unsigned long, caddr_t, struct proc *); +extern void rtredirect(struct ifnet *, struct sockaddr *, struct sockaddr *, struct sockaddr *, int, + struct sockaddr *, struct rtentry **); +extern int rtrequest(int, struct sockaddr *, struct sockaddr *, struct sockaddr *, int, + struct rtentry **); +extern int rtrequest_locked(int, struct sockaddr *, struct sockaddr *, struct sockaddr *, int, + struct rtentry **); +extern int rtrequest_scoped_locked(int, struct sockaddr *, struct sockaddr *, struct sockaddr *, + int, struct rtentry **, unsigned int); +extern unsigned int sa_get_ifscope(struct sockaddr *); +extern void rt_lock(struct rtentry *, boolean_t); +extern void rt_unlock(struct rtentry *); +extern struct sockaddr *rtm_scrub_ifscope(int, struct sockaddr *, struct sockaddr *, + struct sockaddr_storage *); +#endif /* KERNEL_PRIVATE */ + +#endif \ No newline at end of file diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/NSData+gzip.h b/Coding_iOS/Util/Manager/EADeviceToServerLog/NSData+gzip.h new file mode 100644 index 000000000..f1271369b --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/NSData+gzip.h @@ -0,0 +1,14 @@ +// +// NSData+gzip.h +// CodingMart +// +// Created by Ease on 2016/11/30. +// Copyright © 2016年 net.coding. All rights reserved. +// + +#import + +@interface NSData (gzip) ++ (NSData *)ungzipData:(NSData *)compressedData; ++ (NSData*)gzipData:(NSData*)pUncompressedData; +@end diff --git a/Coding_iOS/Util/Manager/EADeviceToServerLog/NSData+gzip.m b/Coding_iOS/Util/Manager/EADeviceToServerLog/NSData+gzip.m new file mode 100644 index 000000000..a805aaf85 --- /dev/null +++ b/Coding_iOS/Util/Manager/EADeviceToServerLog/NSData+gzip.m @@ -0,0 +1,161 @@ +// +// NSData+gzip.m +// CodingMart +// +// Created by Ease on 2016/11/30. +// Copyright © 2016年 net.coding. All rights reserved. +// + +#import "NSData+gzip.h" +#import +//libbz2.1.0 +@implementation NSData (gzip) ++ (NSData *)ungzipData:(NSData *)compressedData +{ + if ([compressedData length] == 0) + return compressedData; + + unsigned full_length = (unsigned int)[compressedData length]; + unsigned half_length = (unsigned int)([compressedData length] / 2); + + NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length]; + BOOL done = NO; + int status; + + z_stream strm; + strm.next_in = (Bytef *)[compressedData bytes]; + strm.avail_in = (unsigned int)[compressedData length]; + strm.total_out = 0; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + if (inflateInit2(&strm, (15+32)) != Z_OK) + return nil; + + while (!done) { + // Make sure we have enough room and reset the lengths. + if (strm.total_out >= [decompressed length]) { + [decompressed increaseLengthBy: half_length]; + } + strm.next_out = [decompressed mutableBytes] + strm.total_out; + strm.avail_out = (unsigned int)([decompressed length] - strm.total_out); + // Inflate another chunk. + status = inflate (&strm, Z_SYNC_FLUSH); + if (status == Z_STREAM_END) { + done = YES; + } else if (status != Z_OK) { + break; + } + } + + if (inflateEnd (&strm) != Z_OK) + return nil; + // Set real length. + if (done) { + [decompressed setLength: strm.total_out]; + return [NSData dataWithData: decompressed]; + } + return nil; +} + ++ (NSData*)gzipData:(NSData*)pUncompressedData +{ + if (!pUncompressedData || [pUncompressedData length] == 0) + { + NSLog(@"%s: Error: Can't compress an empty or null NSData object.", __func__); + return nil; + } + + z_stream zlibStreamStruct; + zlibStreamStruct.zalloc = Z_NULL; // Set zalloc, zfree, and opaque to Z_NULL so + zlibStreamStruct.zfree = Z_NULL; // that when we call deflateInit2 they will be + zlibStreamStruct.opaque = Z_NULL; // updated to use default allocation functions. + zlibStreamStruct.total_out = 0; // Total number of output bytes produced so far + zlibStreamStruct.next_in = (Bytef*)[pUncompressedData bytes]; // Pointer to input bytes + zlibStreamStruct.avail_in = (unsigned int)[pUncompressedData length]; // Number of input bytes left to process + + int initError = deflateInit2(&zlibStreamStruct, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY); + if (initError != Z_OK) + { + NSString *errorMsg = nil; + switch (initError) + { + case Z_STREAM_ERROR: + errorMsg = @"Invalid parameter passed in to function."; + break; + case Z_MEM_ERROR: + errorMsg = @"Insufficient memory."; + break; + case Z_VERSION_ERROR: + errorMsg = @"The version of zlib.h and the version of the library linked do not match."; + break; + default: + errorMsg = @"Unknown error code."; + break; + } + NSLog(@"%s: deflateInit2() Error: \"%@\" Message: \"%s\"", __func__, errorMsg, zlibStreamStruct.msg); + + return nil; + } + + // Create output memory buffer for compressed data. The zlib documentation states that + // destination buffer size must be at least 0.1% larger than avail_in plus 12 bytes. + NSMutableData *compressedData = [NSMutableData dataWithLength:[pUncompressedData length] * 1.01 + 12]; + + int deflateStatus; + do + { + // Store location where next byte should be put in next_out + zlibStreamStruct.next_out = [compressedData mutableBytes] + zlibStreamStruct.total_out; + + // Calculate the amount of remaining free space in the output buffer + // by subtracting the number of bytes that have been written so far + // from the buffer's total capacity + zlibStreamStruct.avail_out = (unsigned int)([compressedData length] - zlibStreamStruct.total_out); + deflateStatus = deflate(&zlibStreamStruct, Z_FINISH); + + } while ( deflateStatus == Z_OK ); + + // Check for zlib error and convert code to usable error message if appropriate + if (deflateStatus != Z_STREAM_END) + { + NSString *errorMsg = nil; + switch (deflateStatus) + { + case Z_ERRNO: + errorMsg = @"Error occured while reading file."; + break; + case Z_STREAM_ERROR: + errorMsg = @"The stream state was inconsistent (e.g., next_in or next_out was NULL)."; + break; + case Z_DATA_ERROR: + errorMsg = @"The deflate data was invalid or incomplete."; + break; + case Z_MEM_ERROR: + errorMsg = @"Memory could not be allocated for processing."; + break; + case Z_BUF_ERROR: + errorMsg = @"Ran out of output buffer for writing compressed bytes."; + break; + case Z_VERSION_ERROR: + errorMsg = @"The version of zlib.h and the version of the library linked do not match."; + break; + default: + errorMsg = @"Unknown error code."; + break; + } + DebugLog(@"%s: zlib error while attempting compression: \"%@\" Message: \"%s\"", __func__, errorMsg, zlibStreamStruct.msg); + + // Free data structures that were dynamically created for the stream. + deflateEnd(&zlibStreamStruct); + + return nil; + } + // Free data structures that were dynamically created for the stream. + deflateEnd(&zlibStreamStruct); + [compressedData setLength: zlibStreamStruct.total_out]; + DebugLog(@"%s: Compressed file from %lu KB to %lu KB", __func__, [pUncompressedData length]/1024, [compressedData length]/1024); + + return compressedData; +} + +@end diff --git a/bootstrap b/bootstrap index 6f7292456..8bc218bce 100755 --- a/bootstrap +++ b/bootstrap @@ -4,5 +4,6 @@ cd $CMD_PATH cp Coding_iOS/Coding_iOS-Prefix.pch.example Coding_iOS/Coding_iOS-Prefix.pch git submodule update --init --recursive pod install +carthage update open Coding_iOS.xcworkspace exit 0