Selaa lähdekoodia

1.局域网ping 功能已经推拉流用局域网Ip和端口链接设备

huangxiaodong 1 vuosi sitten
vanhempi
commit
7c351831ae

+ 32 - 0
创维盒子/双子星云手机.xcodeproj/project.pbxproj

@@ -146,6 +146,12 @@
 		6BF0F3D52AD3937B000AA133 /* DeviceThirdIdModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BF0F3D32AD3937B000AA133 /* DeviceThirdIdModel.h */; };
 		6BF0F3D62AD3937B000AA133 /* DeviceThirdIdModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BF0F3D42AD3937B000AA133 /* DeviceThirdIdModel.m */; };
 		6BF0F3D82AD3DB3C000AA133 /* planet.1ali_3ry_peer in Resources */ = {isa = PBXBuildFile; fileRef = 6BF0F3D72AD3DB3C000AA133 /* planet.1ali_3ry_peer */; };
+		6BF52C962AD5546500A617DB /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BF52C902AD5546500A617DB /* Reachability.m */; };
+		6BF52C972AD5546500A617DB /* SimplePing.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BF52C912AD5546500A617DB /* SimplePing.h */; };
+		6BF52C982AD5546500A617DB /* WHPingTester.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BF52C922AD5546500A617DB /* WHPingTester.h */; };
+		6BF52C992AD5546500A617DB /* Reachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BF52C932AD5546500A617DB /* Reachability.h */; };
+		6BF52C9A2AD5546500A617DB /* WHPingTester.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BF52C942AD5546500A617DB /* WHPingTester.m */; };
+		6BF52C9B2AD5546500A617DB /* SimplePing.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BF52C952AD5546500A617DB /* SimplePing.m */; };
 		6C21BF39CEECF8E81BD97788 /* libPods-双子星云手机Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 16C83602E592F43A82A92B3E /* libPods-双子星云手机Tests.a */; };
 		82762E13327622CA8A8512E6 /* libPods-隐私保护-双子星云手机UITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A7C795CAC690A410AE1E306 /* libPods-隐私保护-双子星云手机UITests.a */; };
 		A00221DB27EAFF4A00E45F78 /* HWAddBookmarkViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A00221D927EAFF4A00E45F78 /* HWAddBookmarkViewController.m */; };
@@ -439,6 +445,12 @@
 		6BF0F3D32AD3937B000AA133 /* DeviceThirdIdModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeviceThirdIdModel.h; sourceTree = "<group>"; };
 		6BF0F3D42AD3937B000AA133 /* DeviceThirdIdModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DeviceThirdIdModel.m; sourceTree = "<group>"; };
 		6BF0F3D72AD3DB3C000AA133 /* planet.1ali_3ry_peer */ = {isa = PBXFileReference; lastKnownFileType = file; path = planet.1ali_3ry_peer; sourceTree = "<group>"; };
