├── README.md
├── SimpleBS.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── bin1991.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── xcuserdata
│ └── bin1991.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ ├── SimpleBS.xcscheme
│ └── xcschememanagement.plist
├── SimpleBS
├── AppDelegate.swift
├── Base.lproj
│ ├── LaunchScreen.xib
│ └── Main.storyboard
├── CDZPinger.h
├── CDZPinger.m
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── ping.imageset
│ │ ├── Contents.json
│ │ ├── ping.png
│ │ ├── ping@2x.png
│ │ └── ping@3x.png
│ └── traceroute.imageset
│ │ ├── Contents.json
│ │ ├── traceroute.png
│ │ ├── traceroute@2x.png
│ │ └── traceroute@3x.png
├── Info.plist
├── Libraries
│ ├── BDHost.h
│ ├── BDHost.m
│ ├── Hop.h
│ └── Hop.m
├── PingTestViewController.swift
├── RootViewController.swift
├── SimpleBS-Bridging-Header.h
├── SimplePing.h
├── SimplePing.m
├── TraceRoute.h
├── TraceRoute.m
└── TraceRouteViewController.swift
├── SimpleBSTests
├── Info.plist
└── SimpleBSTests.swift
└── image
├── Preview.png
├── Preview1.PNG
├── Preview2.PNG
├── Preview3.PNG
├── ping.png
├── ping@2x.png
├── ping@3x.png
├── traceroute.png
├── traceroute@2x.png
└── traceroute@3x.png
/README.md:
--------------------------------------------------------------------------------
1 | # SimpleBS
2 | ## 自制的网络测试小工具
3 | ## A Simple Network Ping and Traceroute Tool
4 | 
5 |
6 | #### 基于另两位网友的OC类实现的ping以及traceroute编写,使用Swift1.2
7 |
8 | 1、软件初步完成,没有使用Autolayout,UI上还有些bug,比如在运行过程中滚动textview会阻塞ping操作导致时间不准,文本长度过长时没能自动往上滚动,UI设计比较糙。
9 | 2、更多功能等待加入,欢迎大家在issue栏发言,谢谢大家!
10 |
--------------------------------------------------------------------------------
/SimpleBS.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | A22A70061BA7A54000CF895A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A22A70051BA7A54000CF895A /* AppDelegate.swift */; };
11 | A22A70081BA7A54000CF895A /* RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A22A70071BA7A54000CF895A /* RootViewController.swift */; };
12 | A22A700B1BA7A54000CF895A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A22A70091BA7A54000CF895A /* Main.storyboard */; };
13 | A22A700D1BA7A54000CF895A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A22A700C1BA7A54000CF895A /* Images.xcassets */; };
14 | A22A70101BA7A54000CF895A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = A22A700E1BA7A54000CF895A /* LaunchScreen.xib */; };
15 | A22A701C1BA7A54000CF895A /* SimpleBSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A22A701B1BA7A54000CF895A /* SimpleBSTests.swift */; };
16 | A28E5BC21BB2410400E97695 /* TraceRoute.m in Sources */ = {isa = PBXBuildFile; fileRef = A28E5BC11BB2410400E97695 /* TraceRoute.m */; };
17 | A28E5BC61BB2413300E97695 /* BDHost.m in Sources */ = {isa = PBXBuildFile; fileRef = A28E5BC51BB2413300E97695 /* BDHost.m */; };
18 | A28E5BC91BB2414100E97695 /* Hop.m in Sources */ = {isa = PBXBuildFile; fileRef = A28E5BC81BB2414100E97695 /* Hop.m */; };
19 | A28E5BCB1BB25BFA00E97695 /* TraceRouteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A28E5BCA1BB25BFA00E97695 /* TraceRouteViewController.swift */; };
20 | A2B711DB1BACA932006614B7 /* CDZPinger.m in Sources */ = {isa = PBXBuildFile; fileRef = A2B711DA1BACA932006614B7 /* CDZPinger.m */; };
21 | A2B711DE1BACA965006614B7 /* SimplePing.m in Sources */ = {isa = PBXBuildFile; fileRef = A2B711DD1BACA965006614B7 /* SimplePing.m */; };
22 | A2B7C7AC1BAA3C72003A525F /* PingTestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2B7C7AB1BAA3C72003A525F /* PingTestViewController.swift */; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXContainerItemProxy section */
26 | A22A70161BA7A54000CF895A /* PBXContainerItemProxy */ = {
27 | isa = PBXContainerItemProxy;
28 | containerPortal = A22A6FF81BA7A54000CF895A /* Project object */;
29 | proxyType = 1;
30 | remoteGlobalIDString = A22A6FFF1BA7A54000CF895A;
31 | remoteInfo = SimpleBS;
32 | };
33 | /* End PBXContainerItemProxy section */
34 |
35 | /* Begin PBXFileReference section */
36 | A22A70001BA7A54000CF895A /* SimpleBS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SimpleBS.app; sourceTree = BUILT_PRODUCTS_DIR; };
37 | A22A70041BA7A54000CF895A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
38 | A22A70051BA7A54000CF895A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
39 | A22A70071BA7A54000CF895A /* RootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewController.swift; sourceTree = ""; };
40 | A22A700A1BA7A54000CF895A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
41 | A22A700C1BA7A54000CF895A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
42 | A22A700F1BA7A54000CF895A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
43 | A22A70151BA7A54000CF895A /* SimpleBSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SimpleBSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
44 | A22A701A1BA7A54000CF895A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
45 | A22A701B1BA7A54000CF895A /* SimpleBSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleBSTests.swift; sourceTree = ""; };
46 | A28E5BC01BB2410400E97695 /* TraceRoute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TraceRoute.h; sourceTree = ""; };
47 | A28E5BC11BB2410400E97695 /* TraceRoute.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TraceRoute.m; sourceTree = ""; };
48 | A28E5BC41BB2413300E97695 /* BDHost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BDHost.h; sourceTree = ""; };
49 | A28E5BC51BB2413300E97695 /* BDHost.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BDHost.m; sourceTree = ""; };
50 | A28E5BC71BB2414100E97695 /* Hop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Hop.h; path = Libraries/Hop.h; sourceTree = ""; };
51 | A28E5BC81BB2414100E97695 /* Hop.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Hop.m; path = Libraries/Hop.m; sourceTree = ""; };
52 | A28E5BCA1BB25BFA00E97695 /* TraceRouteViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TraceRouteViewController.swift; sourceTree = ""; };
53 | A2B711D81BACA931006614B7 /* SimpleBS-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimpleBS-Bridging-Header.h"; sourceTree = ""; };
54 | A2B711D91BACA932006614B7 /* CDZPinger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDZPinger.h; sourceTree = ""; };
55 | A2B711DA1BACA932006614B7 /* CDZPinger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDZPinger.m; sourceTree = ""; };
56 | A2B711DC1BACA965006614B7 /* SimplePing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimplePing.h; sourceTree = ""; };
57 | A2B711DD1BACA965006614B7 /* SimplePing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimplePing.m; sourceTree = ""; };
58 | A2B7C7AB1BAA3C72003A525F /* PingTestViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PingTestViewController.swift; sourceTree = ""; };
59 | /* End PBXFileReference section */
60 |
61 | /* Begin PBXFrameworksBuildPhase section */
62 | A22A6FFD1BA7A54000CF895A /* Frameworks */ = {
63 | isa = PBXFrameworksBuildPhase;
64 | buildActionMask = 2147483647;
65 | files = (
66 | );
67 | runOnlyForDeploymentPostprocessing = 0;
68 | };
69 | A22A70121BA7A54000CF895A /* Frameworks */ = {
70 | isa = PBXFrameworksBuildPhase;
71 | buildActionMask = 2147483647;
72 | files = (
73 | );
74 | runOnlyForDeploymentPostprocessing = 0;
75 | };
76 | /* End PBXFrameworksBuildPhase section */
77 |
78 | /* Begin PBXGroup section */
79 | A22A6FF71BA7A54000CF895A = {
80 | isa = PBXGroup;
81 | children = (
82 | A22A70021BA7A54000CF895A /* SimpleBS */,
83 | A22A70181BA7A54000CF895A /* SimpleBSTests */,
84 | A22A70011BA7A54000CF895A /* Products */,
85 | );
86 | sourceTree = "";
87 | };
88 | A22A70011BA7A54000CF895A /* Products */ = {
89 | isa = PBXGroup;
90 | children = (
91 | A22A70001BA7A54000CF895A /* SimpleBS.app */,
92 | A22A70151BA7A54000CF895A /* SimpleBSTests.xctest */,
93 | );
94 | name = Products;
95 | sourceTree = "";
96 | };
97 | A22A70021BA7A54000CF895A /* SimpleBS */ = {
98 | isa = PBXGroup;
99 | children = (
100 | A22A70051BA7A54000CF895A /* AppDelegate.swift */,
101 | A22A70071BA7A54000CF895A /* RootViewController.swift */,
102 | A2B7C7AB1BAA3C72003A525F /* PingTestViewController.swift */,
103 | A28E5BCA1BB25BFA00E97695 /* TraceRouteViewController.swift */,
104 | A22A70091BA7A54000CF895A /* Main.storyboard */,
105 | A22A700C1BA7A54000CF895A /* Images.xcassets */,
106 | A22A70031BA7A54000CF895A /* Supporting Files */,
107 | );
108 | path = SimpleBS;
109 | sourceTree = "";
110 | };
111 | A22A70031BA7A54000CF895A /* Supporting Files */ = {
112 | isa = PBXGroup;
113 | children = (
114 | A28E5BBF1BB240D900E97695 /* Traceroute */,
115 | A28E5BBE1BB23D0A00E97695 /* Ping */,
116 | A22A70041BA7A54000CF895A /* Info.plist */,
117 | A22A700E1BA7A54000CF895A /* LaunchScreen.xib */,
118 | A2B711D81BACA931006614B7 /* SimpleBS-Bridging-Header.h */,
119 | );
120 | name = "Supporting Files";
121 | sourceTree = "";
122 | };
123 | A22A70181BA7A54000CF895A /* SimpleBSTests */ = {
124 | isa = PBXGroup;
125 | children = (
126 | A22A701B1BA7A54000CF895A /* SimpleBSTests.swift */,
127 | A22A70191BA7A54000CF895A /* Supporting Files */,
128 | );
129 | path = SimpleBSTests;
130 | sourceTree = "";
131 | };
132 | A22A70191BA7A54000CF895A /* Supporting Files */ = {
133 | isa = PBXGroup;
134 | children = (
135 | A22A701A1BA7A54000CF895A /* Info.plist */,
136 | );
137 | name = "Supporting Files";
138 | sourceTree = "";
139 | };
140 | A28E5BBE1BB23D0A00E97695 /* Ping */ = {
141 | isa = PBXGroup;
142 | children = (
143 | A2B711D91BACA932006614B7 /* CDZPinger.h */,
144 | A2B711DA1BACA932006614B7 /* CDZPinger.m */,
145 | A2B711DC1BACA965006614B7 /* SimplePing.h */,
146 | A2B711DD1BACA965006614B7 /* SimplePing.m */,
147 | );
148 | name = Ping;
149 | sourceTree = "";
150 | };
151 | A28E5BBF1BB240D900E97695 /* Traceroute */ = {
152 | isa = PBXGroup;
153 | children = (
154 | A28E5BC31BB2413300E97695 /* Libraries */,
155 | A28E5BC71BB2414100E97695 /* Hop.h */,
156 | A28E5BC81BB2414100E97695 /* Hop.m */,
157 | A28E5BC01BB2410400E97695 /* TraceRoute.h */,
158 | A28E5BC11BB2410400E97695 /* TraceRoute.m */,
159 | );
160 | name = Traceroute;
161 | sourceTree = "";
162 | };
163 | A28E5BC31BB2413300E97695 /* Libraries */ = {
164 | isa = PBXGroup;
165 | children = (
166 | A28E5BC41BB2413300E97695 /* BDHost.h */,
167 | A28E5BC51BB2413300E97695 /* BDHost.m */,
168 | );
169 | path = Libraries;
170 | sourceTree = "";
171 | };
172 | /* End PBXGroup section */
173 |
174 | /* Begin PBXNativeTarget section */
175 | A22A6FFF1BA7A54000CF895A /* SimpleBS */ = {
176 | isa = PBXNativeTarget;
177 | buildConfigurationList = A22A701F1BA7A54000CF895A /* Build configuration list for PBXNativeTarget "SimpleBS" */;
178 | buildPhases = (
179 | A22A6FFC1BA7A54000CF895A /* Sources */,
180 | A22A6FFD1BA7A54000CF895A /* Frameworks */,
181 | A22A6FFE1BA7A54000CF895A /* Resources */,
182 | );
183 | buildRules = (
184 | );
185 | dependencies = (
186 | );
187 | name = SimpleBS;
188 | productName = SimpleBS;
189 | productReference = A22A70001BA7A54000CF895A /* SimpleBS.app */;
190 | productType = "com.apple.product-type.application";
191 | };
192 | A22A70141BA7A54000CF895A /* SimpleBSTests */ = {
193 | isa = PBXNativeTarget;
194 | buildConfigurationList = A22A70221BA7A54000CF895A /* Build configuration list for PBXNativeTarget "SimpleBSTests" */;
195 | buildPhases = (
196 | A22A70111BA7A54000CF895A /* Sources */,
197 | A22A70121BA7A54000CF895A /* Frameworks */,
198 | A22A70131BA7A54000CF895A /* Resources */,
199 | );
200 | buildRules = (
201 | );
202 | dependencies = (
203 | A22A70171BA7A54000CF895A /* PBXTargetDependency */,
204 | );
205 | name = SimpleBSTests;
206 | productName = SimpleBSTests;
207 | productReference = A22A70151BA7A54000CF895A /* SimpleBSTests.xctest */;
208 | productType = "com.apple.product-type.bundle.unit-test";
209 | };
210 | /* End PBXNativeTarget section */
211 |
212 | /* Begin PBXProject section */
213 | A22A6FF81BA7A54000CF895A /* Project object */ = {
214 | isa = PBXProject;
215 | attributes = {
216 | LastUpgradeCheck = 0640;
217 | ORGANIZATIONNAME = bin1991;
218 | TargetAttributes = {
219 | A22A6FFF1BA7A54000CF895A = {
220 | CreatedOnToolsVersion = 6.4;
221 | };
222 | A22A70141BA7A54000CF895A = {
223 | CreatedOnToolsVersion = 6.4;
224 | TestTargetID = A22A6FFF1BA7A54000CF895A;
225 | };
226 | };
227 | };
228 | buildConfigurationList = A22A6FFB1BA7A54000CF895A /* Build configuration list for PBXProject "SimpleBS" */;
229 | compatibilityVersion = "Xcode 3.2";
230 | developmentRegion = English;
231 | hasScannedForEncodings = 0;
232 | knownRegions = (
233 | en,
234 | Base,
235 | );
236 | mainGroup = A22A6FF71BA7A54000CF895A;
237 | productRefGroup = A22A70011BA7A54000CF895A /* Products */;
238 | projectDirPath = "";
239 | projectRoot = "";
240 | targets = (
241 | A22A6FFF1BA7A54000CF895A /* SimpleBS */,
242 | A22A70141BA7A54000CF895A /* SimpleBSTests */,
243 | );
244 | };
245 | /* End PBXProject section */
246 |
247 | /* Begin PBXResourcesBuildPhase section */
248 | A22A6FFE1BA7A54000CF895A /* Resources */ = {
249 | isa = PBXResourcesBuildPhase;
250 | buildActionMask = 2147483647;
251 | files = (
252 | A22A700B1BA7A54000CF895A /* Main.storyboard in Resources */,
253 | A22A70101BA7A54000CF895A /* LaunchScreen.xib in Resources */,
254 | A22A700D1BA7A54000CF895A /* Images.xcassets in Resources */,
255 | );
256 | runOnlyForDeploymentPostprocessing = 0;
257 | };
258 | A22A70131BA7A54000CF895A /* Resources */ = {
259 | isa = PBXResourcesBuildPhase;
260 | buildActionMask = 2147483647;
261 | files = (
262 | );
263 | runOnlyForDeploymentPostprocessing = 0;
264 | };
265 | /* End PBXResourcesBuildPhase section */
266 |
267 | /* Begin PBXSourcesBuildPhase section */
268 | A22A6FFC1BA7A54000CF895A /* Sources */ = {
269 | isa = PBXSourcesBuildPhase;
270 | buildActionMask = 2147483647;
271 | files = (
272 | A2B711DB1BACA932006614B7 /* CDZPinger.m in Sources */,
273 | A22A70081BA7A54000CF895A /* RootViewController.swift in Sources */,
274 | A22A70061BA7A54000CF895A /* AppDelegate.swift in Sources */,
275 | A2B711DE1BACA965006614B7 /* SimplePing.m in Sources */,
276 | A2B7C7AC1BAA3C72003A525F /* PingTestViewController.swift in Sources */,
277 | A28E5BCB1BB25BFA00E97695 /* TraceRouteViewController.swift in Sources */,
278 | A28E5BC21BB2410400E97695 /* TraceRoute.m in Sources */,
279 | A28E5BC61BB2413300E97695 /* BDHost.m in Sources */,
280 | A28E5BC91BB2414100E97695 /* Hop.m in Sources */,
281 | );
282 | runOnlyForDeploymentPostprocessing = 0;
283 | };
284 | A22A70111BA7A54000CF895A /* Sources */ = {
285 | isa = PBXSourcesBuildPhase;
286 | buildActionMask = 2147483647;
287 | files = (
288 | A22A701C1BA7A54000CF895A /* SimpleBSTests.swift in Sources */,
289 | );
290 | runOnlyForDeploymentPostprocessing = 0;
291 | };
292 | /* End PBXSourcesBuildPhase section */
293 |
294 | /* Begin PBXTargetDependency section */
295 | A22A70171BA7A54000CF895A /* PBXTargetDependency */ = {
296 | isa = PBXTargetDependency;
297 | target = A22A6FFF1BA7A54000CF895A /* SimpleBS */;
298 | targetProxy = A22A70161BA7A54000CF895A /* PBXContainerItemProxy */;
299 | };
300 | /* End PBXTargetDependency section */
301 |
302 | /* Begin PBXVariantGroup section */
303 | A22A70091BA7A54000CF895A /* Main.storyboard */ = {
304 | isa = PBXVariantGroup;
305 | children = (
306 | A22A700A1BA7A54000CF895A /* Base */,
307 | );
308 | name = Main.storyboard;
309 | sourceTree = "";
310 | };
311 | A22A700E1BA7A54000CF895A /* LaunchScreen.xib */ = {
312 | isa = PBXVariantGroup;
313 | children = (
314 | A22A700F1BA7A54000CF895A /* Base */,
315 | );
316 | name = LaunchScreen.xib;
317 | sourceTree = "";
318 | };
319 | /* End PBXVariantGroup section */
320 |
321 | /* Begin XCBuildConfiguration section */
322 | A22A701D1BA7A54000CF895A /* Debug */ = {
323 | isa = XCBuildConfiguration;
324 | buildSettings = {
325 | ALWAYS_SEARCH_USER_PATHS = NO;
326 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
327 | CLANG_CXX_LIBRARY = "libc++";
328 | CLANG_ENABLE_MODULES = YES;
329 | CLANG_ENABLE_OBJC_ARC = YES;
330 | CLANG_WARN_BOOL_CONVERSION = YES;
331 | CLANG_WARN_CONSTANT_CONVERSION = YES;
332 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
333 | CLANG_WARN_EMPTY_BODY = YES;
334 | CLANG_WARN_ENUM_CONVERSION = YES;
335 | CLANG_WARN_INT_CONVERSION = YES;
336 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
337 | CLANG_WARN_UNREACHABLE_CODE = YES;
338 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
339 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
340 | COPY_PHASE_STRIP = NO;
341 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
342 | ENABLE_STRICT_OBJC_MSGSEND = YES;
343 | GCC_C_LANGUAGE_STANDARD = gnu99;
344 | GCC_DYNAMIC_NO_PIC = NO;
345 | GCC_NO_COMMON_BLOCKS = YES;
346 | GCC_OPTIMIZATION_LEVEL = 0;
347 | GCC_PREPROCESSOR_DEFINITIONS = (
348 | "DEBUG=1",
349 | "$(inherited)",
350 | );
351 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
352 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
353 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
354 | GCC_WARN_UNDECLARED_SELECTOR = YES;
355 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
356 | GCC_WARN_UNUSED_FUNCTION = YES;
357 | GCC_WARN_UNUSED_VARIABLE = YES;
358 | IPHONEOS_DEPLOYMENT_TARGET = 8.4;
359 | MTL_ENABLE_DEBUG_INFO = YES;
360 | ONLY_ACTIVE_ARCH = YES;
361 | SDKROOT = iphoneos;
362 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
363 | };
364 | name = Debug;
365 | };
366 | A22A701E1BA7A54000CF895A /* Release */ = {
367 | isa = XCBuildConfiguration;
368 | buildSettings = {
369 | ALWAYS_SEARCH_USER_PATHS = NO;
370 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
371 | CLANG_CXX_LIBRARY = "libc++";
372 | CLANG_ENABLE_MODULES = YES;
373 | CLANG_ENABLE_OBJC_ARC = YES;
374 | CLANG_WARN_BOOL_CONVERSION = YES;
375 | CLANG_WARN_CONSTANT_CONVERSION = YES;
376 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
377 | CLANG_WARN_EMPTY_BODY = YES;
378 | CLANG_WARN_ENUM_CONVERSION = YES;
379 | CLANG_WARN_INT_CONVERSION = YES;
380 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
381 | CLANG_WARN_UNREACHABLE_CODE = YES;
382 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
383 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
384 | COPY_PHASE_STRIP = NO;
385 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
386 | ENABLE_NS_ASSERTIONS = NO;
387 | ENABLE_STRICT_OBJC_MSGSEND = YES;
388 | GCC_C_LANGUAGE_STANDARD = gnu99;
389 | GCC_NO_COMMON_BLOCKS = YES;
390 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
391 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
392 | GCC_WARN_UNDECLARED_SELECTOR = YES;
393 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
394 | GCC_WARN_UNUSED_FUNCTION = YES;
395 | GCC_WARN_UNUSED_VARIABLE = YES;
396 | IPHONEOS_DEPLOYMENT_TARGET = 8.4;
397 | MTL_ENABLE_DEBUG_INFO = NO;
398 | SDKROOT = iphoneos;
399 | VALIDATE_PRODUCT = YES;
400 | };
401 | name = Release;
402 | };
403 | A22A70201BA7A54000CF895A /* Debug */ = {
404 | isa = XCBuildConfiguration;
405 | buildSettings = {
406 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
407 | CLANG_ENABLE_MODULES = YES;
408 | INFOPLIST_FILE = SimpleBS/Info.plist;
409 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
410 | PRODUCT_NAME = "$(TARGET_NAME)";
411 | SWIFT_OBJC_BRIDGING_HEADER = "SimpleBS/SimpleBS-Bridging-Header.h";
412 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
413 | };
414 | name = Debug;
415 | };
416 | A22A70211BA7A54000CF895A /* Release */ = {
417 | isa = XCBuildConfiguration;
418 | buildSettings = {
419 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
420 | CLANG_ENABLE_MODULES = YES;
421 | INFOPLIST_FILE = SimpleBS/Info.plist;
422 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
423 | PRODUCT_NAME = "$(TARGET_NAME)";
424 | SWIFT_OBJC_BRIDGING_HEADER = "SimpleBS/SimpleBS-Bridging-Header.h";
425 | };
426 | name = Release;
427 | };
428 | A22A70231BA7A54000CF895A /* Debug */ = {
429 | isa = XCBuildConfiguration;
430 | buildSettings = {
431 | BUNDLE_LOADER = "$(TEST_HOST)";
432 | FRAMEWORK_SEARCH_PATHS = (
433 | "$(SDKROOT)/Developer/Library/Frameworks",
434 | "$(inherited)",
435 | );
436 | GCC_PREPROCESSOR_DEFINITIONS = (
437 | "DEBUG=1",
438 | "$(inherited)",
439 | );
440 | INFOPLIST_FILE = SimpleBSTests/Info.plist;
441 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
442 | PRODUCT_NAME = "$(TARGET_NAME)";
443 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SimpleBS.app/SimpleBS";
444 | };
445 | name = Debug;
446 | };
447 | A22A70241BA7A54000CF895A /* Release */ = {
448 | isa = XCBuildConfiguration;
449 | buildSettings = {
450 | BUNDLE_LOADER = "$(TEST_HOST)";
451 | FRAMEWORK_SEARCH_PATHS = (
452 | "$(SDKROOT)/Developer/Library/Frameworks",
453 | "$(inherited)",
454 | );
455 | INFOPLIST_FILE = SimpleBSTests/Info.plist;
456 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
457 | PRODUCT_NAME = "$(TARGET_NAME)";
458 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SimpleBS.app/SimpleBS";
459 | };
460 | name = Release;
461 | };
462 | /* End XCBuildConfiguration section */
463 |
464 | /* Begin XCConfigurationList section */
465 | A22A6FFB1BA7A54000CF895A /* Build configuration list for PBXProject "SimpleBS" */ = {
466 | isa = XCConfigurationList;
467 | buildConfigurations = (
468 | A22A701D1BA7A54000CF895A /* Debug */,
469 | A22A701E1BA7A54000CF895A /* Release */,
470 | );
471 | defaultConfigurationIsVisible = 0;
472 | defaultConfigurationName = Release;
473 | };
474 | A22A701F1BA7A54000CF895A /* Build configuration list for PBXNativeTarget "SimpleBS" */ = {
475 | isa = XCConfigurationList;
476 | buildConfigurations = (
477 | A22A70201BA7A54000CF895A /* Debug */,
478 | A22A70211BA7A54000CF895A /* Release */,
479 | );
480 | defaultConfigurationIsVisible = 0;
481 | defaultConfigurationName = Release;
482 | };
483 | A22A70221BA7A54000CF895A /* Build configuration list for PBXNativeTarget "SimpleBSTests" */ = {
484 | isa = XCConfigurationList;
485 | buildConfigurations = (
486 | A22A70231BA7A54000CF895A /* Debug */,
487 | A22A70241BA7A54000CF895A /* Release */,
488 | );
489 | defaultConfigurationIsVisible = 0;
490 | defaultConfigurationName = Release;
491 | };
492 | /* End XCConfigurationList section */
493 | };
494 | rootObject = A22A6FF81BA7A54000CF895A /* Project object */;
495 | }
496 |
--------------------------------------------------------------------------------
/SimpleBS.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SimpleBS.xcodeproj/project.xcworkspace/xcuserdata/bin1991.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/SimpleBS.xcodeproj/project.xcworkspace/xcuserdata/bin1991.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/SimpleBS.xcodeproj/xcuserdata/bin1991.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/SimpleBS.xcodeproj/xcuserdata/bin1991.xcuserdatad/xcschemes/SimpleBS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
65 |
66 |
75 |
77 |
83 |
84 |
85 |
86 |
87 |
88 |
94 |
96 |
102 |
103 |
104 |
105 |
107 |
108 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/SimpleBS.xcodeproj/xcuserdata/bin1991.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SimpleBS.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | A22A6FFF1BA7A54000CF895A
16 |
17 | primary
18 |
19 |
20 | A22A70141BA7A54000CF895A
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/SimpleBS/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SimpleBS
4 | //
5 | // Created by bin1991 on 15/9/15.
6 | // Copyright (c) 2015年 bin1991. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(application: UIApplication) {
33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/SimpleBS/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/SimpleBS/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
31 |
37 |
43 |
49 |
55 |
61 |
67 |
73 |
79 |
85 |
86 |
87 |
88 |
94 |
104 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
173 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
--------------------------------------------------------------------------------
/SimpleBS/CDZPinger.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @protocol CDZPingerDelegate;
4 |
5 | @interface CDZPinger : NSObject
6 |
7 | @property (nonatomic, weak) id delegate;
8 | @property (nonatomic, copy, readonly) NSString *domainOrIp;
9 |
10 | /**
11 | * Number of pings to average. Defaults to 6.
12 | */
13 | @property (nonatomic, assign) NSUInteger averageNumberOfPings;
14 |
15 | /**
16 | * Seconds to wait in between pings. Defaults to 1.0.
17 | */
18 | @property (nonatomic, assign) NSTimeInterval pingWaitTime;
19 |
20 | /**
21 | * Designated initializer.
22 | *
23 | * @param domainOrIp Domain name or IPv4 address to ping
24 | */
25 | - (id)initWithHost:(NSString *)domainOrIp;
26 |
27 | /**
28 | * Tell the pinger to begin pinging when it's ready.
29 | */
30 | - (void)startPinging;
31 |
32 | /**
33 | * Tell the pinger to stop pinging and clean up.
34 | */
35 | - (void)stopPinging;
36 |
37 | @end
38 |
39 | @protocol CDZPingerDelegate
40 |
41 | /**
42 | * Called every time the pinger receives a ping back from the server.
43 | *
44 | * @param pinger This CDZPinger object
45 | * @param seconds The average ping time, in seconds
46 | */
47 | - (void)pinger:(CDZPinger *)pinger didUpdateWithAverageSeconds:(NSTimeInterval)seconds;
48 |
49 | @optional
50 |
51 | /**
52 | * Reports a ping error.
53 | *
54 | * Note: The pinger stops running after any error is encountered.
55 | *
56 | * @param pinger This CDZPinger object
57 | * @param error The NSError that was encountered
58 | */
59 | - (void)pinger:(CDZPinger *)pinger didEncounterError:(NSError *)error;
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/SimpleBS/CDZPinger.m:
--------------------------------------------------------------------------------
1 | #import "CDZPinger.h"
2 | #import "SimplePing.h"
3 |
4 | @interface CDZPinger ()
5 |
6 | @property (nonatomic, strong) SimplePing *simplePing;
7 | @property (nonatomic, copy) NSString *domainOrIp;
8 |
9 | @property (nonatomic, assign) BOOL pingingDesired;
10 |
11 | @property (nonatomic, strong) NSDate *pingStartTime;
12 | @property (nonatomic, strong, readonly) NSMutableArray *lastPingTimes;
13 |
14 | @end
15 |
16 | @implementation CDZPinger
17 |
18 | @synthesize lastPingTimes = _lastPingTimes;
19 |
20 | - (id)initWithHost:(NSString *)domainOrIp
21 | {
22 | self = [super init];
23 | if (self) {
24 | self.simplePing.delegate = self;
25 | self.domainOrIp = domainOrIp;
26 | self.averageNumberOfPings = 8;
27 | self.pingWaitTime = 1.0;
28 | }
29 | return self;
30 | }
31 |
32 | - (void)startPinging
33 | {
34 | if (!self.pingingDesired && !self.simplePing) {
35 | self.pingingDesired = YES;
36 | self.simplePing = [SimplePing simplePingWithHostName:self.domainOrIp];
37 | self.simplePing.delegate = self;
38 | [self.simplePing start];
39 | }
40 | }
41 |
42 | - (void)stopPinging
43 | {
44 | self.pingingDesired = NO;
45 | [self.simplePing stop];
46 | self.simplePing = nil;
47 | }
48 |
49 | - (void)receivedError:(NSError *)error {
50 | [self stopPinging];
51 |
52 | id delegate = self.delegate;
53 | if ([delegate respondsToSelector:@selector(pinger:didEncounterError:)]) {
54 | [delegate pinger:self didEncounterError:error];
55 | }
56 | }
57 |
58 | - (void)receivedPingWithTime:(NSTimeInterval)time {
59 | if (self.pingingDesired) {
60 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.pingWaitTime * NSEC_PER_SEC));
61 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
62 | [self sendPing];
63 | });
64 | }
65 |
66 | [self addPingTimeToRecord:time];
67 | __block NSTimeInterval totalTime = 0.0;
68 | __block NSUInteger timeCount = 0;
69 | [self.lastPingTimes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
70 | totalTime += [obj doubleValue];
71 | timeCount++;
72 | }];
73 | NSTimeInterval averageTime = totalTime/(double)timeCount;
74 |
75 | dispatch_async(dispatch_get_main_queue(), ^{
76 | id delegate = self.delegate;
77 | if ([delegate respondsToSelector:@selector(pinger:didUpdateWithAverageSeconds:)]) {
78 | [delegate pinger:self didUpdateWithAverageSeconds:averageTime];
79 | }
80 | });
81 | }
82 |
83 | - (void)sendPing
84 | {
85 | [self.simplePing sendPingWithData:nil];
86 | }
87 |
88 | - (void)addPingTimeToRecord:(NSTimeInterval)time
89 | {
90 | while (self.lastPingTimes.count >= self.averageNumberOfPings) {
91 | [self.lastPingTimes removeObjectAtIndex:0];
92 | }
93 | [self.lastPingTimes addObject:@(time)];
94 | }
95 |
96 | #pragma mark SimplePingDelegate methods
97 |
98 | - (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address
99 | {
100 | if (self.pingingDesired) [self sendPing];
101 | }
102 |
103 | - (void)simplePing:(SimplePing *)pinger didSendPacket:(NSData *)packet
104 | {
105 | self.pingStartTime = [NSDate date];
106 |
107 | NSLog(@"#%u sent", (unsigned int) OSSwapBigToHostInt16(((const ICMPHeader *) [packet bytes])->sequenceNumber));
108 | }
109 |
110 | - (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet
111 | {
112 | NSTimeInterval pingTime = [[NSDate date] timeIntervalSinceDate:self.pingStartTime];
113 | [self receivedPingWithTime:pingTime];
114 |
115 | NSLog(@"#%u received", (unsigned int) OSSwapBigToHostInt16([SimplePing icmpInPacket:packet]->sequenceNumber) );
116 | }
117 |
118 | - (void)simplePing:(SimplePing *)pinger didFailWithError:(NSError *)error
119 | {
120 | [self receivedError:error];
121 | }
122 |
123 | - (void)simplePing:(SimplePing *)pinger didFailToSendPacket:(NSData *)packet error:(NSError *)error
124 | {
125 | [self receivedError:error];
126 | }
127 |
128 | #pragma mark Property overrides
129 |
130 | - (NSMutableArray *)lastPingTimes
131 | {
132 | if (!_lastPingTimes) {
133 | _lastPingTimes = [NSMutableArray array];
134 | }
135 | return _lastPingTimes;
136 | }
137 |
138 | @end
139 |
--------------------------------------------------------------------------------
/SimpleBS/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/SimpleBS/Images.xcassets/ping.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "ping.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "ping@2x.png"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x",
16 | "filename" : "ping@3x.png"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/SimpleBS/Images.xcassets/ping.imageset/ping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/SimpleBS/Images.xcassets/ping.imageset/ping.png
--------------------------------------------------------------------------------
/SimpleBS/Images.xcassets/ping.imageset/ping@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/SimpleBS/Images.xcassets/ping.imageset/ping@2x.png
--------------------------------------------------------------------------------
/SimpleBS/Images.xcassets/ping.imageset/ping@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/SimpleBS/Images.xcassets/ping.imageset/ping@3x.png
--------------------------------------------------------------------------------
/SimpleBS/Images.xcassets/traceroute.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "traceroute.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "traceroute@2x.png"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x",
16 | "filename" : "traceroute@3x.png"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/SimpleBS/Images.xcassets/traceroute.imageset/traceroute.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/SimpleBS/Images.xcassets/traceroute.imageset/traceroute.png
--------------------------------------------------------------------------------
/SimpleBS/Images.xcassets/traceroute.imageset/traceroute@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/SimpleBS/Images.xcassets/traceroute.imageset/traceroute@2x.png
--------------------------------------------------------------------------------
/SimpleBS/Images.xcassets/traceroute.imageset/traceroute@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/SimpleBS/Images.xcassets/traceroute.imageset/traceroute@3x.png
--------------------------------------------------------------------------------
/SimpleBS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | com.bin1991.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSLocationAlwaysUsageDescription
26 | 我们需要使用你的地理位置
27 | NSLocationUsageDescription
28 | 我们需要使用你的地理位置
29 | UILaunchStoryboardName
30 | LaunchScreen
31 | UIMainStoryboardFile
32 | Main
33 | UIRequiredDeviceCapabilities
34 |
35 | armv7
36 |
37 | UISupportedInterfaceOrientations
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationLandscapeLeft
41 | UIInterfaceOrientationLandscapeRight
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/SimpleBS/Libraries/BDHost.h:
--------------------------------------------------------------------------------
1 | //
2 | // BDHost.h
3 | // TraceRoute
4 | //
5 | // Created by Christophe Janot on 06/06/13.
6 | // Copyright (c) 2013 Christophe Janot. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BDHost : NSObject
12 |
13 | + (NSString *)addressForHostname:(NSString *)hostname;
14 | + (NSString *)addressesForHostname:(NSString *)hostname;
15 | + (NSString *)hostnameForAddress:(NSString *)address;
16 | + (NSArray *)hostnamesForAddress:(NSString *)address;
17 | + (NSArray *)ipAddresses;
18 | + (NSArray *)ethernetAddresses;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/SimpleBS/Libraries/BDHost.m:
--------------------------------------------------------------------------------
1 | // MIT license
2 | // Remember to add CFNetwork.framework to your project using Add=>Existing Frameworks.
3 |
4 | #import "BDHost.h"
5 | #import
6 | #import
7 | #import
8 | #import
9 | #import
10 | #import
11 | #import
12 |
13 | @implementation BDHost
14 |
15 | + (NSString *)addressForHostname:(NSString *)hostname {
16 | NSArray *addresses = [BDHost addressesForHostname:hostname];
17 | if ([addresses count] > 0)
18 | return [addresses objectAtIndex:0];
19 | else
20 | return nil;
21 | }
22 |
23 | + (NSArray *)addressesForHostname:(NSString *)hostname {
24 | // Get the addresses for the given hostname.
25 | CFHostRef hostRef = CFHostCreateWithName(kCFAllocatorDefault, (__bridge CFStringRef)hostname);
26 | BOOL isSuccess = CFHostStartInfoResolution(hostRef, kCFHostAddresses, nil);
27 | if (!isSuccess) return nil;
28 | CFArrayRef addressesRef = CFHostGetAddressing(hostRef, nil);
29 | if (addressesRef == nil) return nil;
30 |
31 | // Convert these addresses into strings.
32 | char ipAddress[INET6_ADDRSTRLEN];
33 | NSMutableArray *addresses = [NSMutableArray array];
34 | CFIndex numAddresses = CFArrayGetCount(addressesRef);
35 | for (CFIndex currentIndex = 0; currentIndex < numAddresses; currentIndex++) {
36 | struct sockaddr *address = (struct sockaddr *)CFDataGetBytePtr(CFArrayGetValueAtIndex(addressesRef, currentIndex));
37 | if (address == nil) return nil;
38 | getnameinfo(address, address->sa_len, ipAddress, INET6_ADDRSTRLEN, nil, 0, NI_NUMERICHOST);
39 | if (ipAddress == nil) return nil;
40 | [addresses addObject:[NSString stringWithCString:ipAddress encoding:NSASCIIStringEncoding]];
41 | }
42 |
43 | return addresses;
44 | }
45 |
46 | + (NSString *)hostnameForAddress:(NSString *)address {
47 | NSArray *hostnames = [BDHost hostnamesForAddress:address];
48 | if ([hostnames count] > 0)
49 | return [hostnames objectAtIndex:0];
50 | else
51 | return nil;
52 | }
53 |
54 | + (NSArray *)hostnamesForAddress:(NSString *)address {
55 | // Get the host reference for the given address.
56 | struct addrinfo hints;
57 | struct addrinfo *result = NULL;
58 | memset(&hints, 0, sizeof(hints));
59 | hints.ai_flags = AI_NUMERICHOST;
60 | hints.ai_family = PF_UNSPEC;
61 | hints.ai_socktype = SOCK_STREAM;
62 | hints.ai_protocol = 0;
63 | int errorStatus = getaddrinfo([address cStringUsingEncoding:NSASCIIStringEncoding], NULL, &hints, &result);
64 | if (errorStatus != 0) return nil;
65 | CFDataRef addressRef = CFDataCreate(NULL, (UInt8 *)result->ai_addr, result->ai_addrlen);
66 | if (addressRef == nil) return nil;
67 | freeaddrinfo(result);
68 | CFHostRef hostRef = CFHostCreateWithAddress(kCFAllocatorDefault, addressRef);
69 | if (hostRef == nil) return nil;
70 | CFRelease(addressRef);
71 | BOOL isSuccess = CFHostStartInfoResolution(hostRef, kCFHostNames, NULL);
72 | if (!isSuccess) return nil;
73 |
74 | // Get the hostnames for the host reference.
75 | CFArrayRef hostnamesRef = CFHostGetNames(hostRef, NULL);
76 | NSMutableArray *hostnames = [NSMutableArray array];
77 | for (int currentIndex = 0; currentIndex < [(__bridge NSArray *)hostnamesRef count]; currentIndex++) {
78 | [hostnames addObject:[(__bridge NSArray *)hostnamesRef objectAtIndex:currentIndex]];
79 | }
80 |
81 | return hostnames;
82 | }
83 |
84 | + (NSArray *)ipAddresses {
85 | NSMutableArray *addresses = [NSMutableArray array];
86 | struct ifaddrs *interfaces = NULL;
87 | struct ifaddrs *currentAddress = NULL;
88 |
89 | int success = getifaddrs(&interfaces);
90 | if (success == 0) {
91 | currentAddress = interfaces;
92 | while(currentAddress != NULL) {
93 | if(currentAddress->ifa_addr->sa_family == AF_INET) {
94 | NSString *address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)currentAddress->ifa_addr)->sin_addr)];
95 | if (![address isEqual:@"127.0.0.1"]) {
96 | //NSLog(@"%@ ip: %@", [NSString stringWithUTF8String:currentAddress->ifa_name], address);
97 | [addresses addObject:address];
98 | }
99 | }
100 | currentAddress = currentAddress->ifa_next;
101 | }
102 | }
103 | freeifaddrs(interfaces);
104 | return addresses;
105 | }
106 |
107 | + (NSArray *)ethernetAddresses {
108 | NSMutableArray *addresses = [NSMutableArray array];
109 | struct ifaddrs *interfaces = NULL;
110 | struct ifaddrs *currentAddress = NULL;
111 | int success = getifaddrs(&interfaces);
112 | if (success == 0) {
113 | currentAddress = interfaces;
114 | while(currentAddress != NULL) {
115 | if(currentAddress->ifa_addr->sa_family == AF_LINK) {
116 | NSString *address = [NSString stringWithUTF8String:ether_ntoa((const struct ether_addr *)LLADDR((struct sockaddr_dl *)currentAddress->ifa_addr))];
117 |
118 | // ether_ntoa doesn't format the ethernet address with padding.
119 | char paddedAddress[80];
120 | int a,b,c,d,e,f;
121 | sscanf([address UTF8String], "%x:%x:%x:%x:%x:%x", &a, &b, &c, &d, &e, &f);
122 | sprintf(paddedAddress, "%02X:%02X:%02X:%02X:%02X:%02X",a,b,c,d,e,f);
123 | address = [NSString stringWithUTF8String:paddedAddress];
124 |
125 | if (![address isEqual:@"00:00:00:00:00:00"] && ![address isEqual:@"00:00:00:00:00:FF"]) {
126 | //NSLog(@"%@ mac: %@", [NSString stringWithUTF8String:currentAddress->ifa_name], address);
127 | [addresses addObject:address];
128 | }
129 | }
130 | currentAddress = currentAddress->ifa_next;
131 | }
132 | }
133 | freeifaddrs(interfaces);
134 | return addresses;
135 | }
136 |
137 | @end
138 |
--------------------------------------------------------------------------------
/SimpleBS/Libraries/Hop.h:
--------------------------------------------------------------------------------
1 | //
2 | // Hop.h
3 | // Traceroute
4 | //
5 | // Created by Christophe Janot on 06/06/13.
6 | // Copyright (c) 2013 Christophe Janot. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface Hop : NSObject {
12 | }
13 |
14 | @property NSString *hostAddress;
15 | @property NSString *hostName;
16 | @property int ttl;
17 | @property int time;
18 |
19 | - (Hop *)initWithHostAddress:(NSString *)hostAddress hostName:(NSString *)hostName ttl:(int)ttl time:(int)time;
20 | + (Hop *)HopsManager;
21 | + (Hop *)getHopAt:(int)pos;
22 | + (void)addHop:(Hop *)hop;
23 | + (int)hopsCount;
24 | + (void)clear;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/SimpleBS/Libraries/Hop.m:
--------------------------------------------------------------------------------
1 | //
2 | // Hop.m
3 | // Traceroute
4 | //
5 | // Created by Christophe Janot on 06/06/13.
6 | // Copyright (c) 2013 Christophe Janot. All rights reserved.
7 | //
8 |
9 | #import "Hop.h"
10 |
11 | @implementation Hop
12 |
13 | static Hop *HopsManager;
14 | static NSMutableArray *hops;
15 |
16 | @synthesize hostAddress = _hostAddress;
17 | @synthesize hostName = _hostName;
18 | @synthesize ttl = _ttl;
19 | @synthesize time = _time;
20 |
21 | - (Hop *)initWithHostAddress:(NSString *)hostAddress hostName:(NSString *)hostName ttl:(int)ttl time:(int)time
22 | {
23 | _hostAddress = hostAddress;
24 | _hostName = hostName;
25 | _ttl = ttl;
26 | _time = time;
27 |
28 | NSLog(@"Hop[%d]=%@ %dms",ttl,hostAddress,time);
29 |
30 | return self;
31 | }
32 |
33 | + (Hop *)HopsManager
34 | {
35 | if(!HopsManager) {
36 | HopsManager = [[self allocWithZone:NULL] init];
37 | hops = [[NSMutableArray alloc] init];
38 | }
39 |
40 | return HopsManager;
41 | }
42 |
43 | + (Hop *)getHopAt:(int)pos
44 | {
45 | //NSLog(@"getHopAt:%d",pos);
46 | if(pos >= [hops count]) {
47 | return [hops objectAtIndex:0];
48 | }
49 | return [hops objectAtIndex:pos];
50 | }
51 |
52 | /**
53 | * Ajoute un nouveau hop retourné par le traceroute.
54 | */
55 | + (void)addHop:(Hop *)hop
56 | {
57 | [hops addObject:hop];
58 | }
59 |
60 | /**
61 | * Retourne le nombre de hops couramment trouvés
62 | */
63 | + (int)hopsCount
64 | {
65 | return [hops count];
66 | }
67 |
68 | /**
69 | * Réinitialise la liste des hops
70 | */
71 | + (void)clear
72 | {
73 | [hops removeAllObjects];
74 | }
75 |
76 | @end
77 |
--------------------------------------------------------------------------------
/SimpleBS/PingTestViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NetworkTestViewController.swift
3 | // SimpleBS
4 | //
5 | // Created by bin1991 on 15/9/17.
6 | // Copyright (c) 2015年 bin1991. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class PingTestViewController: UIViewController, CDZPingerDelegate //, UITextViewDelegate
12 | {
13 |
14 | @IBOutlet weak var testAddressInput: UITextField!
15 | @IBOutlet weak var liveResultsView: UITextView!
16 | @IBOutlet weak var finalResultsView: UITextView!
17 | @IBOutlet weak var taskLabel: UILabel!
18 | @IBOutlet weak var OKTapped: UIButton!
19 |
20 | var pinger = CDZPinger()
21 | var currentTimes: Int = 0
22 | var errorTimes: Int = 0
23 | var allTime:[Int] = []
24 | var isBegin: Bool = true
25 | var finalOuput:String = ""
26 | var prefs = NSUserDefaults()
27 |
28 | override func viewDidLoad() {
29 | super.viewDidLoad()
30 | OKTapped.addTarget(self, action: "onClick", forControlEvents: UIControlEvents.TouchUpInside)
31 |
32 | prefs = NSUserDefaults.standardUserDefaults()
33 | var lastHost = prefs.stringForKey("LastHost")
34 | if (lastHost != nil) {
35 | testAddressInput.text = lastHost
36 | }
37 |
38 | println("ViewController Ping")
39 |
40 | // liveResultsView.delegate = self
41 |
42 | // Do any additional setup after loading the view.
43 | }
44 |
45 | func pinger(pinger: CDZPinger!, didUpdateWithAverageSeconds seconds: NSTimeInterval) {
46 | let takesTime = Int(seconds * 1000)
47 | println("Received ping; average time \(takesTime) ms")
48 | var output = liveResultsView.text
49 | currentTimes = currentTimes + 1
50 | liveResultsView.text = output + "\n" + " 64 bytes from" + " \(testAddressInput.text):" + " icmp_seq=\(currentTimes)" + " ttl=58" + " time=" + "\(takesTime)" + " ms"
51 | allTime.append(takesTime)
52 | }
53 |
54 | func pinger(pinger: CDZPinger!, didEncounterError error: NSError!) {
55 | println("请求超时")
56 | errorTimes = errorTimes + 1
57 | }
58 |
59 | func onClick()
60 | {
61 | if isBegin {
62 | self.OKTapped.setTitle("停止", forState: UIControlState.Normal)
63 | isBegin = !isBegin
64 | prefs.setObject(testAddressInput.text, forKey: "LastHost")
65 | prefs.synchronize()
66 | if let addressInput = testAddressInput.text {
67 | testAddressInput.resignFirstResponder()
68 | self.pinger = CDZPinger(host: addressInput)
69 | self.pinger.startPinging()
70 | self.pinger.delegate = self
71 | self.taskLabel.text = " PING \(addressInput): 56 data bytes"
72 | self.liveResultsView.text = ""
73 | }
74 | } else {
75 | self.OKTapped.setTitle("开始", forState: UIControlState.Normal)
76 | isBegin = !isBegin
77 | pinger.stopPinging()
78 | println("^C")
79 | println("\(allTime)")
80 |
81 | var lossPackets = String(format: "%.2f", (errorTimes / currentTimes) * 100) + "%"
82 | println("--- \(testAddressInput.text) ping statistics ---")
83 | println("\(currentTimes - 1) packets transmitted, \(currentTimes - errorTimes - 1) packets received, \(lossPackets) packet loss")
84 | finalOuput = " --- \(testAddressInput.text) ping statistics ---\n \(currentTimes - 1) packets transmitted, \(currentTimes - errorTimes - 1) packets received, \(lossPackets) packet loss\n"
85 |
86 | statistics()
87 | }
88 | }
89 |
90 | func statistics() {
91 |
92 | if allTime != [] {
93 | allTime.sort{ $0 < $1 }
94 | // //冒泡排序
95 | // for var i = 0; i < allTime.count - 1; ++i {
96 | // for var j = 0; j < allTime.count - 1 - i; ++j {
97 | // if allTime[j] > allTime[j + 1] {
98 | // var temp = allTime[j + 1]
99 | // allTime[j + 1] = allTime[j]
100 | // allTime[j] = temp
101 | // }
102 | // }
103 | // }
104 | println("\(allTime)")
105 | let minTime = allTime.first!
106 | let maxTime = allTime.last!
107 | var avgTime: Int = 0
108 | var sumTime: Int = 0
109 |
110 | for var j = 0; j < allTime.count; ++j {
111 | // println("\(j)")
112 | sumTime = sumTime + allTime[j]
113 | }
114 |
115 | if currentTimes != 0 {
116 | avgTime = sumTime / currentTimes
117 | }
118 |
119 | println("round-trip min/avg/max = \(minTime)/\(avgTime)/\(maxTime) ms")
120 |
121 | finalResultsView.text = finalOuput + "round-trip min/avg/max = \(minTime)/\(avgTime)/\(maxTime) ms\n"
122 |
123 | } else {
124 | println("^C")
125 | }
126 | }
127 |
128 | override func didReceiveMemoryWarning() {
129 | super.didReceiveMemoryWarning()
130 | // Dispose of any resources that can be recreated.
131 | }
132 |
133 | override func touchesEnded(touches: Set, withEvent event: UIEvent?) {
134 | testAddressInput.resignFirstResponder()
135 | }
136 |
137 | func textFieldShouldReturn(textField: UITextField) -> Bool {
138 | textField.resignFirstResponder()
139 | return true
140 | }
141 |
142 | /*
143 | // MARK: - Navigation
144 |
145 | // In a storyboard-based application, you will often want to do a little preparation before navigation
146 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
147 | // Get the new view controller using segue.destinationViewController.
148 | // Pass the selected object to the new view controller.
149 | }
150 | */
151 |
152 | }
153 |
--------------------------------------------------------------------------------
/SimpleBS/RootViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // SimpleBS
4 | //
5 | // Created by bin1991 on 15/9/15.
6 | // Copyright (c) 2015年 bin1991. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CoreTelephony
11 | import MapKit
12 | //import CoreLocation
13 |
14 | class RootViewController: UIViewController, MKMapViewDelegate
15 | {
16 |
17 | @IBOutlet weak var carrierNameLabel: UILabel!
18 | @IBOutlet weak var countryNameLabel: UILabel!
19 | @IBOutlet weak var vioceAndDataLabel: UILabel!
20 | @IBOutlet weak var deviceNameLabel: UILabel!
21 | @IBOutlet weak var osNamelabel: UILabel!
22 | @IBOutlet weak var osVesionLabel: UILabel!
23 | @IBOutlet weak var currentLocationMapView: MKMapView!
24 |
25 |
26 |
27 | override func viewDidLoad() {
28 | super.viewDidLoad()
29 | // Do any additional setup after loading the view, typically from a nib.
30 |
31 | getCarrierInfo()
32 | getDeviceInfo()
33 |
34 | //设置地图视图代理
35 | currentLocationMapView.delegate = self
36 | //显示当前位置
37 | currentLocationMapView.showsUserLocation = true
38 |
39 | println("ViewController Main")
40 | }
41 | //获取运营商数据
42 | func getCarrierInfo() {
43 | let telephonyInfo: CTTelephonyNetworkInfo = CTTelephonyNetworkInfo()
44 |
45 | if let carrier:CTCarrier = telephonyInfo.subscriberCellularProvider {
46 | // println("运营商信息: \(carrier.description)")
47 | // println("运营商名称: \(carrier.mobileNetworkCode)")
48 | let carrierCode = carrier.mobileNetworkCode
49 | let countryCode = carrier.mobileCountryCode
50 |
51 | // println("运营商名称: \(carrierNames[carrierCode]!)")
52 | // println("国家或地区: \(countryNames[countryCode]!)")
53 | self.carrierNameLabel.text = carrierNames[carrierCode]!
54 | self.countryNameLabel.text = countryNames[countryCode]!
55 | }
56 |
57 | //获取当前蜂窝网络数据类型并去掉前面没有用的23个字母
58 | if let networkInfo = telephonyInfo.currentRadioAccessTechnology {
59 | let fromIndex = advance(networkInfo.startIndex, 23)
60 | let networkType = networkInfo.substringFromIndex(fromIndex)
61 |
62 | // println("语音与数据: \(networkType)")
63 | self.vioceAndDataLabel.text = networkType
64 |
65 | //网络信号改变时输出新网络类型
66 | NSNotificationCenter.defaultCenter().addObserverForName(CTRadioAccessTechnologyDidChangeNotification,
67 | object: nil,
68 | queue: nil,
69 | usingBlock: { note in
70 | // println("语音与数据类型已变更为: \(networkType)")
71 | self.vioceAndDataLabel.text = networkType
72 | })
73 | }
74 | }
75 | //获取设备数据
76 | func getDeviceInfo() {
77 | let myDevice: UIDevice = UIDevice.currentDevice()
78 | // println("设备名称 : \(myDevice.name)")
79 | // println("系统名称 : \(myDevice.systemName)")
80 | // println("系统版本 : \(myDevice.systemVersion)")
81 | self.deviceNameLabel.text = myDevice.name
82 | self.osNamelabel.text = myDevice.systemName
83 | self.osVesionLabel.text = myDevice.systemVersion
84 |
85 | }
86 | //获取当前位置
87 | func mapView(mapView: MKMapView!, didUpdateUserLocation userLocation: MKUserLocation!) {
88 | let loc: CLLocationCoordinate2D = userLocation.coordinate
89 | let region: MKCoordinateRegion = MKCoordinateRegionMakeWithDistance(loc, 500, 500)
90 | self.currentLocationMapView.setRegion(region, animated: true)
91 | }
92 |
93 | override func didReceiveMemoryWarning() {
94 | super.didReceiveMemoryWarning()
95 | // Dispose of any resources that can be recreated.
96 | }
97 |
98 | // MARK: - Model
99 | let carrierNames: [String: String] =
100 | [
101 | "01": "Cellcard",
102 | "02": "hello",
103 | "03": "S Telecom",
104 | "04": "qb",
105 | "05": "Star-Cell",
106 | "06": "Smart",
107 | "18": "Mfone",
108 | "11": "Seatel",
109 | "09": "Beeline",
110 | "08": "Metfone"
111 | ]
112 |
113 | let countryNames: [String: String] =
114 | [
115 | "460": "中华人民共和国",
116 | "456": "柬埔寨",
117 | "525": "新加坡"
118 | ]
119 |
120 |
121 | }
122 |
123 |
--------------------------------------------------------------------------------
/SimpleBS/SimpleBS-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 | #import "CDZPinger.h"
6 | #import "TraceRoute.h"
--------------------------------------------------------------------------------
/SimpleBS/SimplePing.h:
--------------------------------------------------------------------------------
1 | /*
2 | File: SimplePing.h
3 |
4 | Contains: Implements ping.
5 |
6 | Written by: DTS
7 |
8 | Copyright: Copyright (c) 2010-2012 Apple Inc. All Rights Reserved.
9 |
10 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
11 | ("Apple") in consideration of your agreement to the following
12 | terms, and your use, installation, modification or
13 | redistribution of this Apple software constitutes acceptance of
14 | these terms. If you do not agree with these terms, please do
15 | not use, install, modify or redistribute this Apple software.
16 |
17 | In consideration of your agreement to abide by the following
18 | terms, and subject to these terms, Apple grants you a personal,
19 | non-exclusive license, under Apple's copyrights in this
20 | original Apple software (the "Apple Software"), to use,
21 | reproduce, modify and redistribute the Apple Software, with or
22 | without modifications, in source and/or binary forms; provided
23 | that if you redistribute the Apple Software in its entirety and
24 | without modifications, you must retain this notice and the
25 | following text and disclaimers in all such redistributions of
26 | the Apple Software. Neither the name, trademarks, service marks
27 | or logos of Apple Inc. may be used to endorse or promote
28 | products derived from the Apple Software without specific prior
29 | written permission from Apple. Except as expressly stated in
30 | this notice, no other rights or licenses, express or implied,
31 | are granted by Apple herein, including but not limited to any
32 | patent rights that may be infringed by your derivative works or
33 | by other works in which the Apple Software may be incorporated.
34 |
35 | The Apple Software is provided by Apple on an "AS IS" basis.
36 | APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
37 | WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
38 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING
39 | THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
40 | COMBINATION WITH YOUR PRODUCTS.
41 |
42 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
43 | INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
44 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY
46 | OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
47 | OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY
48 | OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
49 | OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
50 | SUCH DAMAGE.
51 |
52 | */
53 |
54 | #import
55 |
56 | #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
57 | #import
58 | #else
59 | #import
60 | #endif
61 |
62 | #include
63 |
64 | #pragma mark * SimplePing
65 |
66 | // The SimplePing class is a very simple class that lets you send and receive pings.
67 |
68 | @protocol SimplePingDelegate;
69 |
70 | @interface SimplePing : NSObject
71 |
72 | + (SimplePing *)simplePingWithHostName:(NSString *)hostName; // chooses first IPv4 address
73 | + (SimplePing *)simplePingWithHostAddress:(NSData *)hostAddress; // contains (struct sockaddr)
74 |
75 | @property (nonatomic, weak, readwrite) id delegate;
76 |
77 | @property (nonatomic, copy, readonly ) NSString * hostName;
78 | @property (nonatomic, copy, readonly ) NSData * hostAddress;
79 | @property (nonatomic, assign, readonly ) uint16_t identifier;
80 | @property (nonatomic, assign, readonly ) uint16_t nextSequenceNumber;
81 |
82 | - (void)start;
83 | // Starts the pinger object pinging. You should call this after
84 | // you've setup the delegate and any ping parameters.
85 |
86 | - (void)sendPingWithData:(NSData *)data;
87 | // Sends an actual ping. Pass nil for data to use a standard 56 byte payload (resulting in a
88 | // standard 64 byte ping). Otherwise pass a non-nil value and it will be appended to the
89 | // ICMP header.
90 | //
91 | // Do not try to send a ping before you receive the -simplePing:didStartWithAddress: delegate
92 | // callback.
93 |
94 | - (void)stop;
95 | // Stops the pinger object. You should call this when you're done
96 | // pinging.
97 |
98 | + (const struct ICMPHeader *)icmpInPacket:(NSData *)packet;
99 | // Given a valid IP packet contains an ICMP , returns the address of the ICMP header that
100 | // follows the IP header. This doesn't do any significant validation of the packet.
101 |
102 | @end
103 |
104 | @protocol SimplePingDelegate
105 |
106 | @optional
107 |
108 | - (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address;
109 | // Called after the SimplePing has successfully started up. After this callback, you
110 | // can start sending pings via -sendPingWithData:
111 |
112 | - (void)simplePing:(SimplePing *)pinger didFailWithError:(NSError *)error;
113 | // If this is called, the SimplePing object has failed. By the time this callback is
114 | // called, the object has stopped (that is, you don't need to call -stop yourself).
115 |
116 | // IMPORTANT: On the send side the packet does not include an IP header.
117 | // On the receive side, it does. In that case, use +[SimplePing icmpInPacket:]
118 | // to find the ICMP header within the packet.
119 |
120 | - (void)simplePing:(SimplePing *)pinger didSendPacket:(NSData *)packet;
121 | // Called whenever the SimplePing object has successfully sent a ping packet.
122 |
123 | - (void)simplePing:(SimplePing *)pinger didFailToSendPacket:(NSData *)packet error:(NSError *)error;
124 | // Called whenever the SimplePing object tries and fails to send a ping packet.
125 |
126 | - (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet;
127 | // Called whenever the SimplePing object receives an ICMP packet that looks like
128 | // a response to one of our pings (that is, has a valid ICMP checksum, has
129 | // an identifier that matches our identifier, and has a sequence number in
130 | // the range of sequence numbers that we've sent out).
131 |
132 | - (void)simplePing:(SimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet;
133 | // Called whenever the SimplePing object receives an ICMP packet that does not
134 | // look like a response to one of our pings.
135 |
136 | @end
137 |
138 | #pragma mark * IP and ICMP On-The-Wire Format
139 |
140 | // The following declarations specify the structure of ping packets on the wire.
141 |
142 | // IP header structure:
143 |
144 | struct IPHeader {
145 | uint8_t versionAndHeaderLength;
146 | uint8_t differentiatedServices;
147 | uint16_t totalLength;
148 | uint16_t identification;
149 | uint16_t flagsAndFragmentOffset;
150 | uint8_t timeToLive;
151 | uint8_t protocol;
152 | uint16_t headerChecksum;
153 | uint8_t sourceAddress[4];
154 | uint8_t destinationAddress[4];
155 | // options...
156 | // data...
157 | };
158 | typedef struct IPHeader IPHeader;
159 |
160 | check_compile_time(sizeof(IPHeader) == 20);
161 | check_compile_time(offsetof(IPHeader, versionAndHeaderLength) == 0);
162 | check_compile_time(offsetof(IPHeader, differentiatedServices) == 1);
163 | check_compile_time(offsetof(IPHeader, totalLength) == 2);
164 | check_compile_time(offsetof(IPHeader, identification) == 4);
165 | check_compile_time(offsetof(IPHeader, flagsAndFragmentOffset) == 6);
166 | check_compile_time(offsetof(IPHeader, timeToLive) == 8);
167 | check_compile_time(offsetof(IPHeader, protocol) == 9);
168 | check_compile_time(offsetof(IPHeader, headerChecksum) == 10);
169 | check_compile_time(offsetof(IPHeader, sourceAddress) == 12);
170 | check_compile_time(offsetof(IPHeader, destinationAddress) == 16);
171 |
172 | // ICMP type and code combinations:
173 |
174 | enum {
175 | kICMPTypeEchoReply = 0, // code is always 0
176 | kICMPTypeEchoRequest = 8 // code is always 0
177 | };
178 |
179 | // ICMP header structure:
180 |
181 | struct ICMPHeader {
182 | uint8_t type;
183 | uint8_t code;
184 | uint16_t checksum;
185 | uint16_t identifier;
186 | uint16_t sequenceNumber;
187 | // data...
188 | };
189 | typedef struct ICMPHeader ICMPHeader;
190 |
191 | check_compile_time(sizeof(ICMPHeader) == 8);
192 | check_compile_time(offsetof(ICMPHeader, type) == 0);
193 | check_compile_time(offsetof(ICMPHeader, code) == 1);
194 | check_compile_time(offsetof(ICMPHeader, checksum) == 2);
195 | check_compile_time(offsetof(ICMPHeader, identifier) == 4);
196 | check_compile_time(offsetof(ICMPHeader, sequenceNumber) == 6);
197 |
--------------------------------------------------------------------------------
/SimpleBS/SimplePing.m:
--------------------------------------------------------------------------------
1 | /*
2 | File: SimplePing.m
3 |
4 | Contains: Implements ping.
5 |
6 | Written by: DTS
7 |
8 | Copyright: Copyright (c) 2010-2012 Apple Inc. All Rights Reserved.
9 |
10 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
11 | ("Apple") in consideration of your agreement to the following
12 | terms, and your use, installation, modification or
13 | redistribution of this Apple software constitutes acceptance of
14 | these terms. If you do not agree with these terms, please do
15 | not use, install, modify or redistribute this Apple software.
16 |
17 | In consideration of your agreement to abide by the following
18 | terms, and subject to these terms, Apple grants you a personal,
19 | non-exclusive license, under Apple's copyrights in this
20 | original Apple software (the "Apple Software"), to use,
21 | reproduce, modify and redistribute the Apple Software, with or
22 | without modifications, in source and/or binary forms; provided
23 | that if you redistribute the Apple Software in its entirety and
24 | without modifications, you must retain this notice and the
25 | following text and disclaimers in all such redistributions of
26 | the Apple Software. Neither the name, trademarks, service marks
27 | or logos of Apple Inc. may be used to endorse or promote
28 | products derived from the Apple Software without specific prior
29 | written permission from Apple. Except as expressly stated in
30 | this notice, no other rights or licenses, express or implied,
31 | are granted by Apple herein, including but not limited to any
32 | patent rights that may be infringed by your derivative works or
33 | by other works in which the Apple Software may be incorporated.
34 |
35 | The Apple Software is provided by Apple on an "AS IS" basis.
36 | APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
37 | WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
38 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING
39 | THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
40 | COMBINATION WITH YOUR PRODUCTS.
41 |
42 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
43 | INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
44 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY
46 | OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
47 | OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY
48 | OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
49 | OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
50 | SUCH DAMAGE.
51 |
52 | */
53 |
54 | #import "SimplePing.h"
55 |
56 | #include
57 | #include
58 | #include
59 |
60 | #pragma mark * ICMP On-The-Wire Format
61 |
62 | static uint16_t in_cksum(const void *buffer, size_t bufferLen)
63 | // This is the standard BSD checksum code, modified to use modern types.
64 | {
65 | size_t bytesLeft;
66 | int32_t sum;
67 | const uint16_t * cursor;
68 | union {
69 | uint16_t us;
70 | uint8_t uc[2];
71 | } last;
72 | uint16_t answer;
73 |
74 | bytesLeft = bufferLen;
75 | sum = 0;
76 | cursor = buffer;
77 |
78 | /*
79 | * Our algorithm is simple, using a 32 bit accumulator (sum), we add
80 | * sequential 16 bit words to it, and at the end, fold back all the
81 | * carry bits from the top 16 bits into the lower 16 bits.
82 | */
83 | while (bytesLeft > 1) {
84 | sum += *cursor;
85 | cursor += 1;
86 | bytesLeft -= 2;
87 | }
88 |
89 | /* mop up an odd byte, if necessary */
90 | if (bytesLeft == 1) {
91 | last.uc[0] = * (const uint8_t *) cursor;
92 | last.uc[1] = 0;
93 | sum += last.us;
94 | }
95 |
96 | /* add back carry outs from top 16 bits to low 16 bits */
97 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
98 | sum += (sum >> 16); /* add carry */
99 | answer = (uint16_t) ~sum; /* truncate to 16 bits */
100 |
101 | return answer;
102 | }
103 |
104 | #pragma mark * SimplePing
105 |
106 | @interface SimplePing ()
107 |
108 | @property (nonatomic, copy, readwrite) NSData * hostAddress;
109 | @property (nonatomic, assign, readwrite) uint16_t nextSequenceNumber;
110 |
111 | - (void)stopHostResolution;
112 | - (void)stopDataTransfer;
113 |
114 | @end
115 |
116 | @implementation SimplePing
117 | {
118 | CFHostRef _host;
119 | CFSocketRef _socket;
120 | }
121 |
122 | @synthesize hostName = _hostName;
123 | @synthesize hostAddress = _hostAddress;
124 |
125 | @synthesize delegate = _delegate;
126 | @synthesize identifier = _identifier;
127 | @synthesize nextSequenceNumber = _nextSequenceNumber;
128 |
129 | - (id)initWithHostName:(NSString *)hostName address:(NSData *)hostAddress
130 | // The initialiser common to both of our construction class methods.
131 | {
132 | assert( (hostName != nil) == (hostAddress == nil) );
133 | self = [super init];
134 | if (self != nil) {
135 | self->_hostName = [hostName copy];
136 | self->_hostAddress = [hostAddress copy];
137 | self->_identifier = (uint16_t) arc4random();
138 | }
139 | return self;
140 | }
141 |
142 | - (void)dealloc
143 | {
144 | // -stop takes care of _host and _socket.
145 | [self stop];
146 | assert(self->_host == NULL);
147 | assert(self->_socket == NULL);
148 | }
149 |
150 | + (SimplePing *)simplePingWithHostName:(NSString *)hostName
151 | // See comment in header.
152 | {
153 | return [[SimplePing alloc] initWithHostName:hostName address:nil];
154 | }
155 |
156 | + (SimplePing *)simplePingWithHostAddress:(NSData *)hostAddress
157 | // See comment in header.
158 | {
159 | return [[SimplePing alloc] initWithHostName:NULL address:hostAddress];
160 | }
161 |
162 | - (void)noop
163 | {
164 | }
165 |
166 | - (void)didFailWithError:(NSError *)error
167 | // Shut down the pinger object and tell the delegate about the error.
168 | {
169 | assert(error != nil);
170 |
171 | // We retain ourselves temporarily because it's common for the delegate method
172 | // to release its last reference to use, which causes -dealloc to be called here.
173 | // If we then reference self on the return path, things go badly. I don't think
174 | // that happens currently, but I've got into the habit of doing this as a
175 | // defensive measure.
176 |
177 | [self performSelector:@selector(noop) withObject:nil afterDelay:0.0];
178 |
179 | [self stop];
180 | if ( (self.delegate != nil) && [self.delegate respondsToSelector:@selector(simplePing:didFailWithError:)] ) {
181 | [self.delegate simplePing:self didFailWithError:error];
182 | }
183 | }
184 |
185 | - (void)didFailWithHostStreamError:(CFStreamError)streamError
186 | // Convert the CFStreamError to an NSError and then call through to
187 | // -didFailWithError: to shut down the pinger object and tell the
188 | // delegate about the error.
189 | {
190 | NSDictionary * userInfo;
191 | NSError * error;
192 |
193 | if (streamError.domain == kCFStreamErrorDomainNetDB) {
194 | userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
195 | [NSNumber numberWithInteger:streamError.error], kCFGetAddrInfoFailureKey,
196 | nil
197 | ];
198 | } else {
199 | userInfo = nil;
200 | }
201 | error = [NSError errorWithDomain:(NSString *)kCFErrorDomainCFNetwork code:kCFHostErrorUnknown userInfo:userInfo];
202 | assert(error != nil);
203 |
204 | [self didFailWithError:error];
205 | }
206 |
207 | - (void)sendPingWithData:(NSData *)data
208 | // See comment in header.
209 | {
210 | int err;
211 | NSData * payload;
212 | NSMutableData * packet;
213 | ICMPHeader * icmpPtr;
214 | ssize_t bytesSent;
215 |
216 | // Construct the ping packet.
217 |
218 | payload = data;
219 | if (payload == nil) {
220 | payload = [[NSString stringWithFormat:@"%28zd bottles of beer on the wall", (ssize_t) 99 - (size_t) (self.nextSequenceNumber % 100) ] dataUsingEncoding:NSASCIIStringEncoding];
221 | assert(payload != nil);
222 |
223 | assert([payload length] == 56);
224 | }
225 |
226 | packet = [NSMutableData dataWithLength:sizeof(*icmpPtr) + [payload length]];
227 | assert(packet != nil);
228 |
229 | icmpPtr = [packet mutableBytes];
230 | icmpPtr->type = kICMPTypeEchoRequest;
231 | icmpPtr->code = 0;
232 | icmpPtr->checksum = 0;
233 | icmpPtr->identifier = OSSwapHostToBigInt16(self.identifier);
234 | icmpPtr->sequenceNumber = OSSwapHostToBigInt16(self.nextSequenceNumber);
235 | memcpy(&icmpPtr[1], [payload bytes], [payload length]);
236 |
237 | // The IP checksum returns a 16-bit number that's already in correct byte order
238 | // (due to wacky 1's complement maths), so we just put it into the packet as a
239 | // 16-bit unit.
240 |
241 | icmpPtr->checksum = in_cksum([packet bytes], [packet length]);
242 |
243 | // Send the packet.
244 |
245 | if (self->_socket == NULL) {
246 | bytesSent = -1;
247 | err = EBADF;
248 | } else {
249 | bytesSent = sendto(
250 | CFSocketGetNative(self->_socket),
251 | [packet bytes],
252 | [packet length],
253 | 0,
254 | (struct sockaddr *) [self.hostAddress bytes],
255 | (socklen_t) [self.hostAddress length]
256 | );
257 | err = 0;
258 | if (bytesSent < 0) {
259 | err = errno;
260 | }
261 | }
262 |
263 | // Handle the results of the send.
264 |
265 | if ( (bytesSent > 0) && (((NSUInteger) bytesSent) == [packet length]) ) {
266 |
267 | // Complete success. Tell the client.
268 |
269 | if ( (self.delegate != nil) && [self.delegate respondsToSelector:@selector(simplePing:didSendPacket:)] ) {
270 | [self.delegate simplePing:self didSendPacket:packet];
271 | }
272 | } else {
273 | NSError * error;
274 |
275 | // Some sort of failure. Tell the client.
276 |
277 | if (err == 0) {
278 | err = ENOBUFS; // This is not a hugely descriptor error, alas.
279 | }
280 | error = [NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil];
281 | if ( (self.delegate != nil) && [self.delegate respondsToSelector:@selector(simplePing:didFailToSendPacket:error:)] ) {
282 | [self.delegate simplePing:self didFailToSendPacket:packet error:error];
283 | }
284 | }
285 |
286 | self.nextSequenceNumber += 1;
287 | }
288 |
289 | + (NSUInteger)icmpHeaderOffsetInPacket:(NSData *)packet
290 | // Returns the offset of the ICMPHeader within an IP packet.
291 | {
292 | NSUInteger result;
293 | const struct IPHeader * ipPtr;
294 | size_t ipHeaderLength;
295 |
296 | result = NSNotFound;
297 | if ([packet length] >= (sizeof(IPHeader) + sizeof(ICMPHeader))) {
298 | ipPtr = (const IPHeader *) [packet bytes];
299 | assert((ipPtr->versionAndHeaderLength & 0xF0) == 0x40); // IPv4
300 | assert(ipPtr->protocol == 1); // ICMP
301 | ipHeaderLength = (ipPtr->versionAndHeaderLength & 0x0F) * sizeof(uint32_t);
302 | if ([packet length] >= (ipHeaderLength + sizeof(ICMPHeader))) {
303 | result = ipHeaderLength;
304 | }
305 | }
306 | return result;
307 | }
308 |
309 | + (const struct ICMPHeader *)icmpInPacket:(NSData *)packet
310 | // See comment in header.
311 | {
312 | const struct ICMPHeader * result;
313 | NSUInteger icmpHeaderOffset;
314 |
315 | result = nil;
316 | icmpHeaderOffset = [self icmpHeaderOffsetInPacket:packet];
317 | if (icmpHeaderOffset != NSNotFound) {
318 | result = (const struct ICMPHeader *) (((const uint8_t *)[packet bytes]) + icmpHeaderOffset);
319 | }
320 | return result;
321 | }
322 |
323 | - (BOOL)isValidPingResponsePacket:(NSMutableData *)packet
324 | // Returns true if the packet looks like a valid ping response packet destined
325 | // for us.
326 | {
327 | BOOL result;
328 | NSUInteger icmpHeaderOffset;
329 | ICMPHeader * icmpPtr;
330 | uint16_t receivedChecksum;
331 | uint16_t calculatedChecksum;
332 |
333 | result = NO;
334 |
335 | icmpHeaderOffset = [[self class] icmpHeaderOffsetInPacket:packet];
336 | if (icmpHeaderOffset != NSNotFound) {
337 | icmpPtr = (struct ICMPHeader *) (((uint8_t *)[packet mutableBytes]) + icmpHeaderOffset);
338 |
339 | receivedChecksum = icmpPtr->checksum;
340 | icmpPtr->checksum = 0;
341 | calculatedChecksum = in_cksum(icmpPtr, [packet length] - icmpHeaderOffset);
342 | icmpPtr->checksum = receivedChecksum;
343 |
344 | if (receivedChecksum == calculatedChecksum) {
345 | if ( (icmpPtr->type == kICMPTypeEchoReply) && (icmpPtr->code == 0) ) {
346 | if ( OSSwapBigToHostInt16(icmpPtr->identifier) == self.identifier ) {
347 | if ( OSSwapBigToHostInt16(icmpPtr->sequenceNumber) < self.nextSequenceNumber ) {
348 | result = YES;
349 | }
350 | }
351 | }
352 | }
353 | }
354 |
355 | return result;
356 | }
357 |
358 | - (void)readData
359 | // Called by the socket handling code (SocketReadCallback) to process an ICMP
360 | // messages waiting on the socket.
361 | {
362 | int err;
363 | struct sockaddr_storage addr;
364 | socklen_t addrLen;
365 | ssize_t bytesRead;
366 | void * buffer;
367 | enum { kBufferSize = 65535 };
368 |
369 | // 65535 is the maximum IP packet size, which seems like a reasonable bound
370 | // here (plus it's what uses).
371 |
372 | buffer = malloc(kBufferSize);
373 | assert(buffer != NULL);
374 |
375 | // Actually read the data.
376 |
377 | addrLen = sizeof(addr);
378 | bytesRead = recvfrom(CFSocketGetNative(self->_socket), buffer, kBufferSize, 0, (struct sockaddr *) &addr, &addrLen);
379 | err = 0;
380 | if (bytesRead < 0) {
381 | err = errno;
382 | }
383 |
384 | // Process the data we read.
385 |
386 | if (bytesRead > 0) {
387 | NSMutableData * packet;
388 |
389 | packet = [NSMutableData dataWithBytes:buffer length:(NSUInteger) bytesRead];
390 | assert(packet != nil);
391 |
392 | // We got some data, pass it up to our client.
393 |
394 | if ( [self isValidPingResponsePacket:packet] ) {
395 | if ( (self.delegate != nil) && [self.delegate respondsToSelector:@selector(simplePing:didReceivePingResponsePacket:)] ) {
396 | [self.delegate simplePing:self didReceivePingResponsePacket:packet];
397 | }
398 | } else {
399 | if ( (self.delegate != nil) && [self.delegate respondsToSelector:@selector(simplePing:didReceiveUnexpectedPacket:)] ) {
400 | [self.delegate simplePing:self didReceiveUnexpectedPacket:packet];
401 | }
402 | }
403 | } else {
404 |
405 | // We failed to read the data, so shut everything down.
406 |
407 | if (err == 0) {
408 | err = EPIPE;
409 | }
410 | [self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]];
411 | }
412 |
413 | free(buffer);
414 |
415 | // Note that we don't loop back trying to read more data. Rather, we just
416 | // let CFSocket call us again.
417 | }
418 |
419 | static void SocketReadCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
420 | // This C routine is called by CFSocket when there's data waiting on our
421 | // ICMP socket. It just redirects the call to Objective-C code.
422 | {
423 | SimplePing * obj;
424 |
425 | obj = (__bridge SimplePing *) info;
426 | assert([obj isKindOfClass:[SimplePing class]]);
427 |
428 | #pragma unused(s)
429 | assert(s == obj->_socket);
430 | #pragma unused(type)
431 | assert(type == kCFSocketReadCallBack);
432 | #pragma unused(address)
433 | assert(address == nil);
434 | #pragma unused(data)
435 | assert(data == nil);
436 |
437 | [obj readData];
438 | }
439 |
440 | - (void)startWithHostAddress
441 | // We have a host address, so let's actually start pinging it.
442 | {
443 | int err;
444 | int fd;
445 | const struct sockaddr * addrPtr;
446 |
447 | assert(self.hostAddress != nil);
448 |
449 | // Open the socket.
450 |
451 | addrPtr = (const struct sockaddr *) [self.hostAddress bytes];
452 |
453 | fd = -1;
454 | err = 0;
455 | switch (addrPtr->sa_family) {
456 | case AF_INET: {
457 | fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
458 | if (fd < 0) {
459 | err = errno;
460 | }
461 | } break;
462 | case AF_INET6:
463 | assert(NO);
464 | // fall through
465 | default: {
466 | err = EPROTONOSUPPORT;
467 | } break;
468 | }
469 |
470 | if (err != 0) {
471 | [self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]];
472 | } else {
473 | CFSocketContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
474 | CFRunLoopSourceRef rls;
475 |
476 | // Wrap it in a CFSocket and schedule it on the runloop.
477 |
478 | self->_socket = CFSocketCreateWithNative(NULL, fd, kCFSocketReadCallBack, SocketReadCallback, &context);
479 | assert(self->_socket != NULL);
480 |
481 | // The socket will now take care of cleaning up our file descriptor.
482 |
483 | assert( CFSocketGetSocketFlags(self->_socket) & kCFSocketCloseOnInvalidate );
484 | fd = -1;
485 |
486 | rls = CFSocketCreateRunLoopSource(NULL, self->_socket, 0);
487 | assert(rls != NULL);
488 |
489 | CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
490 |
491 | CFRelease(rls);
492 |
493 | if ( (self.delegate != nil) && [self.delegate respondsToSelector:@selector(simplePing:didStartWithAddress:)] ) {
494 | [self.delegate simplePing:self didStartWithAddress:self.hostAddress];
495 | }
496 | }
497 | assert(fd == -1);
498 | }
499 |
500 | - (void)hostResolutionDone
501 | // Called by our CFHost resolution callback (HostResolveCallback) when host
502 | // resolution is complete. We just latch the first IPv4 address and kick
503 | // off the pinging process.
504 | {
505 | Boolean resolved;
506 | NSArray * addresses;
507 |
508 | // Find the first IPv4 address.
509 |
510 | addresses = (__bridge NSArray *) CFHostGetAddressing(self->_host, &resolved);
511 | if ( resolved && (addresses != nil) ) {
512 | resolved = false;
513 | for (NSData * address in addresses) {
514 | const struct sockaddr * addrPtr;
515 |
516 | addrPtr = (const struct sockaddr *) [address bytes];
517 | if ( [address length] >= sizeof(struct sockaddr) && addrPtr->sa_family == AF_INET) {
518 | self.hostAddress = address;
519 | resolved = true;
520 | break;
521 | }
522 | }
523 | }
524 |
525 | // We're done resolving, so shut that down.
526 |
527 | [self stopHostResolution];
528 |
529 | // If all is OK, start pinging, otherwise shut down the pinger completely.
530 |
531 | if (resolved) {
532 | [self startWithHostAddress];
533 | } else {
534 | [self didFailWithError:[NSError errorWithDomain:(NSString *)kCFErrorDomainCFNetwork code:kCFHostErrorHostNotFound userInfo:nil]];
535 | }
536 | }
537 |
538 | static void HostResolveCallback(CFHostRef theHost, CFHostInfoType typeInfo, const CFStreamError *error, void *info)
539 | // This C routine is called by CFHost when the host resolution is complete.
540 | // It just redirects the call to the appropriate Objective-C method.
541 | {
542 | SimplePing * obj;
543 |
544 | NSLog(@">HostResolveCallback");
545 |
546 | obj = (__bridge SimplePing *) info;
547 | assert([obj isKindOfClass:[SimplePing class]]);
548 |
549 | #pragma unused(theHost)
550 | assert(theHost == obj->_host);
551 | #pragma unused(typeInfo)
552 | assert(typeInfo == kCFHostAddresses);
553 |
554 | if ( (error != NULL) && (error->domain != 0) ) {
555 | [obj didFailWithHostStreamError:*error];
556 | } else {
557 | [obj hostResolutionDone];
558 | }
559 | }
560 |
561 | - (void)start
562 | // See comment in header.
563 | {
564 | // If the user supplied us with an address, just start pinging that. Otherwise
565 | // start a host resolution.
566 |
567 | if (self->_hostAddress != nil) {
568 | [self startWithHostAddress];
569 | } else {
570 | Boolean success;
571 | CFHostClientContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
572 | CFStreamError streamError;
573 |
574 | assert(self->_host == NULL);
575 |
576 | self->_host = CFHostCreateWithName(NULL, (__bridge CFStringRef) self.hostName);
577 | assert(self->_host != NULL);
578 |
579 | CFHostSetClient(self->_host, HostResolveCallback, &context);
580 |
581 | CFHostScheduleWithRunLoop(self->_host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
582 |
583 | NSLog(@">CFHostStartInfoResolution");
584 | success = CFHostStartInfoResolution(self->_host, kCFHostAddresses, &streamError);
585 | NSLog(@"_host != NULL) {
596 | CFHostSetClient(self->_host, NULL, NULL);
597 | CFHostUnscheduleFromRunLoop(self->_host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
598 | CFRelease(self->_host);
599 | self->_host = NULL;
600 | }
601 | }
602 |
603 | - (void)stopDataTransfer
604 | // Shut down anything to do with sending and receiving pings.
605 | {
606 | if (self->_socket != NULL) {
607 | CFSocketInvalidate(self->_socket);
608 | CFRelease(self->_socket);
609 | self->_socket = NULL;
610 | }
611 | }
612 |
613 | - (void)stop
614 | // See comment in header.
615 | {
616 | [self stopHostResolution];
617 | [self stopDataTransfer];
618 |
619 | // If we were started with a host name, junk the host address on stop. If the
620 | // client calls -start again, we'll re-resolve the host name.
621 |
622 | if (self.hostName != nil) {
623 | self.hostAddress = NULL;
624 | }
625 | }
626 |
627 | @end
628 |
--------------------------------------------------------------------------------
/SimpleBS/TraceRoute.h:
--------------------------------------------------------------------------------
1 | //
2 | // TraceRoute.h
3 | // Classe implémentant les fonctionnalités d'un traceroute.
4 | //
5 | // Created by Christophe Janot on 06/06/13.
6 | // Copyright (c) 2013 Christophe Janot. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "Hop.h"
11 |
12 | static const int TRACEROUTE_PORT = 80;
13 | static const int TRACEROUTE_MAX_TTL = 20;
14 | static const int TRACEROUTE_ATTEMPTS = 2;
15 | static const int TRACEROUTE_TIMEOUT = 5000000;
16 |
17 | // Delégation afin de notifier chaque nouveau hop découvert pour chaque TTL.
18 | @protocol TraceRouteDelegate
19 |
20 | - (void)newHop:(Hop *)hop;
21 | - (void)end;
22 | - (void)error:(NSString *)errorDesc;
23 |
24 | @end
25 |
26 | @interface TraceRoute : NSObject{
27 |
28 | int udpPort;
29 | int maxTTL;
30 | int readTimeout;
31 | int maxAttempts;
32 | NSString *running;
33 | bool isrunning;
34 | }
35 |
36 | @property (nonatomic, weak) id delegate;
37 |
38 | - (TraceRoute *)initWithMaxTTL:(int)ttl timeout:(int)timeout maxAttempts:(int)attempts port:(int)port;
39 | - (Boolean)doTraceRouteToHost:(NSString *)host maxTTL:(int)ttl timeout:(int)timeout maxAttempts:(int)attempts port:(int)port;
40 | // - (Boolean)doTraceRouteToHost:(NSString *)host;
41 | - (void)stopTrace;
42 | + (int)hopsCount;
43 | - (bool)isRunning;
44 | + (long)getMicroSeconds;
45 | + (long)computeDurationSince:(long)uTime;
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/SimpleBS/TraceRoute.m:
--------------------------------------------------------------------------------
1 | //
2 | // TraceRoute.m
3 | // Traceroute
4 | //
5 | // Created by Christophe Janot on 06/06/13.
6 | // Copyright (c) 2013 Christophe Janot. All rights reserved.
7 | //
8 |
9 | #import "TraceRoute.h"
10 | #include
11 | #include
12 | #include
13 | #import "BDHost.h"
14 |
15 | @implementation TraceRoute
16 |
17 | - (TraceRoute *)initWithMaxTTL:(int)ttl timeout:(int)timeout maxAttempts:(int)attempts port:(int)port
18 | {
19 | [Hop HopsManager];
20 | maxTTL = ttl;
21 | udpPort = port;
22 | readTimeout = timeout;
23 | maxAttempts = attempts;
24 |
25 | return self;
26 | }
27 |
28 | /**
29 | * Exécution totalement paramétrée du traceroute.
30 | */
31 | - (Boolean)doTraceRouteToHost:(NSString *)host maxTTL:(int)ttl timeout:(int)timeout maxAttempts:(int)attempts port:(int)port
32 | {
33 | maxTTL = ttl;
34 | udpPort = port;
35 | readTimeout = timeout;
36 | maxAttempts = attempts;
37 | return [self doTraceRoute:host];
38 | }
39 |
40 | /**
41 | * Exécution du traceroute.
42 | */
43 | - (Boolean)doTraceRoute:(NSString *)host
44 | {
45 | struct hostent *host_entry = gethostbyname(host.UTF8String);
46 | char *ip_addr;
47 | ip_addr = inet_ntoa(*((struct in_addr *)host_entry->h_addr_list[0]));
48 | struct sockaddr_in destination,fromAddr;
49 | int recv_sock;
50 | int send_sock;
51 | Boolean error = false;
52 |
53 | isrunning = true;
54 | // On vide le cache des hops du précédente recherche
55 | [Hop clear];
56 |
57 | // Création de la socket destinée à traiter l'ICMP renvoyée.
58 | if ((recv_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP)) < 0) {
59 | if(_delegate != nil) {
60 | [_delegate error:@"Could not create recv socket"];
61 | }
62 | return false;
63 | }
64 | // Création de la socket destinée à l'émission des trames HTTP.
65 | if((send_sock = socket(AF_INET , SOCK_DGRAM,0))<0){
66 | if(_delegate != nil) {
67 | [_delegate error:@"Could not create xmit socket"];
68 | }
69 | return false;
70 | }
71 | memset(&destination, 0, sizeof(destination));
72 | destination.sin_family = AF_INET;
73 | destination.sin_addr.s_addr = inet_addr(ip_addr);
74 | destination.sin_port = htons(udpPort);
75 | struct timeval tv;
76 | tv.tv_sec = 0;
77 | tv.tv_usec = readTimeout;
78 | setsockopt(recv_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
79 | char *cmsg = "GET / HTTP/1.1\r\n\r\n";
80 | socklen_t n= sizeof(fromAddr);
81 | char buf[100];
82 |
83 | // index sur le TTL en cours de traitement.
84 | int ttl = 1;
85 |
86 | bool icmp = false; // Positionné à true lorsqu'on reçoit la trame ICMP en retour.
87 | Hop *routeHop;
88 | long startTime; // Timestamp lors de l'émission du GET HTTP
89 | int delta; // Durée de l'aller-retour jusqu'au hop.
90 |
91 | // On progresse jusqu'à un nombre de TTLs max.
92 | while(ttl <= maxTTL) {
93 | memset(&fromAddr, 0, sizeof(fromAddr));
94 | if(setsockopt(send_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
95 | error = true;
96 | if(_delegate != nil) {
97 | [_delegate error:@"setsockopt failled"];
98 | }
99 | }
100 |
101 | icmp = false;
102 |
103 | // On effectue plusieurs tentatives si on n'obtient pas de réponse avant le timeout.
104 | for(int try = 0;try < maxAttempts;try++) {
105 | delta = -1;
106 | startTime = [TraceRoute getMicroSeconds];
107 | if (sendto(send_sock,cmsg,sizeof(cmsg),0,(struct sockaddr *) &destination,sizeof(destination)) != sizeof(cmsg) ) {
108 | error = true;
109 | NSLog (@"WARN in send to...\n@");
110 | }
111 | int res = 0;
112 |
113 | if( (res = recvfrom(recv_sock, buf, 100, 0, (struct sockaddr *)&fromAddr,&n))<0) {
114 | // Erreur réseau ou timeout
115 | error = true;
116 | NSLog(@"WARN [%d/%d] %s; recvfrom returned %d\n", try, maxAttempts, strerror(errno), res);
117 | } else {
118 | // On a reçu une trame ICMP. on calcule le temps total entre l'envoi et la réception.
119 | delta = [TraceRoute computeDurationSince:startTime];
120 | char display[16]={0};
121 | // On flag pour spécifier qu'une trame ICMP a bien été reçue.
122 | icmp = true;
123 |
124 | // On décode l'adresse du hop ayant répondu.
125 | inet_ntop(AF_INET, &fromAddr.sin_addr.s_addr, display, sizeof (display));
126 | NSString *hostAddress = [NSString stringWithFormat:@"%s",display];
127 | NSString *hostName = [BDHost hostnameForAddress:hostAddress];
128 |
129 | routeHop = [[Hop alloc] initWithHostAddress:hostAddress hostName:hostName ttl:ttl time:delta];
130 | [Hop addHop:routeHop];
131 |
132 | break;
133 | }
134 | // On teste si l'utilisateur a demandé l'arrêt du traceroute
135 | @synchronized(running) {
136 | if(!isrunning) {
137 | ttl = maxTTL;
138 | // On force le statut d'icmp pour ne pas générer un Hop en sortie de boucle;
139 | icmp = true;
140 | break;
141 | }
142 | }
143 | }
144 | // Détection d'un timeout sur non réponse
145 | if(!icmp) {
146 | routeHop = [[Hop alloc] initWithHostAddress:@"*" hostName:@"*" ttl:ttl time:-1];
147 | [Hop addHop:routeHop];
148 | }
149 | dispatch_async(dispatch_get_main_queue(), ^{
150 | if(_delegate != nil) {
151 | [_delegate newHop:routeHop];
152 | }
153 | });
154 | ttl++;
155 | }
156 | isrunning = false;
157 | // On averti le delegate que le traceroute est terminé.
158 | dispatch_async(dispatch_get_main_queue(), ^{
159 | [_delegate end];
160 | });
161 | return error;
162 | }
163 |
164 | /**
165 | * Méthode demandant l'arrêt du traceroute.
166 | */
167 | - (void)stopTrace
168 | {
169 | @synchronized(running) {
170 | isrunning = false;
171 | }
172 | }
173 |
174 | /**
175 | * Retourne le nombre de hops couramment trouvés
176 | */
177 | + (int)hopsCount
178 | {
179 | return [Hop hopsCount];
180 | }
181 |
182 | /**
183 | * Retourne un boolean indiquant si le traceroute est toujours actif.
184 | */
185 | - (bool)isRunning
186 | {
187 | return isrunning;
188 | }
189 |
190 | /**
191 | * Retourne un timestamp en microsecondes.
192 | */
193 | + (long)getMicroSeconds
194 | {
195 | struct timeval time;
196 | gettimeofday(&time, NULL);
197 | return time.tv_usec;
198 | }
199 |
200 | /**
201 | * Calcule une durée en millisecondes par rapport au timestamp passé en paramètre.
202 | */
203 | + (long)computeDurationSince:(long)uTime
204 | {
205 | long now = [TraceRoute getMicroSeconds];
206 | if(now < uTime) {
207 | return 1000000 - uTime + now;
208 | }
209 | return now - uTime;
210 | }
211 |
212 | @end
213 |
--------------------------------------------------------------------------------
/SimpleBS/TraceRouteViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TraceRouteViewController.swift
3 | // SimpleBS
4 | //
5 | // Created by bin1991 on 15/9/23.
6 | // Copyright (c) 2015年 bin1991. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TraceRouteViewController: UIViewController, UITextFieldDelegate , TraceRouteDelegate
12 | {
13 | @IBOutlet weak var hostTextField: UITextField!
14 | @IBOutlet weak var hostNameLabel: UILabel!
15 | @IBOutlet weak var routeHopsTextView: UITextView!
16 | @IBOutlet weak var execButton: UIButton!
17 |
18 | var traceRoute:TraceRoute = TraceRoute()
19 | var prefs = NSUserDefaults()
20 |
21 | let ttl: Int32 = 20
22 | let timeout: Int32 = 5000000
23 | let port: Int32 = 80
24 | let maxAttempts: Int32 = 2
25 |
26 | override func viewDidLoad() {
27 | super.viewDidLoad()
28 |
29 | execButton.addTarget(self, action: "beginTrace", forControlEvents: UIControlEvents.TouchUpInside)
30 |
31 | prefs = NSUserDefaults.standardUserDefaults()
32 | var lastHost = prefs.stringForKey("LastHost")
33 | if (lastHost != nil) {
34 | hostTextField.text = lastHost
35 | }
36 |
37 | traceRoute = TraceRoute(maxTTL: ttl, timeout: timeout, maxAttempts: maxAttempts, port: port)
38 | traceRoute.delegate = self
39 |
40 | println("ViewController TraceRoute")
41 |
42 | // Do any additional setup after loading the view.
43 | }
44 |
45 | override func didReceiveMemoryWarning() {
46 | super.didReceiveMemoryWarning()
47 | // Dispose of any resources that can be recreated.
48 | }
49 |
50 | func beginTrace() {
51 | hostTextField.resignFirstResponder()
52 | if traceRoute.isRunning() {
53 | traceRoute.stopTrace()
54 |
55 | } else {
56 | prefs.setObject(hostTextField.text, forKey: "LastHost")
57 | prefs.synchronize()
58 |
59 | if let addressInput = hostTextField.text {
60 | NSThread.detachNewThreadSelector("doTraceRoute:", toTarget: traceRoute, withObject: addressInput)
61 | execButton.setTitle("停止", forState: UIControlState.Normal)
62 | routeHopsTextView.text = ""
63 | hostNameLabel.text = "traceroute \(addressInput)"
64 | }
65 | }
66 | }
67 |
68 | // MARK: - TraceRouteDelegate
69 |
70 | func newHop(hop: Hop!) {
71 |
72 | println("\(hop.hostAddress)")
73 |
74 | var output = routeHopsTextView.text
75 | routeHopsTextView.text = output + "\(hop.hostAddress)(\(hop.hostName)) \n"
76 | }
77 |
78 | func end() {
79 | execButton.setTitle("开始", forState: UIControlState.Normal)
80 | }
81 |
82 | func error(errorDesc: String!) {
83 | println("ERROR: \(errorDesc)")
84 | end()
85 | }
86 |
87 |
88 | override func touchesEnded(touches: Set, withEvent event: UIEvent?) {
89 | hostTextField.resignFirstResponder()
90 | }
91 |
92 | func textFieldShouldReturn(textField: UITextField) -> Bool {
93 | textField.resignFirstResponder()
94 | return true
95 | }
96 |
97 | /*
98 | // MARK: - Navigation
99 |
100 | // In a storyboard-based application, you will often want to do a little preparation before navigation
101 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
102 | // Get the new view controller using segue.destinationViewController.
103 | // Pass the selected object to the new view controller.
104 | }
105 | */
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/SimpleBSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | com.bin1991.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/SimpleBSTests/SimpleBSTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SimpleBSTests.swift
3 | // SimpleBSTests
4 | //
5 | // Created by bin1991 on 15/9/15.
6 | // Copyright (c) 2015年 bin1991. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import XCTest
11 |
12 | class SimpleBSTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | XCTAssert(true, "Pass")
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measureBlock() {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/image/Preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/image/Preview.png
--------------------------------------------------------------------------------
/image/Preview1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/image/Preview1.PNG
--------------------------------------------------------------------------------
/image/Preview2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/image/Preview2.PNG
--------------------------------------------------------------------------------
/image/Preview3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/image/Preview3.PNG
--------------------------------------------------------------------------------
/image/ping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/image/ping.png
--------------------------------------------------------------------------------
/image/ping@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/image/ping@2x.png
--------------------------------------------------------------------------------
/image/ping@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/image/ping@3x.png
--------------------------------------------------------------------------------
/image/traceroute.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/image/traceroute.png
--------------------------------------------------------------------------------
/image/traceroute@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/image/traceroute@2x.png
--------------------------------------------------------------------------------
/image/traceroute@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/botong-zhou/SimpleBS/e60223f8cca14cb9f5d942cbc8feeb9505b03229/image/traceroute@3x.png
--------------------------------------------------------------------------------