@onekeyfe/react-native-ping 1.1.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Ping.podspec +19 -0
- package/android/build.gradle +77 -0
- package/android/src/main/java/com/rnping/RNReactNativePingModule.kt +37 -0
- package/android/src/main/java/com/rnping/RNReactNativePingPackage.kt +33 -0
- package/ios/GBPing/GBPing.h +50 -0
- package/ios/GBPing/GBPing.m +944 -0
- package/ios/GBPing/GBPingSummary.h +24 -0
- package/ios/GBPing/GBPingSummary.m +67 -0
- package/ios/GBPing/ICMPHeader.h +79 -0
- package/ios/LHNetwork/LHDefinition.h +24 -0
- package/ios/LHNetwork/LHNetwork.h +34 -0
- package/ios/LHNetwork/LHNetwork.m +223 -0
- package/ios/Ping.h +10 -0
- package/ios/Ping.mm +91 -0
- package/lib/module/NativePing.js +5 -0
- package/lib/module/NativePing.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativePing.d.ts +10 -0
- package/lib/typescript/src/NativePing.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +87 -0
- package/src/NativePing.ts +8 -0
- package/src/index.tsx +4 -0
|
@@ -0,0 +1,944 @@
|
|
|
1
|
+
//
|
|
2
|
+
// GBPing.m
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
#import "GBPing.h"
|
|
6
|
+
#import "LHDefinition.h"
|
|
7
|
+
|
|
8
|
+
#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
|
|
9
|
+
#import <CFNetwork/CFNetwork.h>
|
|
10
|
+
#else
|
|
11
|
+
#import <CoreServices/CoreServices.h>
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
#import "ICMPHeader.h"
|
|
15
|
+
|
|
16
|
+
#include <sys/socket.h>
|
|
17
|
+
#include <netinet/in.h>
|
|
18
|
+
|
|
19
|
+
#include <stdio.h>
|
|
20
|
+
#include <stdlib.h>
|
|
21
|
+
#include <unistd.h>
|
|
22
|
+
#include <errno.h>
|
|
23
|
+
#include <string.h>
|
|
24
|
+
#include <sys/types.h>
|
|
25
|
+
#include <arpa/inet.h>
|
|
26
|
+
#include <netdb.h>
|
|
27
|
+
|
|
28
|
+
static NSTimeInterval const kPendingPingsCleanupGrace = 1.0;
|
|
29
|
+
|
|
30
|
+
static NSUInteger const kDefaultPayloadSize = 56;
|
|
31
|
+
static NSUInteger const kDefaultTTL = 49;
|
|
32
|
+
static NSTimeInterval const kDefaultPingPeriod = 1.0;
|
|
33
|
+
static NSTimeInterval const kDefaultTimeout = 2.0;
|
|
34
|
+
|
|
35
|
+
@interface GBPing ()
|
|
36
|
+
|
|
37
|
+
@property (assign, atomic) int socket;
|
|
38
|
+
@property (strong, nonatomic) NSData *hostAddress;
|
|
39
|
+
@property (strong, nonatomic) NSString *hostAddressString;
|
|
40
|
+
@property (assign, nonatomic) uint16_t identifier;
|
|
41
|
+
|
|
42
|
+
@property (assign, atomic, readwrite) BOOL isPinging;
|
|
43
|
+
@property (assign, atomic, readwrite) BOOL isReady;
|
|
44
|
+
@property (assign, nonatomic) NSUInteger nextSequenceNumber;
|
|
45
|
+
@property (strong, atomic) NSMutableDictionary *pendingPings;
|
|
46
|
+
@property (strong, nonatomic) NSMutableDictionary *timeoutTimers;
|
|
47
|
+
|
|
48
|
+
@property (strong, nonatomic) dispatch_queue_t setupQueue;
|
|
49
|
+
|
|
50
|
+
@property (assign, atomic) BOOL isStopped;
|
|
51
|
+
|
|
52
|
+
@property (copy, atomic) void (^ successBlock)(GBPingSummary *summary);
|
|
53
|
+
@property (copy, atomic) void (^ failBlock)(NSError *summary);
|
|
54
|
+
|
|
55
|
+
@end
|
|
56
|
+
|
|
57
|
+
@implementation GBPing
|
|
58
|
+
{
|
|
59
|
+
NSUInteger _payloadSize;
|
|
60
|
+
NSUInteger _ttl;
|
|
61
|
+
NSTimeInterval _timeout;
|
|
62
|
+
NSTimeInterval _pingPeriod;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#pragma mark - custom acc
|
|
66
|
+
|
|
67
|
+
- (void)setTimeout:(NSTimeInterval)timeout
|
|
68
|
+
{
|
|
69
|
+
@synchronized(self) {
|
|
70
|
+
if (self.isPinging) {
|
|
71
|
+
if (self.debug) {
|
|
72
|
+
NSLog(@"GBPing: can't set timeout while pinger is running.");
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
_timeout = timeout;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
- (NSTimeInterval)timeout
|
|
81
|
+
{
|
|
82
|
+
@synchronized(self) {
|
|
83
|
+
if (!_timeout) {
|
|
84
|
+
return kDefaultTimeout;
|
|
85
|
+
} else {
|
|
86
|
+
return _timeout;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
- (void)setTtl:(NSUInteger)ttl
|
|
92
|
+
{
|
|
93
|
+
@synchronized(self) {
|
|
94
|
+
if (self.isPinging) {
|
|
95
|
+
if (self.debug) {
|
|
96
|
+
NSLog(@"GBPing: can't set ttl while pinger is running.");
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
_ttl = ttl;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
- (NSUInteger)ttl
|
|
105
|
+
{
|
|
106
|
+
@synchronized(self) {
|
|
107
|
+
if (!_ttl) {
|
|
108
|
+
return kDefaultTTL;
|
|
109
|
+
} else {
|
|
110
|
+
return _ttl;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
- (void)setPayloadSize:(NSUInteger)payloadSize
|
|
116
|
+
{
|
|
117
|
+
@synchronized(self) {
|
|
118
|
+
if (self.isPinging) {
|
|
119
|
+
if (self.debug) {
|
|
120
|
+
NSLog(@"GBPing: can't set payload size while pinger is running.");
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
_payloadSize = payloadSize;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
- (NSUInteger)payloadSize
|
|
129
|
+
{
|
|
130
|
+
@synchronized(self) {
|
|
131
|
+
if (!_payloadSize) {
|
|
132
|
+
return kDefaultPayloadSize;
|
|
133
|
+
} else {
|
|
134
|
+
return _payloadSize;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
- (void)setPingPeriod:(NSTimeInterval)pingPeriod
|
|
140
|
+
{
|
|
141
|
+
@synchronized(self) {
|
|
142
|
+
if (self.isPinging) {
|
|
143
|
+
if (self.debug) {
|
|
144
|
+
NSLog(@"GBPing: can't set pingPeriod while pinger is running.");
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
_pingPeriod = pingPeriod;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
- (NSTimeInterval)pingPeriod
|
|
153
|
+
{
|
|
154
|
+
@synchronized(self) {
|
|
155
|
+
if (!_pingPeriod) {
|
|
156
|
+
return (NSTimeInterval)kDefaultPingPeriod;
|
|
157
|
+
} else {
|
|
158
|
+
return _pingPeriod;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
#pragma mark - core pinging methods
|
|
164
|
+
|
|
165
|
+
- (void)setupWithBlock:(StartupCallback)callback
|
|
166
|
+
{
|
|
167
|
+
//error out of its already setup
|
|
168
|
+
if (self.isReady) {
|
|
169
|
+
if (self.debug) {
|
|
170
|
+
NSLog(@"GBPing: Can't setup, already setup.");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
//notify about error and return
|
|
174
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
175
|
+
DEFINE_NSError(runningError, PingUtil_Message_PreviousPingIsStillRunning)
|
|
176
|
+
callback(NO, runningError);
|
|
177
|
+
});
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
//error out if no host is set
|
|
182
|
+
if (!self.host) {
|
|
183
|
+
if (self.debug) {
|
|
184
|
+
NSLog(@"GBPing: set host before attempting to start.");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
//notify about error and return
|
|
188
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
189
|
+
DEFINE_NSError(hostError, PingUtil_Message_HostErrorNotSetHost)
|
|
190
|
+
callback(NO, hostError);
|
|
191
|
+
});
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
//set up data structs
|
|
196
|
+
self.nextSequenceNumber = 0;
|
|
197
|
+
self.pendingPings = [[NSMutableDictionary alloc] init];
|
|
198
|
+
self.timeoutTimers = [[NSMutableDictionary alloc] init];
|
|
199
|
+
|
|
200
|
+
dispatch_async(self.setupQueue, ^{
|
|
201
|
+
CFStreamError streamError;
|
|
202
|
+
BOOL success;
|
|
203
|
+
|
|
204
|
+
CFHostRef hostRef = CFHostCreateWithName(NULL, (__bridge CFStringRef)self.host);
|
|
205
|
+
|
|
206
|
+
/*
|
|
207
|
+
* CFHostCreateWithName will return a null result in certain cases.
|
|
208
|
+
* CFHostStartInfoResolution will return YES if _hostRef is null.
|
|
209
|
+
*/
|
|
210
|
+
if (hostRef) {
|
|
211
|
+
success = CFHostStartInfoResolution(hostRef, kCFHostAddresses, &streamError);
|
|
212
|
+
} else {
|
|
213
|
+
success = NO;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (!success) {
|
|
217
|
+
//construct an error
|
|
218
|
+
NSDictionary *userInfo;
|
|
219
|
+
NSError *error;
|
|
220
|
+
|
|
221
|
+
if (hostRef && streamError.domain == kCFStreamErrorDomainNetDB) {
|
|
222
|
+
userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
223
|
+
[NSNumber numberWithInteger:streamError.error], kCFGetAddrInfoFailureKey,
|
|
224
|
+
nil
|
|
225
|
+
];
|
|
226
|
+
} else {
|
|
227
|
+
userInfo = nil;
|
|
228
|
+
}
|
|
229
|
+
error = [NSError errorWithDomain:(NSString *)kCFErrorDomainCFNetwork code:kCFHostErrorUnknown userInfo:userInfo];
|
|
230
|
+
|
|
231
|
+
//clean up so far
|
|
232
|
+
[self stop];
|
|
233
|
+
|
|
234
|
+
//notify about error and return
|
|
235
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
236
|
+
DEFINE_NSError(hostUnknowError, PingUtil_Message_HostErrorUnknown)
|
|
237
|
+
callback(NO, hostUnknowError);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
//just incase
|
|
241
|
+
if (hostRef) {
|
|
242
|
+
CFRelease(hostRef);
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
//get the first IPv4 or IPv6 address
|
|
248
|
+
Boolean resolved;
|
|
249
|
+
NSArray *addresses = (__bridge NSArray *)CFHostGetAddressing(hostRef, &resolved);
|
|
250
|
+
if (resolved && (addresses != nil)) {
|
|
251
|
+
resolved = false;
|
|
252
|
+
for (NSData *address in addresses) {
|
|
253
|
+
const struct sockaddr *anAddrPtr = (const struct sockaddr *)[address bytes];
|
|
254
|
+
|
|
255
|
+
if ([address length] >= sizeof(struct sockaddr) &&
|
|
256
|
+
(anAddrPtr->sa_family == AF_INET || anAddrPtr->sa_family == AF_INET6)) {
|
|
257
|
+
resolved = true;
|
|
258
|
+
self.hostAddress = address;
|
|
259
|
+
struct sockaddr_in *sin = (struct sockaddr_in *)anAddrPtr;
|
|
260
|
+
char str[INET6_ADDRSTRLEN];
|
|
261
|
+
inet_ntop(anAddrPtr->sa_family, &(sin->sin_addr), str, INET6_ADDRSTRLEN);
|
|
262
|
+
self.hostAddressString = [[NSString alloc] initWithUTF8String:str];
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
//we can stop host resolution now
|
|
269
|
+
if (hostRef) {
|
|
270
|
+
CFRelease(hostRef);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
//if an error occurred during resolution
|
|
274
|
+
if (!resolved) {
|
|
275
|
+
//stop
|
|
276
|
+
[self stop];
|
|
277
|
+
|
|
278
|
+
//notify about error and return
|
|
279
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
280
|
+
DEFINE_NSError(hostError, PingUtil_Message_HostErrorHostNotFound)
|
|
281
|
+
callback(NO, hostError);
|
|
282
|
+
});
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
//set up socket
|
|
287
|
+
int err = 0;
|
|
288
|
+
switch (self.hostAddressFamily) {
|
|
289
|
+
case AF_INET: {
|
|
290
|
+
self.socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
|
|
291
|
+
if (self.socket < 0) {
|
|
292
|
+
err = errno;
|
|
293
|
+
}
|
|
294
|
+
} break;
|
|
295
|
+
case AF_INET6: {
|
|
296
|
+
self.socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
|
|
297
|
+
if (self.socket < 0) {
|
|
298
|
+
err = errno;
|
|
299
|
+
}
|
|
300
|
+
} break;
|
|
301
|
+
default: {
|
|
302
|
+
err = EPROTONOSUPPORT;
|
|
303
|
+
} break;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
//couldnt setup socket
|
|
307
|
+
if (err) {
|
|
308
|
+
//clean up so far
|
|
309
|
+
[self stop];
|
|
310
|
+
|
|
311
|
+
//notify about error and close
|
|
312
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
313
|
+
DEFINE_NSError(unknownError, PingUtil_Message_Unknown)
|
|
314
|
+
callback(NO, unknownError);
|
|
315
|
+
});
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
//set ttl on the socket
|
|
320
|
+
if (self.ttl) {
|
|
321
|
+
u_char ttlForSockOpt = (u_char)self.ttl;
|
|
322
|
+
setsockopt(self.socket, IPPROTO_IP, IP_TTL, &ttlForSockOpt, sizeof(NSUInteger));
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
//we are ready now
|
|
326
|
+
self.isReady = YES;
|
|
327
|
+
|
|
328
|
+
//notify that we are ready
|
|
329
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
330
|
+
callback(YES, nil);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
self.isStopped = NO;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
- (void)startPingingWithBlock:(void (^)(GBPingSummary *))successBlock fail:(void (^)(NSError *))failBlock
|
|
338
|
+
{
|
|
339
|
+
if (self.isReady && !self.isPinging) {
|
|
340
|
+
self.successBlock = [successBlock copy];
|
|
341
|
+
self.failBlock = [failBlock copy];
|
|
342
|
+
//go into infinite listenloop on a new thread (listenThread)
|
|
343
|
+
NSThread *listenThread = [[NSThread alloc] initWithTarget:self selector:@selector(listenLoop) object:nil];
|
|
344
|
+
listenThread.name = @"listenThread";
|
|
345
|
+
|
|
346
|
+
//set up loop that sends packets on a new thread (sendThread)
|
|
347
|
+
NSThread *sendThread = [[NSThread alloc] initWithTarget:self selector:@selector(sendLoop) object:nil];
|
|
348
|
+
sendThread.name = @"sendThread";
|
|
349
|
+
|
|
350
|
+
//we're pinging now
|
|
351
|
+
self.isPinging = YES;
|
|
352
|
+
[listenThread start];
|
|
353
|
+
[sendThread start];
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
- (void)listenLoop
|
|
358
|
+
{
|
|
359
|
+
@autoreleasepool {
|
|
360
|
+
while (self.isPinging)
|
|
361
|
+
[self listenOnce];
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
- (void)listenOnce
|
|
366
|
+
{
|
|
367
|
+
int err;
|
|
368
|
+
struct sockaddr_storage addr;
|
|
369
|
+
socklen_t addrLen;
|
|
370
|
+
ssize_t bytesRead;
|
|
371
|
+
void *buffer;
|
|
372
|
+
enum { kBufferSize = 65535 };
|
|
373
|
+
|
|
374
|
+
buffer = malloc(kBufferSize);
|
|
375
|
+
assert(buffer);
|
|
376
|
+
|
|
377
|
+
//set socket timeout
|
|
378
|
+
struct timeval tv;
|
|
379
|
+
tv.tv_sec = self.timeout / 1000;
|
|
380
|
+
tv.tv_usec = 0;
|
|
381
|
+
if (setsockopt(self.socket, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) < 0) {
|
|
382
|
+
NSLog(@"Set Timeput Error");
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
//read the data.
|
|
386
|
+
addrLen = sizeof(addr);
|
|
387
|
+
bytesRead = recvfrom(self.socket, buffer, kBufferSize, 0, (struct sockaddr *)&addr, &addrLen);
|
|
388
|
+
err = 0;
|
|
389
|
+
if (bytesRead < 0) {
|
|
390
|
+
err = errno;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
//process the data we read.
|
|
394
|
+
if (bytesRead > 0) {
|
|
395
|
+
char hoststr[INET6_ADDRSTRLEN];
|
|
396
|
+
struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
|
|
397
|
+
inet_ntop(sin->sin_family, &(sin->sin_addr), hoststr, INET6_ADDRSTRLEN);
|
|
398
|
+
NSString *host = [[NSString alloc] initWithUTF8String:hoststr];
|
|
399
|
+
|
|
400
|
+
if ([host isEqualToString:self.hostAddressString]) { // only make sense where received packet comes from expected source
|
|
401
|
+
NSDate *receiveDate = [NSDate date];
|
|
402
|
+
NSMutableData *packet;
|
|
403
|
+
|
|
404
|
+
packet = [NSMutableData dataWithBytes:buffer length:(NSUInteger)bytesRead];
|
|
405
|
+
assert(packet);
|
|
406
|
+
|
|
407
|
+
//complete the ping summary
|
|
408
|
+
const struct ICMPHeader *headerPointer;
|
|
409
|
+
|
|
410
|
+
if (sin->sin_family == AF_INET) {
|
|
411
|
+
headerPointer = [[self class] icmp4InPacket:packet];
|
|
412
|
+
} else {
|
|
413
|
+
headerPointer = (const struct ICMPHeader *)[packet bytes];
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
NSUInteger seqNo = (NSUInteger)OSSwapBigToHostInt16(headerPointer->sequenceNumber);
|
|
417
|
+
NSNumber *key = @(seqNo);
|
|
418
|
+
GBPingSummary *pingSummary = [(GBPingSummary *)self.pendingPings[key] copy];
|
|
419
|
+
|
|
420
|
+
if (pingSummary) {
|
|
421
|
+
if ([self isValidPingResponsePacket:packet]) {
|
|
422
|
+
//override the source address (we might have sent to google.com and 172.123.213.192 replied)
|
|
423
|
+
pingSummary.receiveDate = receiveDate;
|
|
424
|
+
// IP can't be read from header for ICMPv6
|
|
425
|
+
if (sin->sin_family == AF_INET) {
|
|
426
|
+
pingSummary.host = [[self class] sourceAddressInPacket:packet];
|
|
427
|
+
|
|
428
|
+
//set ttl from response (different servers may respond with different ttls)
|
|
429
|
+
const struct IPHeader *ipPtr;
|
|
430
|
+
if ([packet length] >= sizeof(IPHeader)) {
|
|
431
|
+
ipPtr = (const IPHeader *)[packet bytes];
|
|
432
|
+
pingSummary.ttl = ipPtr->timeToLive;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
pingSummary.status = GBPingStatusSuccess;
|
|
437
|
+
|
|
438
|
+
//invalidate the timeouttimer
|
|
439
|
+
NSTimer *timer = self.timeoutTimers[key];
|
|
440
|
+
[timer invalidate];
|
|
441
|
+
[self.timeoutTimers removeObjectForKey:key];
|
|
442
|
+
|
|
443
|
+
if (self.successBlock) {
|
|
444
|
+
self.successBlock([pingSummary copy]);
|
|
445
|
+
}
|
|
446
|
+
if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didReceiveReplyWithSummary:)]) {
|
|
447
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
448
|
+
//notify delegate
|
|
449
|
+
[self.delegate ping:self didReceiveReplyWithSummary:[pingSummary copy]];
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
} else {
|
|
453
|
+
pingSummary.status = GBPingStatusFail;
|
|
454
|
+
|
|
455
|
+
if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didReceiveUnexpectedReplyWithSummary:)]) {
|
|
456
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
457
|
+
[self.delegate ping:self didReceiveUnexpectedReplyWithSummary:[pingSummary copy]];
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
} else {
|
|
464
|
+
//we failed to read the data, so shut everything down.
|
|
465
|
+
if (err == 0) {
|
|
466
|
+
err = EPIPE;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
@synchronized(self) {
|
|
470
|
+
if (!self.isStopped) {
|
|
471
|
+
if (self.failBlock) {
|
|
472
|
+
DEFINE_NSError(unknownError, PingUtil_Message_Unknown)
|
|
473
|
+
_failBlock(unknownError);
|
|
474
|
+
}
|
|
475
|
+
if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didFailWithError:)]) {
|
|
476
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
477
|
+
[self.delegate ping:self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]];
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
//stop the whole thing
|
|
484
|
+
[self stop];
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
free(buffer);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
- (void)sendLoop
|
|
491
|
+
{
|
|
492
|
+
@autoreleasepool {
|
|
493
|
+
while (self.isPinging) {
|
|
494
|
+
[self sendPing];
|
|
495
|
+
|
|
496
|
+
NSTimeInterval runUntil = CFAbsoluteTimeGetCurrent() + self.pingPeriod;
|
|
497
|
+
NSTimeInterval time = 0;
|
|
498
|
+
while (runUntil > time) {
|
|
499
|
+
NSDate *runUntilDate = [NSDate dateWithTimeIntervalSinceReferenceDate:runUntil];
|
|
500
|
+
[[NSRunLoop currentRunLoop] runUntilDate:runUntilDate];
|
|
501
|
+
|
|
502
|
+
time = CFAbsoluteTimeGetCurrent();
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
- (void)sendPing
|
|
509
|
+
{
|
|
510
|
+
if (self.isPinging) {
|
|
511
|
+
int err;
|
|
512
|
+
NSData *packet;
|
|
513
|
+
ssize_t bytesSent;
|
|
514
|
+
|
|
515
|
+
// Construct the ping packet.
|
|
516
|
+
NSData *payload = [self generateDataWithLength:(self.payloadSize)];
|
|
517
|
+
|
|
518
|
+
switch (self.hostAddressFamily) {
|
|
519
|
+
case AF_INET: {
|
|
520
|
+
packet = [self pingPacketWithType:kICMPv4TypeEchoRequest payload:payload requiresChecksum:YES];
|
|
521
|
+
} break;
|
|
522
|
+
case AF_INET6: {
|
|
523
|
+
packet = [self pingPacketWithType:kICMPv6TypeEchoRequest payload:payload requiresChecksum:NO];
|
|
524
|
+
} break;
|
|
525
|
+
default: {
|
|
526
|
+
assert(NO);
|
|
527
|
+
} break;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// this is our ping summary
|
|
531
|
+
GBPingSummary *newPingSummary = [GBPingSummary new];
|
|
532
|
+
|
|
533
|
+
// Send the packet.
|
|
534
|
+
if (self.socket == 0) {
|
|
535
|
+
bytesSent = -1;
|
|
536
|
+
err = EBADF;
|
|
537
|
+
} else {
|
|
538
|
+
//record the send date
|
|
539
|
+
NSDate *sendDate = [NSDate date];
|
|
540
|
+
|
|
541
|
+
//construct ping summary, as much as it can
|
|
542
|
+
newPingSummary.sequenceNumber = self.nextSequenceNumber;
|
|
543
|
+
newPingSummary.host = self.host;
|
|
544
|
+
newPingSummary.sendDate = sendDate;
|
|
545
|
+
newPingSummary.ttl = self.ttl;
|
|
546
|
+
newPingSummary.payloadSize = self.payloadSize;
|
|
547
|
+
newPingSummary.status = GBPingStatusPending;
|
|
548
|
+
|
|
549
|
+
//add it to pending pings
|
|
550
|
+
NSNumber *key = @(self.nextSequenceNumber);
|
|
551
|
+
self.pendingPings[key] = newPingSummary;
|
|
552
|
+
|
|
553
|
+
//increment sequence number
|
|
554
|
+
self.nextSequenceNumber += 1;
|
|
555
|
+
|
|
556
|
+
//we create a copy, this one will be passed out to other threads
|
|
557
|
+
GBPingSummary *pingSummaryCopy = [newPingSummary copy];
|
|
558
|
+
|
|
559
|
+
//we need to clean up our list of pending pings, and we do that after the timeout has elapsed (+ some grace period)
|
|
560
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((self.timeout + kPendingPingsCleanupGrace) * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
561
|
+
//remove the ping from the pending list
|
|
562
|
+
[self.pendingPings removeObjectForKey:key];
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
//add a timeout timer
|
|
566
|
+
//add a timeout timer
|
|
567
|
+
NSTimer *timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:self.timeout
|
|
568
|
+
target:[NSBlockOperation blockOperationWithBlock:^{
|
|
569
|
+
newPingSummary.status = GBPingStatusFail;
|
|
570
|
+
|
|
571
|
+
//notify about the failure
|
|
572
|
+
if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didTimeoutWithSummary:)]) {
|
|
573
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
574
|
+
[self.delegate ping:self didTimeoutWithSummary:pingSummaryCopy];
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
//remove the timer itself from the timers list
|
|
579
|
+
//lm make sure that the timer list doesnt grow and these removals actually work... try logging the count of the timeoutTimers when stopping the pinger
|
|
580
|
+
[self.timeoutTimers removeObjectForKey:key];
|
|
581
|
+
}]
|
|
582
|
+
selector:@selector(main)
|
|
583
|
+
userInfo:nil
|
|
584
|
+
repeats:NO];
|
|
585
|
+
[[NSRunLoop mainRunLoop] addTimer:timeoutTimer forMode:NSRunLoopCommonModes];
|
|
586
|
+
|
|
587
|
+
//keep a local ref to it
|
|
588
|
+
if (self.timeoutTimers) {
|
|
589
|
+
self.timeoutTimers[key] = timeoutTimer;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
//notify delegate about this
|
|
593
|
+
if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didSendPingWithSummary:)]) {
|
|
594
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
595
|
+
[self.delegate ping:self didSendPingWithSummary:pingSummaryCopy];
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
bytesSent = sendto(
|
|
600
|
+
self.socket,
|
|
601
|
+
[packet bytes],
|
|
602
|
+
[packet length],
|
|
603
|
+
0,
|
|
604
|
+
(struct sockaddr *)[self.hostAddress bytes],
|
|
605
|
+
(socklen_t)[self.hostAddress length]
|
|
606
|
+
);
|
|
607
|
+
err = 0;
|
|
608
|
+
if (bytesSent < 0) {
|
|
609
|
+
err = errno;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// This is after the sending
|
|
614
|
+
|
|
615
|
+
//successfully sent
|
|
616
|
+
if ((bytesSent > 0) && (((NSUInteger)bytesSent) == [packet length])) {
|
|
617
|
+
//noop, we already notified delegate about sending of the ping
|
|
618
|
+
}
|
|
619
|
+
//failed to send
|
|
620
|
+
else {
|
|
621
|
+
//complete the error
|
|
622
|
+
if (err == 0) {
|
|
623
|
+
err = ENOBUFS; // This is not a hugely descriptor error, alas.
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
//little log
|
|
627
|
+
if (self.debug) {
|
|
628
|
+
NSLog(@"GBPing: failed to send packet with error code: %d", err);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
//change status
|
|
632
|
+
newPingSummary.status = GBPingStatusFail;
|
|
633
|
+
|
|
634
|
+
GBPingSummary *pingSummaryCopyAfterFailure = [newPingSummary copy];
|
|
635
|
+
|
|
636
|
+
if (self.failBlock) {
|
|
637
|
+
DEFINE_NSError(unknownError, PingUtil_Message_Unknown)
|
|
638
|
+
self.failBlock(unknownError);
|
|
639
|
+
}
|
|
640
|
+
//notify delegate
|
|
641
|
+
if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didFailToSendPingWithSummary:error:)]) {
|
|
642
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
643
|
+
[self.delegate ping:self didFailToSendPingWithSummary:pingSummaryCopyAfterFailure error:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]];
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
- (void)stop
|
|
651
|
+
{
|
|
652
|
+
@synchronized(self) {
|
|
653
|
+
if (!self.isStopped) {
|
|
654
|
+
self.isPinging = NO;
|
|
655
|
+
|
|
656
|
+
self.isReady = NO;
|
|
657
|
+
|
|
658
|
+
//destroy listenThread by closing socket (listenThread)
|
|
659
|
+
if (self.socket) {
|
|
660
|
+
close(self.socket);
|
|
661
|
+
self.socket = 0;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
//destroy host
|
|
665
|
+
self.hostAddress = nil;
|
|
666
|
+
|
|
667
|
+
//clean up pendingpings
|
|
668
|
+
[self.pendingPings removeAllObjects];
|
|
669
|
+
self.pendingPings = nil;
|
|
670
|
+
for (NSNumber *key in [self.timeoutTimers copy]) {
|
|
671
|
+
NSTimer *timer = self.timeoutTimers[key];
|
|
672
|
+
[timer invalidate];
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
//clean up timeouttimers
|
|
676
|
+
[self.timeoutTimers removeAllObjects];
|
|
677
|
+
self.timeoutTimers = nil;
|
|
678
|
+
|
|
679
|
+
//reset seq number
|
|
680
|
+
self.nextSequenceNumber = 0;
|
|
681
|
+
|
|
682
|
+
self.isStopped = YES;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
#pragma mark - util
|
|
688
|
+
|
|
689
|
+
static uint16_t in_cksum(const void *buffer, size_t bufferLen)
|
|
690
|
+
// This is the standard BSD checksum code, modified to use modern types.
|
|
691
|
+
{
|
|
692
|
+
size_t bytesLeft;
|
|
693
|
+
int32_t sum;
|
|
694
|
+
const uint16_t *cursor;
|
|
695
|
+
union {
|
|
696
|
+
uint16_t us;
|
|
697
|
+
uint8_t uc[2];
|
|
698
|
+
} last;
|
|
699
|
+
uint16_t answer;
|
|
700
|
+
|
|
701
|
+
bytesLeft = bufferLen;
|
|
702
|
+
sum = 0;
|
|
703
|
+
cursor = buffer;
|
|
704
|
+
|
|
705
|
+
/*
|
|
706
|
+
* Our algorithm is simple, using a 32 bit accumulator (sum), we add
|
|
707
|
+
* sequential 16 bit words to it, and at the end, fold back all the
|
|
708
|
+
* carry bits from the top 16 bits into the lower 16 bits.
|
|
709
|
+
*/
|
|
710
|
+
while (bytesLeft > 1) {
|
|
711
|
+
sum += *cursor;
|
|
712
|
+
cursor += 1;
|
|
713
|
+
bytesLeft -= 2;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/* mop up an odd byte, if necessary */
|
|
717
|
+
if (bytesLeft == 1) {
|
|
718
|
+
last.uc[0] = *(const uint8_t *)cursor;
|
|
719
|
+
last.uc[1] = 0;
|
|
720
|
+
sum += last.us;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/* add back carry outs from top 16 bits to low 16 bits */
|
|
724
|
+
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
|
|
725
|
+
sum += (sum >> 16); /* add carry */
|
|
726
|
+
answer = (uint16_t) ~sum; /* truncate to 16 bits */
|
|
727
|
+
|
|
728
|
+
return answer;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
+ (NSString *)sourceAddressInPacket:(NSData *)packet
|
|
732
|
+
{
|
|
733
|
+
// Returns the source address of the IP packet
|
|
734
|
+
|
|
735
|
+
const struct IPHeader *ipPtr;
|
|
736
|
+
const uint8_t *sourceAddress;
|
|
737
|
+
|
|
738
|
+
if ([packet length] >= sizeof(IPHeader)) {
|
|
739
|
+
ipPtr = (const IPHeader *)[packet bytes];
|
|
740
|
+
|
|
741
|
+
sourceAddress = ipPtr->sourceAddress;//dont need to swap byte order those cuz theyre the smallest atomic unit (1 byte)
|
|
742
|
+
NSString *ipString = [NSString stringWithFormat:@"%d.%d.%d.%d", sourceAddress[0], sourceAddress[1], sourceAddress[2], sourceAddress[3]];
|
|
743
|
+
|
|
744
|
+
return ipString;
|
|
745
|
+
} else return nil;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
+ (NSUInteger)icmp4HeaderOffsetInPacket:(NSData *)packet
|
|
749
|
+
// Returns the offset of the ICMPHeader within an IP packet.
|
|
750
|
+
{
|
|
751
|
+
NSUInteger result;
|
|
752
|
+
const struct IPHeader *ipPtr;
|
|
753
|
+
size_t ipHeaderLength;
|
|
754
|
+
|
|
755
|
+
result = NSNotFound;
|
|
756
|
+
if ([packet length] >= (sizeof(IPHeader) + sizeof(ICMPHeader))) {
|
|
757
|
+
ipPtr = (const IPHeader *)[packet bytes];
|
|
758
|
+
assert((ipPtr->versionAndHeaderLength & 0xF0) == 0x40); // IPv4
|
|
759
|
+
assert(ipPtr->protocol == 1); // ICMP
|
|
760
|
+
ipHeaderLength = (ipPtr->versionAndHeaderLength & 0x0F) * sizeof(uint32_t);
|
|
761
|
+
if ([packet length] >= (ipHeaderLength + sizeof(ICMPHeader))) {
|
|
762
|
+
result = ipHeaderLength;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
return result;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
+ (const struct ICMPHeader *)icmp4InPacket:(NSData *)packet
|
|
769
|
+
// See comment in header.
|
|
770
|
+
{
|
|
771
|
+
const struct ICMPHeader *result;
|
|
772
|
+
NSUInteger icmpHeaderOffset;
|
|
773
|
+
|
|
774
|
+
result = nil;
|
|
775
|
+
icmpHeaderOffset = [self icmp4HeaderOffsetInPacket:packet];
|
|
776
|
+
if (icmpHeaderOffset != NSNotFound) {
|
|
777
|
+
result = (const struct ICMPHeader *)(((const uint8_t *)[packet bytes]) + icmpHeaderOffset);
|
|
778
|
+
}
|
|
779
|
+
return result;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
- (BOOL)isValidPingResponsePacket:(NSMutableData *)packet
|
|
783
|
+
{
|
|
784
|
+
BOOL result;
|
|
785
|
+
|
|
786
|
+
switch (self.hostAddressFamily) {
|
|
787
|
+
case AF_INET: {
|
|
788
|
+
result = [self isValidPing4ResponsePacket:packet];
|
|
789
|
+
} break;
|
|
790
|
+
case AF_INET6: {
|
|
791
|
+
result = [self isValidPing6ResponsePacket:packet];
|
|
792
|
+
} break;
|
|
793
|
+
default: {
|
|
794
|
+
assert(NO);
|
|
795
|
+
result = NO;
|
|
796
|
+
} break;
|
|
797
|
+
}
|
|
798
|
+
return result;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
- (BOOL)isValidPing4ResponsePacket:(NSMutableData *)packet
|
|
802
|
+
// Returns true if the packet looks like a valid ping response packet destined
|
|
803
|
+
// for us.
|
|
804
|
+
{
|
|
805
|
+
BOOL result;
|
|
806
|
+
NSUInteger icmpHeaderOffset;
|
|
807
|
+
ICMPHeader *icmpPtr;
|
|
808
|
+
uint16_t receivedChecksum;
|
|
809
|
+
uint16_t calculatedChecksum;
|
|
810
|
+
|
|
811
|
+
result = NO;
|
|
812
|
+
|
|
813
|
+
icmpHeaderOffset = [[self class] icmp4HeaderOffsetInPacket:packet];
|
|
814
|
+
if (icmpHeaderOffset != NSNotFound) {
|
|
815
|
+
icmpPtr = (struct ICMPHeader *)(((uint8_t *)[packet mutableBytes]) + icmpHeaderOffset);
|
|
816
|
+
|
|
817
|
+
receivedChecksum = icmpPtr->checksum;
|
|
818
|
+
icmpPtr->checksum = 0;
|
|
819
|
+
calculatedChecksum = in_cksum(icmpPtr, [packet length] - icmpHeaderOffset);
|
|
820
|
+
icmpPtr->checksum = receivedChecksum;
|
|
821
|
+
|
|
822
|
+
if (receivedChecksum == calculatedChecksum) {
|
|
823
|
+
if ( (icmpPtr->type == kICMPv4TypeEchoReply) && (icmpPtr->code == 0) ) {
|
|
824
|
+
if (OSSwapBigToHostInt16(icmpPtr->identifier) == self.identifier) {
|
|
825
|
+
if (OSSwapBigToHostInt16(icmpPtr->sequenceNumber) < self.nextSequenceNumber) {
|
|
826
|
+
result = YES;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// NSLog(@"valid: %@, type: %d", _b(result), icmpPtr->type);
|
|
834
|
+
|
|
835
|
+
return result;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
- (BOOL)isValidPing6ResponsePacket:(NSMutableData *)packet
|
|
839
|
+
// Returns true if the IPv6 packet looks like a valid ping response packet destined
|
|
840
|
+
// for us.
|
|
841
|
+
{
|
|
842
|
+
BOOL result;
|
|
843
|
+
const ICMPHeader *icmpPtr;
|
|
844
|
+
|
|
845
|
+
result = NO;
|
|
846
|
+
|
|
847
|
+
if (packet.length >= sizeof(*icmpPtr)) {
|
|
848
|
+
icmpPtr = packet.bytes;
|
|
849
|
+
|
|
850
|
+
if ( (icmpPtr->type == kICMPv6TypeEchoReply) && (icmpPtr->code == 0) ) {
|
|
851
|
+
if (OSSwapBigToHostInt16(icmpPtr->identifier) == self.identifier) {
|
|
852
|
+
if (OSSwapBigToHostInt16(icmpPtr->sequenceNumber) < self.nextSequenceNumber) {
|
|
853
|
+
result = YES;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
return result;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
- (NSData *)generateDataWithLength:(NSUInteger)length
|
|
863
|
+
{
|
|
864
|
+
//create a buffer full of 7's of specified length
|
|
865
|
+
char tempBuffer[length];
|
|
866
|
+
memset(tempBuffer, 7, length);
|
|
867
|
+
|
|
868
|
+
return [[NSData alloc] initWithBytes:tempBuffer length:length];
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
- (void)_invokeTimeoutCallback:(NSTimer *)timer
|
|
872
|
+
{
|
|
873
|
+
dispatch_block_t callback = timer.userInfo;
|
|
874
|
+
if (callback) {
|
|
875
|
+
callback();
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
- (NSData *)pingPacketWithType:(uint8_t)type payload:(NSData *)payload requiresChecksum:(BOOL)requiresChecksum
|
|
880
|
+
{
|
|
881
|
+
NSMutableData *packet;
|
|
882
|
+
ICMPHeader *icmpPtr;
|
|
883
|
+
|
|
884
|
+
packet = [NSMutableData dataWithLength:sizeof(*icmpPtr) + payload.length];
|
|
885
|
+
assert(packet != nil);
|
|
886
|
+
|
|
887
|
+
icmpPtr = packet.mutableBytes;
|
|
888
|
+
icmpPtr->type = type;
|
|
889
|
+
icmpPtr->code = 0;
|
|
890
|
+
icmpPtr->checksum = 0;
|
|
891
|
+
icmpPtr->identifier = OSSwapHostToBigInt16(self.identifier);
|
|
892
|
+
icmpPtr->sequenceNumber = OSSwapHostToBigInt16(self.nextSequenceNumber);
|
|
893
|
+
memcpy(&icmpPtr[1], [payload bytes], [payload length]);
|
|
894
|
+
|
|
895
|
+
if (requiresChecksum) {
|
|
896
|
+
// The IP checksum routine returns a 16-bit number that's already in correct byte order
|
|
897
|
+
// (due to wacky 1's complement maths), so we just put it into the packet as a 16-bit unit.
|
|
898
|
+
|
|
899
|
+
icmpPtr->checksum = in_cksum(packet.bytes, packet.length);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
return packet;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
- (sa_family_t)hostAddressFamily
|
|
906
|
+
{
|
|
907
|
+
sa_family_t result;
|
|
908
|
+
|
|
909
|
+
result = AF_UNSPEC;
|
|
910
|
+
if ( (self.hostAddress != nil) && (self.hostAddress.length >= sizeof(struct sockaddr)) ) {
|
|
911
|
+
result = ((const struct sockaddr *)self.hostAddress.bytes)->sa_family;
|
|
912
|
+
}
|
|
913
|
+
return result;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
#pragma mark - memory
|
|
917
|
+
|
|
918
|
+
- (id)init
|
|
919
|
+
{
|
|
920
|
+
if (self = [super init]) {
|
|
921
|
+
self.setupQueue = dispatch_queue_create("GBPing setup queue", 0);
|
|
922
|
+
self.isStopped = YES;
|
|
923
|
+
self.identifier = arc4random();
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
return self;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
- (void)dealloc
|
|
930
|
+
{
|
|
931
|
+
self.delegate = nil;
|
|
932
|
+
self.host = nil;
|
|
933
|
+
self.timeoutTimers = nil;
|
|
934
|
+
self.pendingPings = nil;
|
|
935
|
+
self.hostAddress = nil;
|
|
936
|
+
|
|
937
|
+
//clean up socket to be sure
|
|
938
|
+
if (self.socket) {
|
|
939
|
+
close(self.socket);
|
|
940
|
+
self.socket = 0;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
@end
|