+		6BF52C902AD5546500A617DB /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
+		6BF52C912AD5546500A617DB /* SimplePing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimplePing.h; sourceTree = "<group>"; };
+		6BF52C922AD5546500A617DB /* WHPingTester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WHPingTester.h; sourceTree = "<group>"; };
+		6BF52C932AD5546500A617DB /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
+		6BF52C942AD5546500A617DB /* WHPingTester.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WHPingTester.m; sourceTree = "<group>"; };
+		6BF52C952AD5546500A617DB /* SimplePing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimplePing.m; sourceTree = "<group>"; };
 		71D630B0FBD97501D316E4AB /* Pods-隐私保护.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-隐私保护.release.xcconfig"; path = "Target Support Files/Pods-隐私保护/Pods-隐私保护.release.xcconfig"; sourceTree = "<group>"; };
 		86FBD9FD629A5194B7C58D9F /* Pods-双子星云手机-双子星云手机UITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-双子星云手机-双子星云手机UITests.debug.xcconfig"; path = "Target Support Files/Pods-双子星云手机-双子星云手机UITests/Pods-双子星云手机-双子星云手机UITests.debug.xcconfig"; sourceTree = "<group>"; };
 		A00221D827EAFF4A00E45F78 /* HWAddBookmarkViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HWAddBookmarkViewController.h; sourceTree = "<group>"; };
@@ -997,6 +1009,19 @@
 			path = model;
 			sourceTree = "<group>";
 		};
+		6BF52C8F2AD5546500A617DB /* pingTool */ = {
+			isa = PBXGroup;
+			children = (
+				6BF52C902AD5546500A617DB /* Reachability.m */,
+				6BF52C912AD5546500A617DB /* SimplePing.h */,
+				6BF52C922AD5546500A617DB /* WHPingTester.h */,
+				6BF52C932AD5546500A617DB /* Reachability.h */,
+				6BF52C942AD5546500A617DB /* WHPingTester.m */,
+				6BF52C952AD5546500A617DB /* SimplePing.m */,
+			);
+			path = pingTool;
+			sourceTree = "<group>";
+		};
 		A003F69D27D841C800715CBF /* Base */ = {
 			isa = PBXGroup;
 			children = (
@@ -1025,6 +1050,7 @@
 		A003F6B727D841FF00715CBF /* Vendor */ = {
 			isa = PBXGroup;
 			children = (
+				6BF52C8F2AD5546500A617DB /* pingTool */,
 				18664FEA2AC28A0E008F8A61 /* UDP */,
 				18BA24852AA5C57900BA01EE /* RSATool.h */,
 				18BA24862AA5C57900BA01EE /* RSATool.m */,
@@ -1361,6 +1387,7 @@
 				18C4754F2A8E0DB5006129C0 /* MySetViewController.h in Headers */,
 				18FCE53F2AD136670020F623 /* PlayerViewController+TouchPointXD.h in Headers */,
 				18FCE53E2AD136670020F623 /* PlayerViewController+AdjustBtnFrame.h in Headers */,
+				6BF52C972AD5546500A617DB /* SimplePing.h in Headers */,
 				6B3F96342AD2A15A008E349E /* netWorkManager.h in Headers */,
 				184C8ADD2A949DBD00F26650 /* HWVersionModel.h in Headers */,
 				186820212AB98600005702A6 /* QRCodeScanViewController.h in Headers */,
@@ -1369,6 +1396,7 @@
 				183AE6D42A8CAFAE00B11CB0 /* UIView+View.h in Headers */,
 				184C8ACC2A94557200F26650 /* HidenMaskSetViewController.h in Headers */,
 				18EC79DC2ABC109F0084836A /* SetPWDSecondViewController.h in Headers */,
+				6BF52C992AD5546500A617DB /* Reachability.h in Headers */,
 				18BB18412AC417CB00A36F63 /* RYShearDeviceUDPManager.h in Headers */,
 				184C8AD52A949D5900F26650 /* AboutViewController.h in Headers */,
 				187076772A9F400300F15F7F /* PlayerLoadingView.h in Headers */,
@@ -1379,6 +1407,7 @@
 				18F9CB072ABD7835003FF71A /* QRCodeScanForChangeDeviceViewController.h in Headers */,
 				18664FF62AC2B3A4008F8A61 /* ShearDeviceUDPManager.h in Headers */,
 				18F9CAFF2ABD3643003FF71A /* ModifyPWDSecondViewController.h in Headers */,
+				6BF52C982AD5546500A617DB /* WHPingTester.h in Headers */,
 				18FCE5392AD1351B0020F623 /* PlayerViewController.h in Headers */,
 				183AE7C72A8CB39100B11CB0 /* SafeForKey.h in Headers */,
 				186820252AB9B5BF005702A6 /* SetPWDFirstViewController.h in Headers */,
@@ -1660,6 +1689,7 @@
 				A084D68927E8587400054880 /* HWToolViewController.m in Sources */,
 				18E557232A3C5D75005CC84B /* NSString+FloatHandle.m in Sources */,
 				A08A950227E9A4E400C544BB /* FMDatabase.m in Sources */,
+				6BF52C962AD5546500A617DB /* Reachability.m in Sources */,
 				18F9CAFB2ABD35C4003FF71A /* ModifyPWDFirstViewController.m in Sources */,
 				183AE6542A8A2CF000B11CB0 /* AFURLResponseSerialization.m in Sources */,
 				A0295B1227ED938B009C5D8B /* HWHistoryViewController.m in Sources */,
@@ -1705,11 +1735,13 @@
 				A08A94E027E9837600C544BB /* HWPageListCell.m in Sources */,
 				A084D69827E8657800054880 /* HWHomeListCell.m in Sources */,
 				183AE6032A89CE3C00B11CB0 /* JSONKeyMapper.m in Sources */,
+				6BF52C9B2AD5546500A617DB /* SimplePing.m in Sources */,
 				A08A950427E9A4E400C544BB /* FMResultSet.m in Sources */,
 				A003F6C227D841FF00715CBF /* UIScrollView+EmptyDataSet.m in Sources */,
 				183AE7C82A8CB39100B11CB0 /* SafeForKey.m in Sources */,
 				183AE6042A89CE3C00B11CB0 /* JSONModel.m in Sources */,
 				18FCE5492AD15E750020F623 /* PlayerViewController+AppDelegate.m in Sources */,
+				6BF52C9A2AD5546500A617DB /* WHPingTester.m in Sources */,
 				183AE6082A89CE3C00B11CB0 /* JSONHTTPClient.m in Sources */,
 				183AE6532A8A2CF000B11CB0 /* AFImageDownloader.m in Sources */,
 				A003F6B327D841EE00715CBF /* UIColor+HZXColor.m in Sources */,

+ 10 - 1
创维盒子/双子星云手机/Class/Guide/QRCodeScanViewController.m

@@ -9,6 +9,7 @@
 #import <AVFoundation/AVFoundation.h>
 #import <ImageIO/ImageIO.h>
 #import "GuideViewController.h"
+#import "RSATool.h"
 
 @interface QRCodeScanViewController ()<AVCaptureMetadataOutputObjectsDelegate,AVCaptureVideoDataOutputSampleBufferDelegate,UINavigationControllerDelegate,UIImagePickerControllerDelegate>
 
@@ -175,8 +176,16 @@ AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device
         
         /*扫描到有用信息时取消扫描*/
         NSString *resStr = object.stringValue;//RK3908P1V62112465
+        
+        if(resStr.length == @"Ch0IKJCY9lOgokjfPBFE1cowdC1+tj7ywB2pZgSzjhc=".length)
+        {
+            resStr = [RSATool AES128Decrypt:resStr key:@"fvO8gAfNSr1tbdQe"];
+            
+        }
+        
         if (([resStr containsString:@"RK"] && (resStr.length == @"RK3908P1V62112465".length))
-            || resStr.length == @"0333933700223250017273".length){
+            || resStr.length == @"0333933700223250017273".length
+             ){
             
             NSDictionary *newDict = [[NSDictionary alloc] initWithObjectsAndKeys:resStr,Const_Have_Add_Device_SN, nil];
             [HWDataManager setObjectWithKey:Const_Have_Add_Device value:newDict];

+ 41 - 14
创维盒子/双子星云手机/CloudPlayer/PlayerViewController.mm

@@ -197,19 +197,32 @@ UITextFieldDelegate>
 #pragma mark 检测融云链接是否完成
 - (void)checkThridRuiYunFun{
     
+    HLog(@"局域网是否能ping通:%d",[connectDeviceManager shareInstance].DeviceThirdIdMod.data.isPingOk);
     HLog(@"瑞云连接状态:%d",[[connectDeviceManager shareInstance] curConnectDeviceState]);
-    
-    if([[connectDeviceManager shareInstance] curConnectDeviceState] == DeviceConnectDeciceOk){
-        ip = @"127.0.0.1";
-        internetVideoPort = [[connectDeviceManager shareInstance] tcpPortStr];
-        [_checkThridConnectTimer invalidate];
-        
-        [self connectVideoServer];
-        [self opencommandChannelManagerrc_openURL];
-        
-        _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerChange) userInfo:nil repeats:YES];
-        [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
+    if([connectDeviceManager shareInstance].DeviceThirdIdMod.data.isPingOk){
+        ip = [connectDeviceManager shareInstance].DeviceThirdIdMod.data.ip;
+        internetVideoPort = @"9100";
+        [self didCanConnectServerFun];
+    }
+    else{
+        if([[connectDeviceManager shareInstance] curConnectDeviceState] == DeviceConnectDeciceOk){
+            ip = @"127.0.0.1";
+            internetVideoPort = [[connectDeviceManager shareInstance] tcpPortStr];
+            [self didCanConnectServerFun];
+        }
     }
+    
+}
+
+#pragma mark 走局域网或者瑞云SDK链接OK
+- (void)didCanConnectServerFun{
+    [_checkThridConnectTimer invalidate];
+    
+    [self connectVideoServer];
+    [self opencommandChannelManagerrc_openURL];
+    
+    _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerChange) userInfo:nil repeats:YES];
+    [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
 }
 
 - (void)initData
@@ -359,6 +372,11 @@ UITextFieldDelegate>
     //初始化指令通道
     self.commandChannelManager = [[RCCommandChannelManager alloc] init];
     NSString *instructionsChannelUrl = [NSString stringWithFormat:@"ws://%@:%@/businessChannel",ip,internetVideoPort];
+    
+    if([connectDeviceManager shareInstance].DeviceThirdIdMod.data.isPingOk){
+        instructionsChannelUrl = [NSString stringWithFormat:@"ws://%@:%@/businessChannel",ip,@"9300"];
+    }
+    
     if (instructionsChannelUrl && instructionsChannelUrl.length > 0) { //当都有值才可连接
         HLog(@"WebSocket11111指令通道连接开始11111 url = %@ ",instructionsChannelUrl);
         [self.commandChannelManager rc_openURL:instructionsChannelUrl connected:^{
@@ -1255,7 +1273,7 @@ NSDate *lastVideoTome;/*上一帧数据时间*/
 
 // 连接
 - (void)connectVideoServer {
-    if (!mySelf || haveBack){
+    if (!mySelf || haveBack || !ip || !internetVideoPort){
         return;
     }
     
@@ -1273,10 +1291,19 @@ NSDate *lastVideoTome;/*上一帧数据时间*/
     NSString *tempIP = ip;
     
     HLog(@"__连接ip__%@,端口__%@",ip,internetVideoPort);
+    
+    //
+    RCCloudPhoneConnectType ConnectType = RCCloudPhoneConnectType_websocket;
+    RCCloudPhoneVideoQuality VideoQuality = RCCloudPhoneVideoQuality_High;
+    if([connectDeviceManager shareInstance].DeviceThirdIdMod.data.isPingOk)
+    {
+        ConnectType = RCCloudPhoneConnectType_udp;
+        VideoQuality = RCCloudPhoneVideoQuality_Default;
+    }
     result = [self.liveStreamManager rc_openWithIp:ip
                                                          port:internetVideoPort.intValue
-                                                  connectType:RCCloudPhoneConnectType_websocket
-                                                 videoQuality:RCCloudPhoneVideoQuality_High
+                                                  connectType:ConnectType
+                                                 videoQuality:VideoQuality
                                                        verify:@"123456"
                                                  streamAESKey:nil];
     

+ 1 - 1
创维盒子/双子星云手机/CloudPlayer/View/PlayerView.m

@@ -66,7 +66,7 @@ ShowImageViewDelegate>{
                   inRect:CGRectMake(0, 0, glkshowImageView.drawableWidth, glkshowImageView.drawableHeight)
                 fromRect:[ciImage extent]];
     
-    [self->glkshowImageView display];
+    //[self->glkshowImageView display];
 }
 
 - (void)showIMage

+ 64 - 0
创维盒子/双子星云手机/Vendor/pingTool/Reachability.h

@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ See LICENSE.txt for this sample’s licensing information
+ 
+ Abstract:
+ Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
+ */
+
+#import <Foundation/Foundation.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+#import <netinet/in.h>
+
+
+typedef enum : NSInteger {
+	NotReachable = 0,
+	ReachableViaWiFi,
+	ReachableViaWWAN
+} NetworkStatus;
+
+#pragma mark IPv6 Support
+//Reachability fully support IPv6.  For full details, see ReadMe.md.
+
+
+extern NSString *kReachabilityChangedNotification;
+
+
+@interface Reachability : NSObject
+
+/*!
+ * Use to check the reachability of a given host name.
+ */
++ (instancetype)reachabilityWithHostName:(NSString *)hostName;
+
+/*!
+ * Use to check the reachability of a given IP address.
+ */
++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress;
+
+/*!
+ * Checks whether the default route is available. Should be used by applications that do not connect to a particular host.
+ */
++ (instancetype)reachabilityForInternetConnection;
+
+
+#pragma mark reachabilityForLocalWiFi
+//reachabilityForLocalWiFi has been removed from the sample.  See ReadMe.md for more information.
+//+ (instancetype)reachabilityForLocalWiFi;
+
+/*!
+ * Start listening for reachability notifications on the current run loop.
+ */
+- (BOOL)startNotifier;
+- (void)stopNotifier;
+
+- (NetworkStatus)currentReachabilityStatus;
+
+/*!
+ * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand.
+ */
+- (BOOL)connectionRequired;
+
+@end
+
+

+ 242 - 0
创维盒子/双子星云手机/Vendor/pingTool/Reachability.m

@@ -0,0 +1,242 @@
+/*
+ Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ See LICENSE.txt for this sample’s licensing information
+ 
+ Abstract:
+ Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
+ */
+
+#import <arpa/inet.h>
+#import <ifaddrs.h>
+#import <netdb.h>
+#import <sys/socket.h>
+#import <netinet/in.h>
+
+#import <CoreFoundation/CoreFoundation.h>
+
+#import "Reachability.h"
+
+#pragma mark IPv6 Support
+//Reachability fully support IPv6.  For full details, see ReadMe.md.
+
+
+NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";
+
+
+#pragma mark - Supporting functions
+
+#define kShouldPrintReachabilityFlags 1
+
+static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
+{
+#if kShouldPrintReachabilityFlags
+
+    HLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
+          (flags & kSCNetworkReachabilityFlagsIsWWAN)				? 'W' : '-',
+          (flags & kSCNetworkReachabilityFlagsReachable)            ? 'R' : '-',
+
+          (flags & kSCNetworkReachabilityFlagsTransientConnection)  ? 't' : '-',
+          (flags & kSCNetworkReachabilityFlagsConnectionRequired)   ? 'c' : '-',
+          (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)  ? 'C' : '-',
+          (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
+          (flags & kSCNetworkReachabilityFlagsConnectionOnDemand)   ? 'D' : '-',
+          (flags & kSCNetworkReachabilityFlagsIsLocalAddress)       ? 'l' : '-',
+          (flags & kSCNetworkReachabilityFlagsIsDirect)             ? 'd' : '-',
+          comment
+          );
+#endif
+}
+
+
+static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
+{
+#pragma unused (target, flags)
+	NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
+	NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
+
+    Reachability* noteObject = (__bridge Reachability *)info;
+    // Post a notification to notify the client that the network reachability changed.
+    [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
+}
+
+
+#pragma mark - Reachability implementation
+
+@implementation Reachability
+{
+	SCNetworkReachabilityRef _reachabilityRef;
+}
+
++ (instancetype)reachabilityWithHostName:(NSString *)hostName
+{
+	Reachability* returnValue = NULL;
+	SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
+	if (reachability != NULL)
+	{
+		returnValue= [[self alloc] init];
+		if (returnValue != NULL)
+		{
+			returnValue->_reachabilityRef = reachability;
+		}
+        else {
+            CFRelease(reachability);
+        }
+	}
+	return returnValue;
+}
+
+
++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress
+{
+	SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
+
+	Reachability* returnValue = NULL;
+
+	if (reachability != NULL)
+	{
+		returnValue = [[self alloc] init];
+		if (returnValue != NULL)
+		{
+			returnValue->_reachabilityRef = reachability;
+		}
+        else {
+            CFRelease(reachability);
+        }
+	}
+	return returnValue;
+}
+
+
++ (instancetype)reachabilityForInternetConnection
+{
+	struct sockaddr_in zeroAddress;
+	bzero(&zeroAddress, sizeof(zeroAddress));
+	zeroAddress.sin_len = sizeof(zeroAddress);
+	zeroAddress.sin_family = AF_INET;
+    
+    return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
+}
+
+#pragma mark reachabilityForLocalWiFi
+//reachabilityForLocalWiFi has been removed from the sample.  See ReadMe.md for more information.
+//+ (instancetype)reachabilityForLocalWiFi
+
+
+
+#pragma mark - Start and stop notifier
+
+- (BOOL)startNotifier
+{
+	BOOL returnValue = NO;
+	SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
+
+	if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
+	{
+		if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
+		{
+			returnValue = YES;
+		}
+	}
+    
+	return returnValue;
+}
+
+
+- (void)stopNotifier
+{
+	if (_reachabilityRef != NULL)
+	{
+		SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+	}
+}
+
+
+- (void)dealloc
+{
+	[self stopNotifier];
+	if (_reachabilityRef != NULL)
+	{
+		CFRelease(_reachabilityRef);
+	}
+}
+
+
+#pragma mark - Network Flag Handling
+
+- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
+{
+	PrintReachabilityFlags(flags, "networkStatusForFlags");
+	if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
+	{
+		// The target host is not reachable.
+		return NotReachable;
+	}
+
+    NetworkStatus returnValue = NotReachable;
+
+	if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
+	{
+		/*
+         If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
+         */
+		returnValue = ReachableViaWiFi;
+	}
+
+	if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
+        (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
+	{
+        /*
+         ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
+         */
+
+        if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
+        {
+            /*
+             ... and no [user] intervention is needed...
+             */
+            returnValue = ReachableViaWiFi;
+        }
+    }
+
+	if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
+	{
+		/*
+         ... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
+         */
+		returnValue = ReachableViaWWAN;
+	}
+    
+	return returnValue;
+}
+
+
+- (BOOL)connectionRequired
+{
+	NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
+	SCNetworkReachabilityFlags flags;
+
+	if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
+	{
+		return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
+	}
+
+    return NO;
+}
+
+
+- (NetworkStatus)currentReachabilityStatus
+{
+	NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
+	NetworkStatus returnValue = NotReachable;
+	SCNetworkReachabilityFlags flags;
+    
+	if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
+	{
+        returnValue = [self networkStatusForFlags:flags];
+	}
+    
+	return returnValue;
+}
+
+
+@end

+ 278 - 0
创维盒子/双子星云手机/Vendor/pingTool/SimplePing.h

@@ -0,0 +1,278 @@
+/*
+ Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ See LICENSE.txt for this sample’s licensing information
+ 
+ Abstract:
+ An object wrapper around the low-level BSD Sockets ping function.
+ */
+
+#import <Foundation/Foundation.h>
+
+#include <AssertMacros.h>           // for __Check_Compile_Time
+
+#ifndef _SA_FAMILY_T
+#define _SA_FAMILY_T
+#include <machine/types.h> /* __uint8_t */
+typedef __uint8_t               sa_family_t;
+#endif  /* _SA_FAMILY_T */
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol SimplePingDelegate;
+
+/*! Controls the IP address version used by SimplePing instances.
+ */
+
+typedef NS_ENUM(NSInteger, SimplePingAddressStyle) {
+    SimplePingAddressStyleAny,          ///< Use the first IPv4 or IPv6 address found; the default.
+    SimplePingAddressStyleICMPv4,       ///< Use the first IPv4 address found.
+    SimplePingAddressStyleICMPv6        ///< Use the first IPv6 address found.
+};
+
+/*! An object wrapper around the low-level BSD Sockets ping function.
+ *  \details To use the class create an instance, set the delegate and call `-start`
+ *      to start the instance on the current run loop.  If things go well you'll soon get the
+ *      `-simplePing:didStartWithAddress:` delegate callback.  From there you can can call
+ *      `-sendPingWithData:` to send a ping and you'll receive the
+ *      `-simplePing:didReceivePingResponsePacket:sequenceNumber:` and
+ *      `-simplePing:didReceiveUnexpectedPacket:` delegate callbacks as ICMP packets arrive.
+ *
+ *      The class can be used from any thread but the use of any single instance must be
+ *      confined to a specific thread and that thread must run its run loop.
+ */
+
+@interface SimplePing : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/*! Initialise the object to ping the specified host.
+ *  \param hostName The DNS name of the host to ping; an IPv4 or IPv6 address in string form will
+ *      work here.
+ *  \returns The initialised object.
+ */
+
+- (instancetype)initWithHostName:(NSString *)hostName NS_DESIGNATED_INITIALIZER;
+
+/*! A copy of the value passed to `-initWithHostName:`.
+ */
+
+@property (nonatomic, copy, readonly) NSString * hostName;
+
+/*! The delegate for this object.
+ *  \details Delegate callbacks are schedule in the default run loop mode of the run loop of the
+ *      thread that calls `-start`.
+ */
+
+@property (nonatomic, weak, readwrite, nullable) id<SimplePingDelegate> delegate;
+
+/*! Controls the IP address version used by the object.
+ *  \details You should set this value before starting the object.
+ */
+
+@property (nonatomic, assign, readwrite) SimplePingAddressStyle addressStyle;
+
+/*! The address being pinged.
+ *  \details The contents of the NSData is a (struct sockaddr) of some form.  The
+ *      value is nil while the object is stopped and remains nil on start until
+ *      `-simplePing:didStartWithAddress:` is called.
+ */
+
+@property (nonatomic, copy, readonly, nullable) NSData * hostAddress;
+
+/*! The address family for `hostAddress`, or `AF_UNSPEC` if that's nil.
+ */
+
+@property (nonatomic, assign, readonly) sa_family_t hostAddressFamily;
+
+/*! The identifier used by pings by this object.
+ *  \details When you create an instance of this object it generates a random identifier
+ *      that it uses to identify its own pings.
+ */
+
+@property (nonatomic, assign, readonly) uint16_t identifier;
+
+/*! The next sequence number to be used by this object.
+ *  \details This value starts at zero and increments each time you send a ping (safely
+ *      wrapping back to zero if necessary).  The sequence number is included in the ping,
+ *      allowing you to match up requests and responses, and thus calculate ping times and
+ *      so on.
+ */
+
+@property (nonatomic, assign, readonly) uint16_t nextSequenceNumber;
+
+/*! Starts the object.
+ *  \details You should set up the delegate and any ping parameters before calling this.
+ *
+ *      If things go well you'll soon get the `-simplePing:didStartWithAddress:` delegate
+ *      callback, at which point you can start sending pings (via `-sendPingWithData:`) and
+ *      will start receiving ICMP packets (either ping responses, via the
+ *      `-simplePing:didReceivePingResponsePacket:sequenceNumber:` delegate callback, or
+ *      unsolicited ICMP packets, via the `-simplePing:didReceiveUnexpectedPacket:` delegate
+ *      callback).
+ *
+ *      If the object fails to start, typically because `hostName` doesn't resolve, you'll get
+ *      the `-simplePing:didFailWithError:` delegate callback.
+ *
+ *      It is not correct to start an already started object.
+ */
+
+- (void)start;
+
+/*! Sends a ping packet containing the specified data.
+ *  \details Sends an actual ping.
+ *
+ *      The object must be started when you call this method and, on starting the object, you must
+ *      wait for the `-simplePing:didStartWithAddress:` delegate callback before calling it.
+ *  \param data Some data to include in the ping packet, after the ICMP header, or nil if you
+ *      want the packet to include a standard 56 byte payload (resulting in a standard 64 byte
+ *      ping).
+ */
+
+- (void)sendPingWithData:(nullable NSData *)data;
+
+/*! Stops the object.
+ *  \details You should call this when you're done pinging.
+ *
+ *      It's safe to call this on an object that's stopped.
+ */
+
+- (void)stop;
+
+@end
+
+/*! A delegate protocol for the SimplePing class.
+ */
+
+@protocol SimplePingDelegate <NSObject>
+
+@optional
+
+/*! A SimplePing delegate callback, called once the object has started up.
+ *  \details This is called shortly after you start the object to tell you that the
+ *      object has successfully started.  On receiving this callback, you can call
+ *      `-sendPingWithData:` to send pings.
+ *
+ *      If the object didn't start, `-simplePing:didFailWithError:` is called instead.
+ *  \param pinger The object issuing the callback.
+ *  \param address The address that's being pinged; at the time this delegate callback
+ *      is made, this will have the same value as the `hostAddress` property.
+ */
+
+- (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address;
+
+/*! A SimplePing delegate callback, called if the object fails to start up.
+ *  \details This is called shortly after you start the object to tell you that the
+ *      object has failed to start.  The most likely cause of failure is a problem
+ *      resolving `hostName`.
+ *
+ *      By the time this callback is called, the object has stopped (that is, you don't
+ *      need to call `-stop` yourself).
+ *  \param pinger The object issuing the callback.
+ *  \param error Describes the failure.
+ */
+
+- (void)simplePing:(SimplePing *)pinger didFailWithError:(NSError *)error;
+
+/*! A SimplePing delegate callback, called when the object has successfully sent a ping packet.
+ *  \details Each call to `-sendPingWithData:` will result in either a
+ *      `-simplePing:didSendPacket:sequenceNumber:` delegate callback or a
+ *      `-simplePing:didFailToSendPacket:sequenceNumber:error:` delegate callback (unless you
+ *      stop the object before you get the callback).  These callbacks are currently delivered
+ *      synchronously from within `-sendPingWithData:`, but this synchronous behaviour is not
+ *      considered API.
+ *  \param pinger The object issuing the callback.
+ *  \param packet The packet that was sent; this includes the ICMP header (`ICMPHeader`) and the
+ *      data you passed to `-sendPingWithData:` but does not include any IP-level headers.
+ *  \param sequenceNumber The ICMP sequence number of that packet.
+ */
+
+- (void)simplePing:(SimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber;
+
+/*! A SimplePing delegate callback, called when the object fails to send a ping packet.
+ *  \details Each call to `-sendPingWithData:` will result in either a
+ *      `-simplePing:didSendPacket:sequenceNumber:` delegate callback or a
+ *      `-simplePing:didFailToSendPacket:sequenceNumber:error:` delegate callback (unless you
+ *      stop the object before you get the callback).  These callbacks are currently delivered
+ *      synchronously from within `-sendPingWithData:`, but this synchronous behaviour is not
+ *      considered API.
+ *  \param pinger The object issuing the callback.
+ *  \param packet The packet that was not sent; see `-simplePing:didSendPacket:sequenceNumber:`
+ *      for details.
+ *  \param sequenceNumber The ICMP sequence number of that packet.
+ *  \param error Describes the failure.
+ */
+
+- (void)simplePing:(SimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error;
+
+/*! A SimplePing delegate callback, called when the object receives a ping response.
+ *  \details If the object receives an ping response that matches a ping request that it
+ *      sent, it informs the delegate via this callback.  Matching is primarily done based on
+ *      the ICMP identifier, although other criteria are used as well.
+ *  \param pinger The object issuing the callback.
+ *  \param packet The packet received; this includes the ICMP header (`ICMPHeader`) and any data that
+ *      follows that in the ICMP message but does not include any IP-level headers.
+ *  \param sequenceNumber The ICMP sequence number of that packet.
+ */
+
+- (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber;
+
+/*! A SimplePing delegate callback, called when the object receives an unmatched ICMP message.
+ *  \details If the object receives an ICMP message that does not match a ping request that it
+ *      sent, it informs the delegate via this callback.  The nature of ICMP handling in a
+ *      BSD kernel makes this a common event because, when an ICMP message arrives, it is
+ *      delivered to all ICMP sockets.
+ *
+ *      IMPORTANT: This callback is especially common when using IPv6 because IPv6 uses ICMP
+ *      for important network management functions.  For example, IPv6 routers periodically
+ *      send out Router Advertisement (RA) packets via Neighbor Discovery Protocol (NDP), which
+ *      is implemented on top of ICMP.
+ *
+ *      For more on matching, see the discussion associated with
+ *      `-simplePing:didReceivePingResponsePacket:sequenceNumber:`.
+ *  \param pinger The object issuing the callback.
+ *  \param packet The packet received; this includes the ICMP header (`ICMPHeader`) and any data that
+ *      follows that in the ICMP message but does not include any IP-level headers.
+ */
+
+- (void)simplePing:(SimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet;
+
+@end
+
+#pragma mark * ICMP On-The-Wire Format
+
+/*! Describes the on-the-wire header format for an ICMP ping.
+ *  \details This defines the header structure of ping packets on the wire.  Both IPv4 and
+ *      IPv6 use the same basic structure.
+ *
+ *      This is declared in the header because clients of SimplePing might want to use
+ *      it parse received ping packets.
+ */
+
+struct ICMPHeader {
+    uint8_t     type;
+    uint8_t     code;
+    uint16_t    checksum;
+    uint16_t    identifier;
+    uint16_t    sequenceNumber;
+    // data...
+};
+typedef struct ICMPHeader ICMPHeader;
+
+__Check_Compile_Time(sizeof(ICMPHeader) == 8);
+__Check_Compile_Time(offsetof(ICMPHeader, type) == 0);
+__Check_Compile_Time(offsetof(ICMPHeader, code) == 1);
+__Check_Compile_Time(offsetof(ICMPHeader, checksum) == 2);
+__Check_Compile_Time(offsetof(ICMPHeader, identifier) == 4);
+__Check_Compile_Time(offsetof(ICMPHeader, sequenceNumber) == 6);
+
+enum {
+    ICMPv4TypeEchoRequest = 8,          ///< The ICMP `type` for a ping request; in this case `code` is always 0.
+    ICMPv4TypeEchoReply   = 0           ///< The ICMP `type` for a ping response; in this case `code` is always 0.
+};
+
+enum {
+    ICMPv6TypeEchoRequest = 128,        ///< The ICMP `type` for a ping request; in this case `code` is always 0.
+    ICMPv6TypeEchoReply   = 129         ///< The ICMP `type` for a ping response; in this case `code` is always 0.
+};
+
+NS_ASSUME_NONNULL_END

+ 782 - 0
创维盒子/双子星云手机/Vendor/pingTool/SimplePing.m

@@ -0,0 +1,782 @@
+/*
+ Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ See LICENSE.txt for this sample’s licensing information
+ 
+ Abstract:
+ An object wrapper around the low-level BSD Sockets ping function.
+ */
+
+#import "SimplePing.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#pragma mark * IPv4 and ICMPv4 On-The-Wire Format
+
+/*! Describes the on-the-wire header format for an IPv4 packet.
+ *  \details This defines the header structure of IPv4 packets on the wire.  We need
+ *      this in order to skip this header in the IPv4 case, where the kernel passes
+ *      it to us for no obvious reason.
+ */
+
+struct IPv4Header {
+    uint8_t     versionAndHeaderLength;
+    uint8_t     differentiatedServices;
+    uint16_t    totalLength;
+    uint16_t    identification;
+    uint16_t    flagsAndFragmentOffset;
+    uint8_t     timeToLive;
+    uint8_t     protocol;
+    uint16_t    headerChecksum;
+    uint8_t     sourceAddress[4];
+    uint8_t     destinationAddress[4];
+    // options...
+    // data...
+};
+typedef struct IPv4Header IPv4Header;
+
+__Check_Compile_Time(sizeof(IPv4Header) == 20);
+__Check_Compile_Time(offsetof(IPv4Header, versionAndHeaderLength) == 0);
+__Check_Compile_Time(offsetof(IPv4Header, differentiatedServices) == 1);
+__Check_Compile_Time(offsetof(IPv4Header, totalLength) == 2);
+__Check_Compile_Time(offsetof(IPv4Header, identification) == 4);
+__Check_Compile_Time(offsetof(IPv4Header, flagsAndFragmentOffset) == 6);
+__Check_Compile_Time(offsetof(IPv4Header, timeToLive) == 8);
+__Check_Compile_Time(offsetof(IPv4Header, protocol) == 9);
+__Check_Compile_Time(offsetof(IPv4Header, headerChecksum) == 10);
+__Check_Compile_Time(offsetof(IPv4Header, sourceAddress) == 12);
+__Check_Compile_Time(offsetof(IPv4Header, destinationAddress) == 16);
+
+/*! Calculates an IP checksum.
+ *  \details This is the standard BSD checksum code, modified to use modern types.
+ *  \param buffer A pointer to the data to checksum.
+ *  \param bufferLen The length of that data.
+ *  \returns The checksum value, in network byte order.
+ */
+
+static uint16_t in_cksum(const void *buffer, size_t bufferLen) {
+    //
+    size_t              bytesLeft;
+    int32_t             sum;
+    const uint16_t *    cursor;
+    union {
+        uint16_t        us;
+        uint8_t         uc[2];
+    } last;
+    uint16_t            answer;
+    
+    bytesLeft = bufferLen;
+    sum = 0;
+    cursor = buffer;
+    
+    /*
+     * Our algorithm is simple, using a 32 bit accumulator (sum), we add
+     * sequential 16 bit words to it, and at the end, fold back all the
+     * carry bits from the top 16 bits into the lower 16 bits.
+     */
+    while (bytesLeft > 1) {
+        sum += *cursor;
+        cursor += 1;
+        bytesLeft -= 2;
+    }
+    
+    /* mop up an odd byte, if necessary */
+    if (bytesLeft == 1) {
+        last.uc[0] = * (const uint8_t *) cursor;
+        last.uc[1] = 0;
+        sum += last.us;
+    }
+    
+    /* add back carry outs from top 16 bits to low 16 bits */
+    sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
+    sum += (sum >> 16);			/* add carry */
+    answer = (uint16_t) ~sum;   /* truncate to 16 bits */
+    
+    return answer;
+}
+
+#pragma mark * SimplePing
+
+@interface SimplePing ()
+
+// read/write versions of public properties
+
+@property (nonatomic, copy,   readwrite, nullable) NSData *     hostAddress;
+@property (nonatomic, assign, readwrite          ) uint16_t     nextSequenceNumber;
+
+// private properties
+
+/*! True if nextSequenceNumber has wrapped from 65535 to 0.
+ */
+
+@property (nonatomic, assign, readwrite)           BOOL         nextSequenceNumberHasWrapped;
+
+/*! A host object for name-to-address resolution.
+ */
+
+@property (nonatomic, strong, readwrite, nullable) CFHostRef host __attribute__ ((NSObject));
+
+/*! A socket object for ICMP send and receive.
+ */
+
+@property (nonatomic, strong, readwrite, nullable) CFSocketRef socket __attribute__ ((NSObject));
+
+@end
+
+@implementation SimplePing
+
+- (instancetype)initWithHostName:(NSString *)hostName {
+    NSParameterAssert(hostName != nil);
+    self = [super init];
+    if (self != nil) {
+        self->_hostName   = [hostName copy];
+        self->_identifier = (uint16_t) arc4random();
+    }
+    return self;
+}
+
+- (void)dealloc {
+    [self stop];
+    // Double check that -stop took care of _host and _socket.
+    assert(self->_host == NULL);
+    assert(self->_socket == NULL);
+}
+
+- (sa_family_t)hostAddressFamily {
+    sa_family_t     result;
+    
+    result = AF_UNSPEC;
+    if ( (self.hostAddress != nil) && (self.hostAddress.length >= sizeof(struct sockaddr)) ) {
+        result = ((const struct sockaddr *) self.hostAddress.bytes)->sa_family;
+    }
+    return result;
+}
+
+/*! Shuts down the pinger object and tell the delegate about the error.
+ *  \param error Describes the failure.
+ */
+
+- (void)didFailWithError:(NSError *)error {
+    id<SimplePingDelegate>  strongDelegate;
+    
+    assert(error != nil);
+    
+    // We retain ourselves temporarily because it's common for the delegate method
+    // to release its last reference to us, which causes -dealloc to be called here.
+    // If we then reference self on the return path, things go badly.  I don't think
+    // that happens currently, but I've got into the habit of doing this as a
+    // defensive measure.
+    
+    CFAutorelease( CFBridgingRetain( self ));
+    
+    [self stop];
+    strongDelegate = self.delegate;
+    if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didFailWithError:)] ) {
+        [strongDelegate simplePing:self didFailWithError:error];
+    }
+}
+
+/*! Shuts down the pinger object and tell the delegate about the error.
+ *  \details This converts the CFStreamError to an NSError and then call through to
+ *      -didFailWithError: to do the real work.
+ *  \param streamError Describes the failure.
+ */
+
+- (void)didFailWithHostStreamError:(CFStreamError)streamError {
+    NSDictionary *  userInfo;
+    NSError *       error;
+    
+    if (streamError.domain == kCFStreamErrorDomainNetDB) {
+        userInfo = @{(id) kCFGetAddrInfoFailureKey: @(streamError.error)};
+    } else {
+        userInfo = nil;
+    }
+    error = [NSError errorWithDomain:(NSString *) kCFErrorDomainCFNetwork code:kCFHostErrorUnknown userInfo:userInfo];
+    
+    [self didFailWithError:error];
+}
+
+/*! Builds a ping packet from the supplied parameters.
+ *  \param type The packet type, which is different for IPv4 and IPv6.
+ *  \param payload Data to place after the ICMP header.
+ *  \param requiresChecksum Determines whether a checksum is calculated (IPv4) or not (IPv6).
+ *  \returns A ping packet suitable to be passed to the kernel.
+ */
+
+- (NSData *)pingPacketWithType:(uint8_t)type payload:(NSData *)payload requiresChecksum:(BOOL)requiresChecksum {
+    NSMutableData *         packet;
+    ICMPHeader *            icmpPtr;
+    
+    packet = [NSMutableData dataWithLength:sizeof(*icmpPtr) + payload.length];
+    assert(packet != nil);
+    
+    icmpPtr = packet.mutableBytes;
+    icmpPtr->type = type;
+    icmpPtr->code = 0;
+    icmpPtr->checksum = 0;
+    icmpPtr->identifier     = OSSwapHostToBigInt16(self.identifier);
+    icmpPtr->sequenceNumber = OSSwapHostToBigInt16(self.nextSequenceNumber);
+    memcpy(&icmpPtr[1], [payload bytes], [payload length]);
+    
+    if (requiresChecksum) {
+        // The IP checksum routine returns a 16-bit number that's already in correct byte order
+        // (due to wacky 1's complement maths), so we just put it into the packet as a 16-bit unit.
+        
+        icmpPtr->checksum = in_cksum(packet.bytes, packet.length);
+    }
+    
+    return packet;
+}
+
+- (void)sendPingWithData:(NSData *)data {
+    int                     err;
+    NSData *                payload;
+    NSData *                packet;
+    ssize_t                 bytesSent;
+    id<SimplePingDelegate>  strongDelegate;
+    
+    // data may be nil
+    NSParameterAssert(self.hostAddress != nil);     // gotta wait for -simplePing:didStartWithAddress:
+    
+    // Construct the ping packet.
+    
+    payload = data;
+    if (payload == nil) {
+        payload = [[NSString stringWithFormat:@"%28zd bottles of beer on the wall", (ssize_t) 99 - (size_t) (self.nextSequenceNumber % 100) ] dataUsingEncoding:NSASCIIStringEncoding];
+        assert(payload != nil);
+        
+        // Our dummy payload is sized so that the resulting ICMP packet, including the ICMPHeader, is
+        // 64-bytes, which makes it easier to recognise our packets on the wire.
+        
+        assert([payload length] == 56);
+    }
+    
+    switch (self.hostAddressFamily) {
+        case AF_INET: {
+            packet = [self pingPacketWithType:ICMPv4TypeEchoRequest payload:payload requiresChecksum:YES];
+        } break;
+        case AF_INET6: {
+            packet = [self pingPacketWithType:ICMPv6TypeEchoRequest payload:payload requiresChecksum:NO];
+        } break;
+        default: {
+            assert(NO);
+        } break;
+    }
+    assert(packet != nil);
+    
+    // Send the packet.
+    
+    if (self.socket == NULL) {
+        bytesSent = -1;
+        err = EBADF;
+    } else {
+        bytesSent = sendto(
+                           CFSocketGetNative(self.socket),
+                           packet.bytes,
+                           packet.length,
+                           0,
+                           self.hostAddress.bytes,
+                           (socklen_t) self.hostAddress.length
+                           );
+        err = 0;
+        if (bytesSent < 0) {
+            err = errno;
+        }
+    }
+    
+    // Handle the results of the send.
+    
+    strongDelegate = self.delegate;
+    if ( (bytesSent > 0) && (((NSUInteger) bytesSent) == packet.length) ) {
+        
+        // Complete success.  Tell the client.
+        
+        if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didSendPacket:sequenceNumber:)] ) {
+            [strongDelegate simplePing:self didSendPacket:packet sequenceNumber:self.nextSequenceNumber];
+        }
+    } else {
+        NSError *   error;
+        
+        // Some sort of failure.  Tell the client.
+        
+        if (err == 0) {
+            err = ENOBUFS;          // This is not a hugely descriptor error, alas.
+        }
+        error = [NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil];
+        if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didFailToSendPacket:sequenceNumber:error:)] ) {
+            [strongDelegate simplePing:self didFailToSendPacket:packet sequenceNumber:self.nextSequenceNumber error:error];
+        }
+    }
+    
+    self.nextSequenceNumber += 1;
+    if (self.nextSequenceNumber == 0) {
+        self.nextSequenceNumberHasWrapped = YES;
+    }
+}
+
+/*! Calculates the offset of the ICMP header within an IPv4 packet.
+ *  \details In the IPv4 case the kernel returns us a buffer that includes the
+ *      IPv4 header.  We're not interested in that, so we have to skip over it.
+ *      This code does a rough check of the IPv4 header and, if it looks OK,
+ *      returns the offset of the ICMP header.
+ *  \param packet The IPv4 packet, as returned to us by the kernel.
+ *  \returns The offset of the ICMP header, or NSNotFound.
+ */
+
++ (NSUInteger)icmpHeaderOffsetInIPv4Packet:(NSData *)packet {
+    // Returns the offset of the ICMPv4Header within an IP packet.
+    NSUInteger                  result;
+    const struct IPv4Header *   ipPtr;
+    size_t                      ipHeaderLength;
+    
+    result = NSNotFound;
+    if (packet.length >= (sizeof(IPv4Header) + sizeof(ICMPHeader))) {
+        ipPtr = (const IPv4Header *) packet.bytes;
+        if ( ((ipPtr->versionAndHeaderLength & 0xF0) == 0x40) &&            // IPv4
+            ( ipPtr->protocol == IPPROTO_ICMP ) ) {
+            ipHeaderLength = (ipPtr->versionAndHeaderLength & 0x0F) * sizeof(uint32_t);
+            if (packet.length >= (ipHeaderLength + sizeof(ICMPHeader))) {
+                result = ipHeaderLength;
+            }
+        }
+    }
+    return result;
+}
+
+/*! Checks whether the specified sequence number is one we sent.
+ *  \param sequenceNumber The incoming sequence number.
+ *  \returns YES if the sequence number looks like one we sent.
+ */
+
+- (BOOL)validateSequenceNumber:(uint16_t)sequenceNumber {
+    if (self.nextSequenceNumberHasWrapped) {
+        // If the sequence numbers have wrapped that we can't reliably check
+        // whether this is a sequence number we sent.  Rather, we check to see
+        // whether the sequence number is within the last 120 sequence numbers
+        // we sent.  Note that the uint16_t subtraction here does the right
+        // thing regardless of the wrapping.
+        //
+        // Why 120?  Well, if we send one ping per second, 120 is 2 minutes, which
+        // is the standard "max time a packet can bounce around the Internet" value.
+        return ((uint16_t) (self.nextSequenceNumber - sequenceNumber)) < (uint16_t) 120;
+    } else {
+        return sequenceNumber < self.nextSequenceNumber;
+    }
+}
+
+/*! Checks whether an incoming IPv4 packet looks like a ping response.
+ *  \details This routine modifies this `packet` data!  It does this for two reasons:
+ *
+ *      * It needs to zero out the `checksum` field of the ICMPHeader in order to do
+ *          its checksum calculation.
+ *
+ *      * It removes the IPv4 header from the front of the packet.
+ *  \param packet The IPv4 packet, as returned to us by the kernel.
+ *  \param sequenceNumberPtr A pointer to a place to start the ICMP sequence number.
+ *  \returns YES if the packet looks like a reasonable IPv4 ping response.
+ */
+
+- (BOOL)validatePing4ResponsePacket:(NSMutableData *)packet sequenceNumber:(uint16_t *)sequenceNumberPtr {
+    BOOL                result;
+    NSUInteger          icmpHeaderOffset;
+    ICMPHeader *        icmpPtr;
+    uint16_t            receivedChecksum;
+    uint16_t            calculatedChecksum;
+    
+    result = NO;
+    
+    icmpHeaderOffset = [[self class] icmpHeaderOffsetInIPv4Packet:packet];
+    if (icmpHeaderOffset != NSNotFound) {
+        icmpPtr = (struct ICMPHeader *) (((uint8_t *) packet.mutableBytes) + icmpHeaderOffset);
+        
+        receivedChecksum   = icmpPtr->checksum;
+        icmpPtr->checksum  = 0;
+        calculatedChecksum = in_cksum(icmpPtr, packet.length - icmpHeaderOffset);
+        icmpPtr->checksum  = receivedChecksum;
+        
+        if (receivedChecksum == calculatedChecksum) {
+            if ( (icmpPtr->type == ICMPv4TypeEchoReply) && (icmpPtr->code == 0) ) {
+                if ( OSSwapBigToHostInt16(icmpPtr->identifier) == self.identifier ) {
+                    uint16_t    sequenceNumber;
+                    
+                    sequenceNumber = OSSwapBigToHostInt16(icmpPtr->sequenceNumber);
+                    if ([self validateSequenceNumber:sequenceNumber]) {
+                        
+                        // Remove the IPv4 header off the front of the data we received, leaving us with
+                        // just the ICMP header and the ping payload.
+                        [packet replaceBytesInRange:NSMakeRange(0, icmpHeaderOffset) withBytes:NULL length:0];
+                        
+                        *sequenceNumberPtr = sequenceNumber;
+                        result = YES;
+                    }
+                }
+            }
+        }
+    }
+    
+    return result;
+}
+
+/*! Checks whether an incoming IPv6 packet looks like a ping response.
+ *  \param packet The IPv6 packet, as returned to us by the kernel; note that this routine
+ *      could modify this data but does not need to in the IPv6 case.
+ *  \param sequenceNumberPtr A pointer to a place to start the ICMP sequence number.
+ *  \returns YES if the packet looks like a reasonable IPv4 ping response.
+ */
+
+- (BOOL)validatePing6ResponsePacket:(NSMutableData *)packet sequenceNumber:(uint16_t *)sequenceNumberPtr {
+    BOOL                    result;
+    const ICMPHeader *      icmpPtr;
+    
+    result = NO;
+    
+    if (packet.length >= sizeof(*icmpPtr)) {
+        icmpPtr = packet.bytes;
+        
+        // In the IPv6 case we don't check the checksum because that's hard (we need to
+        // cook up an IPv6 pseudo header and we don't have the ingredients) and unnecessary
+        // (the kernel has already done this check).
+        
+        if ( (icmpPtr->type == ICMPv6TypeEchoReply) && (icmpPtr->code == 0) ) {
+            if ( OSSwapBigToHostInt16(icmpPtr->identifier) == self.identifier ) {
+                uint16_t    sequenceNumber;
+                
+                sequenceNumber = OSSwapBigToHostInt16(icmpPtr->sequenceNumber);
+                if ([self validateSequenceNumber:sequenceNumber]) {
+                    *sequenceNumberPtr = sequenceNumber;
+                    result = YES;
+                }
+            }
+        }
+    }
+    return result;
+}
+
+/*! Checks whether an incoming packet looks like a ping response.
+ *  \param packet The packet, as returned to us by the kernel; note that may end up modifying
+ *      this data.
+ *  \param sequenceNumberPtr A pointer to a place to start the ICMP sequence number.
+ *  \returns YES if the packet looks like a reasonable IPv4 ping response.
+ */
+
+- (BOOL)validatePingResponsePacket:(NSMutableData *)packet sequenceNumber:(uint16_t *)sequenceNumberPtr {
+    BOOL        result;
+    
+    switch (self.hostAddressFamily) {
+        case AF_INET: {
+            result = [self validatePing4ResponsePacket:packet sequenceNumber:sequenceNumberPtr];
+        } break;
+        case AF_INET6: {
+            result = [self validatePing6ResponsePacket:packet sequenceNumber:sequenceNumberPtr];
+        } break;
+        default: {
+            assert(NO);
+            result = NO;
+        } break;
+    }
+    return result;
+}
+
+/*! Reads data from the ICMP socket.
+ *  \details Called by the socket handling code (SocketReadCallback) to process an ICMP
+ *      message waiting on the socket.
+ */
+
+- (void)readData {
+    int                     err;
+    struct sockaddr_storage addr;
+    socklen_t               addrLen;
+    ssize_t                 bytesRead;
+    void *                  buffer;
+    enum { kBufferSize = 65535 };
+    
+    // 65535 is the maximum IP packet size, which seems like a reasonable bound
+    // here (plus it's what <x-man-page://8/ping> uses).
+    
+    buffer = malloc(kBufferSize);
+    assert(buffer != NULL);
+    
+    // Actually read the data.  We use recvfrom(), and thus get back the source address,
+    // but we don't actually do anything with it.  It would be trivial to pass it to
+    // the delegate but we don't need it in this example.
+    
+    addrLen = sizeof(addr);
+    bytesRead = recvfrom(CFSocketGetNative(self.socket), buffer, kBufferSize, 0, (struct sockaddr *) &addr, &addrLen);
+    err = 0;
+    if (bytesRead < 0) {
+        err = errno;
+    }
+    
+    // Process the data we read.
+    
+    if (bytesRead > 0) {
+        NSMutableData *         packet;
+        id<SimplePingDelegate>  strongDelegate;
+        uint16_t                sequenceNumber;
+        
+        packet = [NSMutableData dataWithBytes:buffer length:(NSUInteger) bytesRead];
+        assert(packet != nil);
+        
+        // We got some data, pass it up to our client.
+        
+        strongDelegate = self.delegate;
+        if ( [self validatePingResponsePacket:packet sequenceNumber:&sequenceNumber] ) {
+            if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didReceivePingResponsePacket:sequenceNumber:)] ) {
+                [strongDelegate simplePing:self didReceivePingResponsePacket:packet sequenceNumber:sequenceNumber];
+            }
+        } else {
+            if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didReceiveUnexpectedPacket:)] ) {
+                [strongDelegate simplePing:self didReceiveUnexpectedPacket:packet];
+            }
+        }
+    } else {
+        
+        // We failed to read the data, so shut everything down.
+        
+        if (err == 0) {
+            err = EPIPE;
+        }
+        [self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]];
+    }
+    
+    free(buffer);
+    
+    // Note that we don't loop back trying to read more data.  Rather, we just
+    // let CFSocket call us again.
+}
+
+/*! The callback for our CFSocket object.
+ *  \details This simply routes the call to our `-readData` method.
+ *  \param s See the documentation for CFSocketCallBack.
+ *  \param type See the documentation for CFSocketCallBack.
+ *  \param address See the documentation for CFSocketCallBack.
+ *  \param data See the documentation for CFSocketCallBack.
+ *  \param info See the documentation for CFSocketCallBack; this is actually a pointer to the
+ *      'owning' object.
+ */
+
+static void SocketReadCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
+    // This C routine is called by CFSocket when there's data waiting on our
+    // ICMP socket.  It just redirects the call to Objective-C code.
+    SimplePing *    obj;
+    
+    obj = (__bridge SimplePing *) info;
+    assert([obj isKindOfClass:[SimplePing class]]);
+    
+#pragma unused(s)
+    assert(s == obj.socket);
+#pragma unused(type)
+    assert(type == kCFSocketReadCallBack);
+#pragma unused(address)
+    assert(address == nil);
+#pragma unused(data)
+    assert(data == nil);
+    
+    [obj readData];
+}
+
+/*! Starts the send and receive infrastructure.
+ *  \details This is called once we've successfully resolved `hostName` in to
+ *      `hostAddress`.  It's responsible for setting up the socket for sending and
+ *      receiving pings.
+ */
+
+- (void)startWithHostAddress {
+    int                     err;
+    int                     fd;
+    
+    assert(self.hostAddress != nil);
+    
+    // Open the socket.
+    
+    fd = -1;
+    err = 0;
+    switch (self.hostAddressFamily) {
+        case AF_INET: {
+            fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+            if (fd < 0) {
+                err = errno;
+            }
+        } break;
+        case AF_INET6: {
+            fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
+            if (fd < 0) {
+                err = errno;
+            }
+        } break;
+        default: {
+            err = EPROTONOSUPPORT;
+        } break;
+    }
+    
+    if (err != 0) {
+        [self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]];
+    } else {
+        CFSocketContext         context = {0, (__bridge void *)(self), NULL, NULL, NULL};
+        CFRunLoopSourceRef      rls;
+        id<SimplePingDelegate>  strongDelegate;
+        
+        // Wrap it in a CFSocket and schedule it on the runloop.
+        
+        self.socket = (CFSocketRef) CFAutorelease( CFSocketCreateWithNative(NULL, fd, kCFSocketReadCallBack, SocketReadCallback, &context) );
+        assert(self.socket != NULL);
+        
+        // The socket will now take care of cleaning up our file descriptor.
+        
+        assert( CFSocketGetSocketFlags(self.socket) & kCFSocketCloseOnInvalidate );
+        fd = -1;
+        
+        rls = CFSocketCreateRunLoopSource(NULL, self.socket, 0);
+        assert(rls != NULL);
+        
+        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+        
+        CFRelease(rls);
+        
+        strongDelegate = self.delegate;
+        if ( (strongDelegate != nil) && [strongDelegate respondsToSelector:@selector(simplePing:didStartWithAddress:)] ) {
+            [strongDelegate simplePing:self didStartWithAddress:self.hostAddress];
+        }
+    }
+    assert(fd == -1);
+}
+
+/*! Processes the results of our name-to-address resolution.
+ *  \details Called by our CFHost resolution callback (HostResolveCallback) when host
+ *      resolution is complete.  We just latch the first appropriate address and kick
+ *      off the send and receive infrastructure.
+ */
+
+- (void)hostResolutionDone {
+    Boolean     resolved;
+    NSArray *   addresses;
+    
+    // Find the first appropriate address.
+    
+    addresses = (__bridge NSArray *) CFHostGetAddressing(self.host, &resolved);
+    if ( resolved && (addresses != nil) ) {
+        resolved = false;
+        for (NSData * address in addresses) {
+            const struct sockaddr * addrPtr;
+            
+            addrPtr = (const struct sockaddr *) address.bytes;
+            if ( address.length >= sizeof(struct sockaddr) ) {
+                switch (addrPtr->sa_family) {
+                    case AF_INET: {
+                        if (self.addressStyle != SimplePingAddressStyleICMPv6) {
+                            self.hostAddress = address;
+                            resolved = true;
+                        }
+                    } break;
+                    case AF_INET6: {
+                        if (self.addressStyle != SimplePingAddressStyleICMPv4) {
+                            self.hostAddress = address;
+                            resolved = true;
+                        }
+                    } break;
+                }
+            }
+            if (resolved) {
+                break;
+            }
+        }
+    }
+    
+    // We're done resolving, so shut that down.
+    
+    [self stopHostResolution];
+    
+    // If all is OK, start the send and receive infrastructure, otherwise stop.
+    
+    if (resolved) {
+        [self startWithHostAddress];
+    } else {
+        [self didFailWithError:[NSError errorWithDomain:(NSString *)kCFErrorDomainCFNetwork code:kCFHostErrorHostNotFound userInfo:nil]];
+    }
+}
+
+/*! The callback for our CFHost object.
+ *  \details This simply routes the call to our `-hostResolutionDone` or
+ *      `-didFailWithHostStreamError:` methods.
+ *  \param theHost See the documentation for CFHostClientCallBack.
+ *  \param typeInfo See the documentation for CFHostClientCallBack.
+ *  \param error See the documentation for CFHostClientCallBack.
+ *  \param info See the documentation for CFHostClientCallBack; this is actually a pointer to
+ *      the 'owning' object.
+ */
+
+static void HostResolveCallback(CFHostRef theHost, CFHostInfoType typeInfo, const CFStreamError *error, void *info) {
+    // This C routine is called by CFHost when the host resolution is complete.
+    // It just redirects the call to the appropriate Objective-C method.
+    SimplePing *    obj;
+    
+    obj = (__bridge SimplePing *) info;
+    assert([obj isKindOfClass:[SimplePing class]]);
+    
+#pragma unused(theHost)
+    assert(theHost == obj.host);
+#pragma unused(typeInfo)
+    assert(typeInfo == kCFHostAddresses);
+    
+    if ( (error != NULL) && (error->domain != 0) ) {
+        [obj didFailWithHostStreamError:*error];
+    } else {
+        [obj hostResolutionDone];
+    }
+}
+
+- (void)start {
+    Boolean             success;
+    CFHostClientContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
+    CFStreamError       streamError;
+    
+    assert(self.host == NULL);
+    assert(self.hostAddress == nil);
+    
+    self.host = (CFHostRef) CFAutorelease( CFHostCreateWithName(NULL, (__bridge CFStringRef) self.hostName) );
+    assert(self.host != NULL);
+    
+    CFHostSetClient(self.host, HostResolveCallback, &context);
+    
+    CFHostScheduleWithRunLoop(self.host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    
+    success = CFHostStartInfoResolution(self.host, kCFHostAddresses, &streamError);
+    if ( ! success ) {
+        [self didFailWithHostStreamError:streamError];
+    }
+}
+
+/*! Stops the name-to-address resolution infrastructure.
+ */
+
+- (void)stopHostResolution {
+    // Shut down the CFHost.
+    if (self.host != NULL) {
+        CFHostSetClient(self.host, NULL, NULL);
+        CFHostUnscheduleFromRunLoop(self.host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+        self.host = NULL;
+    }
+}
+
+/*! Stops the send and receive infrastructure.
+ */
+
+- (void)stopSocket {
+    if (self.socket != NULL) {
+        CFSocketInvalidate(self.socket);
+        self.socket = NULL;
+    }
+}
+
+- (void)stop {
+    [self stopHostResolution];
+    [self stopSocket];
+    
+    // Junk the host address on stop.  If the client calls -start again, we'll 
+    // re-resolve the host name.
+    
+    self.hostAddress = NULL;
+}
+
+@end

+ 42 - 0
创维盒子/双子星云手机/Vendor/pingTool/WHPingTester.h

@@ -0,0 +1,42 @@
+//
+//  WHPingTester.h
+//  BigVPN
+//
+//  Created by wanghe on 2017/5/11.
+//  Copyright © 2017年 wanghe. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "SimplePing.h"
+
+@protocol WHPingDelegate <NSObject>
+@optional
+- (void) didPingSucccessWithTime:(float)time withError:(NSError*) error;
+- (void) didPingfialewithError:(NSError*)error;
+@end
+
+
+@interface WHPingTester : NSObject<SimplePingDelegate>
+@property (nonatomic, weak, readwrite) id<WHPingDelegate> delegate;
+- (instancetype) init NS_UNAVAILABLE;
+- (instancetype) initWithHostName:(NSString*)hostName NS_DESIGNATED_INITIALIZER;
+@property(nonatomic, assign) NSInteger countdownTime; //设置倒计时时间,10s执行一次
+
+- (void) startPing;
+- (void) stopPing;
+@end
+
+typedef NS_ENUM(NSUInteger, WHPingStatus){
+    WHPingStatusSending = 0 << 0,
+    WHPingStatusTimeout = 1 << 1,
+    WHPingStatusSended = 2 << 2,
+};
+
+@interface WHPingItem : NSObject
+//@property(nonatomic, assign) WHPingStatus status;
+@property(nonatomic, assign) uint16_t sequence;
+@property(nonatomic, strong) NSDate* beginDate;
+@end
+
+
+

+ 132 - 0
创维盒子/双子星云手机/Vendor/pingTool/WHPingTester.m

@@ -0,0 +1,132 @@
+//
+//  WHPingTester.m
+//  BigVPN
+//
+//  Created by wanghe on 2017/5/11.
+//  Copyright © 2017年 wanghe. All rights reserved.
+//
+
+#import "WHPingTester.h"
+
+@interface WHPingTester()<SimplePingDelegate>
+{
+    NSTimer* _timer;
+}
+@property(nonatomic, strong) SimplePing* simplePing;
+
+@property(nonatomic, strong) NSMutableArray<WHPingItem*>* pingItems;
+@end
+
+@implementation WHPingTester
+
+
+- (instancetype) initWithHostName:(NSString*)hostName
+{
+    if(self = [super init])
+    {
+        self.simplePing = [[SimplePing alloc] initWithHostName:hostName];
+        self.simplePing.delegate = self;
+        self.simplePing.addressStyle = SimplePingAddressStyleAny;
+
+        self.pingItems = [NSMutableArray new];
+    }
+    return self;
+}
+
+- (void) startPing
+{
+    [self.simplePing start];
+    
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        if([self.pingItems count] > 0)
+        {
+            if(self.delegate!=nil && [self.delegate respondsToSelector:@selector(didPingSucccessWithTime:withError:)])
+            {
+                [self.delegate didPingSucccessWithTime:0 withError:[NSError errorWithDomain:NSURLErrorDomain code:111 userInfo:nil]];
+            }
+        }
+    });
+}
+
+- (void) stopPing
+{
+    [_timer invalidate];
+    _timer = nil;
+    [self.simplePing stop];
+}
+
+
+- (void) actionTimer
+{
+    if (self.countdownTime > 0) {
+        _timer = [NSTimer scheduledTimerWithTimeInterval:self.countdownTime target:self selector:@selector(sendPingData) userInfo:nil repeats:YES];
+    }
+    else
+    {
+        _timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(sendPingData) userInfo:nil repeats:YES];
+    }
+}
+
+- (void) sendPingData
+{
+    
+    [self.simplePing sendPingWithData:nil];
+    
+}
+
+
+#pragma mark Ping Delegate
+- (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address
+{
+    [self actionTimer];
+}
+
+- (void)simplePing:(SimplePing *)pinger didFailWithError:(NSError *)error
+{
+    HLog(@"ping失败--->%@", error);
+    if(self.delegate!=nil && [self.delegate respondsToSelector:@selector(didPingfialewithError:)])
+    {
+        [self.delegate didPingfialewithError:error];
+    }
+}
+
+- (void)simplePing:(SimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber
+{
+    WHPingItem* item = [WHPingItem new];
+    item.sequence = sequenceNumber;
+    [self.pingItems addObject:item];
+    item.beginDate = [NSDate date];
+}
+- (void)simplePing:(SimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error
+{
+    HLog(@"发包失败--->%@", error);
+    if(self.delegate!=nil && [self.delegate respondsToSelector:@selector(didPingSucccessWithTime:withError:)])
+    {
+        [self.delegate didPingSucccessWithTime:0 withError:error];
+    }
+}
+
+- (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber
+{
+    [self.pingItems enumerateObjectsUsingBlock:^(WHPingItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        if(obj.sequence == sequenceNumber)
+        {
+            if(self.delegate!=nil && [self.delegate respondsToSelector:@selector(didPingSucccessWithTime:withError:)])
+            {
+                float delayTime = [[NSDate date] timeIntervalSinceDate:obj.beginDate] * 1000;
+                [self.delegate didPingSucccessWithTime:delayTime withError:nil];
+            }
+            [self.pingItems removeObject:obj];
+        }
+    }];
+}
+
+- (void)simplePing:(SimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet
+{
+}
+
+@end
+
+@implementation WHPingItem
+@synthesize beginDate;
+@end

+ 69 - 1
创维盒子/双子星云手机/connectDeviceManager/connectDeviceManager.m

@@ -11,12 +11,17 @@
 #import <RayProxy/RaylinkProxy.h>
 #import <CocoaAsyncSocket/GCDAsyncSocket.h>
 
+#import "WHPingTester.h"
+
 @interface connectDeviceManager ()<
 GCDAsyncSocketDelegate,
-RaylinkProxyDelegate
+RaylinkProxyDelegate,
+WHPingDelegate
 >
 {
     dispatch_queue_t initProxyQueue;
+    
+    WHPingTester *whPingTester;
 }
 
 @property (nonatomic, strong) NSTimer *connectCheckTimer;
@@ -65,6 +70,8 @@ static connectDeviceManager *connectDeviceManagerInstance = nil;
         if(weakSelf.DeviceThirdIdMod.status == 0)
         {
             weakSelf.curConnectDeviceState = DeviceConnectGetThridOK;
+            NSString *ipStr = weakSelf.DeviceThirdIdMod.data.ip;
+            [weakSelf startPingDeviceIp:ipStr];
             [weakSelf initRuiyunSDKFun];
         }
         
@@ -306,4 +313,65 @@ static connectDeviceManager *connectDeviceManagerInstance = nil;
         HLog("网络报错");
     }];
 }
+
+#pragma mark ---ping-----站点 判断是否是局域网
+- (void)startPingDeviceIp:(NSString *)roomInternetIp
+{
+    //roomInternetIp = @"www.baidu.com";
+    if(!roomInternetIp || roomInternetIp.length < 7){
+        self.DeviceThirdIdMod.data.isPingOk = NO;
+        return;
+    }
+    
+    if (self->whPingTester)
+    {
+        [self->whPingTester stopPing];
+        self->whPingTester = nil;
+    }
+    
+    self->whPingTester = [[WHPingTester alloc] initWithHostName:roomInternetIp];
+    self->whPingTester.delegate = self;
+    //self->whPingTester.countdownTime = 1; //1秒ping一次
+    [self->whPingTester startPing];
+    
+    
+    /// 启动定时器监听 10秒后 whPingTester的状态
+    [NSTimer scheduledTimerWithTimeInterval:5 repeats:NO block:^(NSTimer * _Nonnull timer) {
+        
+        if(self->whPingTester){
+            [self didGetPingStateIsOK:NO];
+        }
+    }];
+    
+}
+
+#pragma mark ---ping---- 代理回调
+- (void) didPingSucccessWithTime:(float)time withError:(NSError*) error
+{
+    HLog(@"time:%f \n error: %@",time,error)
+    
+    //if(error.code == 111 || time > 1000) //超时或者延时超过100ms,就要记录数据
+    if(error != nil)
+    {
+        [self didGetPingStateIsOK:NO];
+    }
+    else if(time > 0){
+        [self didGetPingStateIsOK:YES];
+    }
+    
+}
+
+- (void) didPingfialewithError:(NSError*)error
+{
+    HLog(@" error  error: %@",error)
+    [self didGetPingStateIsOK:NO];
+}
+
+-(void)didGetPingStateIsOK:(BOOL)isOk
+{
+    self.DeviceThirdIdMod.data.isPingOk = isOk;
+    [self->whPingTester stopPing];
+    self->whPingTester = nil;
+}
+
 @end

+ 3 - 1
创维盒子/双子星云手机/connectDeviceManager/model/DeviceThirdIdModel.h

@@ -9,7 +9,7 @@
 #import "JSONModel.h"
 NS_ASSUME_NONNULL_BEGIN
 
-@interface DeviceThirdDataModel : JSONModel
+@interface DeviceThirdDataModel : SuperModel
 
 /**板卡类型*/
 @property(nonatomic,copy) NSString  *broadType;//
@@ -24,6 +24,8 @@ NS_ASSUME_NONNULL_BEGIN
 /**sn*/
 @property (nonatomic,copy) NSString *sn; //
 
+/**自定义字段 是否为局域网*/
+@property (nonatomic,assign) bool isPingOk; //
 @end
 
 @interface DeviceThirdIdModel : SuperModel