├── 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 | ![](https://raw.githubusercontent.com/bin1991/SimpleBS/master/image/Preview.png) 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 --------------------------------------------------------------------------------