Lookin_PTChannel.m 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. #import "Lookin_PTChannel.h"
  2. #import "Lookin_PTPrivate.h"
  3. #include <sys/ioctl.h>
  4. #include <sys/un.h>
  5. #include <err.h>
  6. #include <fcntl.h>
  7. #include <arpa/inet.h>
  8. #import <objc/runtime.h>
  9. // Read member of sockaddr_in without knowing the family
  10. #define PT_SOCKADDR_ACCESS(ss, member4, member6) \
  11. (((ss)->ss_family == AF_INET) ? ( \
  12. ((const struct sockaddr_in *)(ss))->member4 \
  13. ) : ( \
  14. ((const struct sockaddr_in6 *)(ss))->member6 \
  15. ))
  16. // Connection state (storage: uint8_t)
  17. #define kConnStateNone 0
  18. #define kConnStateConnecting 1
  19. #define kConnStateConnected 2
  20. #define kConnStateListening 3
  21. // Delegate support optimization (storage: uint8_t)
  22. #define kDelegateFlagImplements_ioFrameChannel_shouldAcceptFrameOfType_tag_payloadSize 1
  23. #define kDelegateFlagImplements_ioFrameChannel_didEndWithError 2
  24. #define kDelegateFlagImplements_ioFrameChannel_didAcceptConnection_fromAddress 4
  25. #pragma mark -
  26. // Note: We are careful about the size of this struct as each connected peer
  27. // implies one allocation of this struct.
  28. @interface Lookin_PTChannel () {
  29. dispatch_io_t dispatchObj_channel_;
  30. dispatch_source_t dispatchObj_source_;
  31. NSError *endError_; // 64 bit
  32. @public // here be hacks
  33. id<Lookin_PTChannelDelegate> delegate_; // 64 bit
  34. uint8_t delegateFlags_; // 8 bit
  35. @private
  36. uint8_t connState_; // 8 bit
  37. //char padding_[6]; // 48 bit -- only if allocation speed is important
  38. }
  39. - (id)initWithProtocol:(Lookin_PTProtocol*)protocol delegate:(id<Lookin_PTChannelDelegate>)delegate;
  40. - (BOOL)acceptIncomingConnection:(dispatch_fd_t)serverSocketFD;
  41. @end
  42. static const uint8_t kUserInfoKey;
  43. #pragma mark -
  44. @interface Lookin_PTData ()
  45. - (id)initWithMappedDispatchData:(dispatch_data_t)mappedContiguousData data:(void*)data length:(size_t)length;
  46. @end
  47. #pragma mark -
  48. @interface Lookin_PTAddress () {
  49. struct sockaddr_storage sockaddr_;
  50. }
  51. - (id)initWithSockaddr:(const struct sockaddr_storage*)addr;
  52. @end
  53. #pragma mark -
  54. @implementation Lookin_PTChannel
  55. @synthesize protocol = protocol_;
  56. + (Lookin_PTChannel*)channelWithDelegate:(id<Lookin_PTChannelDelegate>)delegate {
  57. return [[Lookin_PTChannel alloc] initWithProtocol:[Lookin_PTProtocol sharedProtocolForQueue:dispatch_get_main_queue()] delegate:delegate];
  58. }
  59. - (id)initWithProtocol:(Lookin_PTProtocol*)protocol delegate:(id<Lookin_PTChannelDelegate>)delegate {
  60. if (!(self = [super init])) return nil;
  61. protocol_ = protocol;
  62. self.delegate = delegate;
  63. return self;
  64. }
  65. - (id)initWithProtocol:(Lookin_PTProtocol*)protocol {
  66. if (!(self = [super init])) return nil;
  67. protocol_ = protocol;
  68. return self;
  69. }
  70. - (id)init {
  71. return [self initWithProtocol:[Lookin_PTProtocol sharedProtocolForQueue:dispatch_get_main_queue()]];
  72. }
  73. - (void)dealloc {
  74. #if PT_DISPATCH_RETAIN_RELEASE
  75. if (dispatchObj_channel_) dispatch_release(dispatchObj_channel_);
  76. else if (dispatchObj_source_) dispatch_release(dispatchObj_source_);
  77. #endif
  78. }
  79. - (BOOL)isConnected {
  80. return connState_ == kConnStateConnecting || connState_ == kConnStateConnected;
  81. }
  82. - (BOOL)isListening {
  83. return connState_ == kConnStateListening;
  84. }
  85. - (id)userInfo {
  86. return objc_getAssociatedObject(self, (void*)&kUserInfoKey);
  87. }
  88. - (void)setUserInfo:(id)userInfo {
  89. objc_setAssociatedObject(self, (const void*)&kUserInfoKey, userInfo, OBJC_ASSOCIATION_RETAIN);
  90. }
  91. - (void)setConnState:(char)connState {
  92. connState_ = connState;
  93. }
  94. - (void)setDispatchChannel:(dispatch_io_t)channel {
  95. assert(connState_ == kConnStateConnecting || connState_ == kConnStateConnected || connState_ == kConnStateNone);
  96. dispatch_io_t prevChannel = dispatchObj_channel_;
  97. if (prevChannel != channel) {
  98. dispatchObj_channel_ = channel;
  99. #if PT_DISPATCH_RETAIN_RELEASE
  100. if (dispatchObj_channel_) dispatch_retain(dispatchObj_channel_);
  101. if (prevChannel) dispatch_release(prevChannel);
  102. #endif
  103. if (!dispatchObj_channel_ && !dispatchObj_source_) {
  104. connState_ = kConnStateNone;
  105. }
  106. }
  107. }
  108. - (void)setDispatchSource:(dispatch_source_t)source {
  109. assert(connState_ == kConnStateListening || connState_ == kConnStateNone);
  110. dispatch_source_t prevSource = dispatchObj_source_;
  111. if (prevSource != source) {
  112. dispatchObj_source_ = source;
  113. #if PT_DISPATCH_RETAIN_RELEASE
  114. if (dispatchObj_source_) dispatch_retain(dispatchObj_source_);
  115. if (prevSource) dispatch_release(prevSource);
  116. #endif
  117. if (!dispatchObj_channel_ && !dispatchObj_source_) {
  118. connState_ = kConnStateNone;
  119. }
  120. }
  121. }
  122. - (id<Lookin_PTChannelDelegate>)delegate {
  123. return delegate_;
  124. }
  125. - (void)setDelegate:(id<Lookin_PTChannelDelegate>)delegate {
  126. delegate_ = delegate;
  127. delegateFlags_ = 0;
  128. if (!delegate_) {
  129. return;
  130. }
  131. if ([delegate respondsToSelector:@selector(ioFrameChannel:shouldAcceptFrameOfType:tag:payloadSize:)]) {
  132. delegateFlags_ |= kDelegateFlagImplements_ioFrameChannel_shouldAcceptFrameOfType_tag_payloadSize;
  133. }
  134. if (delegate_ && [delegate respondsToSelector:@selector(ioFrameChannel:didEndWithError:)]) {
  135. delegateFlags_ |= kDelegateFlagImplements_ioFrameChannel_didEndWithError;
  136. }
  137. if (delegate_ && [delegate respondsToSelector:@selector(ioFrameChannel:didAcceptConnection:fromAddress:)]) {
  138. delegateFlags_ |= kDelegateFlagImplements_ioFrameChannel_didAcceptConnection_fromAddress;
  139. }
  140. }
  141. //- (void)setFileDescriptor:(dispatch_fd_t)fd {
  142. // [self setDispatchChannel:dispatch_io_create(DISPATCH_IO_STREAM, fd, protocol_.queue, ^(int error) {
  143. // close(fd);
  144. // })];
  145. //}
  146. #pragma mark - Connecting
  147. - (void)connectToPort:(int)port overUSBHub:(Lookin_PTUSBHub*)usbHub deviceID:(NSNumber*)deviceID callback:(void(^)(NSError *error))callback {
  148. assert(protocol_ != NULL);
  149. if (connState_ != kConnStateNone) {
  150. if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil]);
  151. return;
  152. }
  153. connState_ = kConnStateConnecting;
  154. [usbHub connectToDevice:deviceID port:port onStart:^(NSError *err, dispatch_io_t dispatchChannel) {
  155. NSError *error = err;
  156. if (!error) {
  157. [self startReadingFromConnectedChannel:dispatchChannel error:&error];
  158. } else {
  159. self->connState_ = kConnStateNone;
  160. }
  161. if (callback) callback(error);
  162. } onEnd:^(NSError *error) {
  163. if (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
  164. [self->delegate_ ioFrameChannel:self didEndWithError:error];
  165. }
  166. self->endError_ = nil;
  167. }];
  168. }
  169. - (void)connectToPort:(in_port_t)port IPv4Address:(in_addr_t)address callback:(void(^)(NSError *error, Lookin_PTAddress *address))callback {
  170. assert(protocol_ != NULL);
  171. if (connState_ != kConnStateNone) {
  172. if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil], nil);
  173. return;
  174. }
  175. connState_ = kConnStateConnecting;
  176. int error = 0;
  177. // Create socket
  178. dispatch_fd_t fd = socket(AF_INET, SOCK_STREAM, 0);
  179. if (fd == -1) {
  180. perror("socket(AF_INET, SOCK_STREAM, 0) failed");
  181. error = errno;
  182. if (callback) callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil], nil);
  183. return;
  184. }
  185. // Connect socket
  186. struct sockaddr_in addr;
  187. bzero((char *)&addr, sizeof(addr));
  188. addr.sin_len = sizeof(addr);
  189. addr.sin_family = AF_INET;
  190. addr.sin_port = htons(port);
  191. //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  192. //addr.sin_addr.s_addr = htonl(INADDR_ANY);
  193. addr.sin_addr.s_addr = htonl(address);
  194. // prevent SIGPIPE
  195. int on = 1;
  196. setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
  197. // int socket, const struct sockaddr *address, socklen_t address_len
  198. if (connect(fd, (const struct sockaddr *)&addr, addr.sin_len) == -1) {
  199. //perror("connect");
  200. error = errno;
  201. close(fd);
  202. if (callback) callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], nil);
  203. return;
  204. }
  205. // get actual address
  206. //if (getsockname(fd, (struct sockaddr*)&addr, (socklen_t*)&addr.sin_len) == -1) {
  207. // error = errno;
  208. // close(fd);
  209. // if (callback) callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], nil);
  210. // return;
  211. //}
  212. dispatch_io_t dispatchChannel = dispatch_io_create(DISPATCH_IO_STREAM, fd, protocol_.queue, ^(int error) {
  213. close(fd);
  214. if (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
  215. NSError *err = error == 0 ? self->endError_ : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil];
  216. [self->delegate_ ioFrameChannel:self didEndWithError:err];
  217. self->endError_ = nil;
  218. }
  219. });
  220. if (!dispatchChannel) {
  221. close(fd);
  222. if (callback) callback([[NSError alloc] initWithDomain:@"PTError" code:0 userInfo:nil], nil);
  223. return;
  224. }
  225. // Success
  226. NSError *err = nil;
  227. Lookin_PTAddress *ptAddr = [[Lookin_PTAddress alloc] initWithSockaddr:(struct sockaddr_storage*)&addr];
  228. [self startReadingFromConnectedChannel:dispatchChannel error:&err];
  229. if (callback) callback(err, ptAddr);
  230. }
  231. #pragma mark - Listening and serving
  232. - (void)listenOnPort:(in_port_t)port IPv4Address:(in_addr_t)address callback:(void(^)(NSError *error))callback {
  233. assert(dispatchObj_source_ == nil);
  234. // Create socket
  235. dispatch_fd_t fd = socket(AF_INET, SOCK_STREAM, 0);
  236. if (fd == -1) {
  237. if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
  238. return;
  239. }
  240. // Connect socket
  241. struct sockaddr_in addr;
  242. bzero((char *)&addr, sizeof(addr));
  243. addr.sin_family = AF_INET;
  244. addr.sin_port = htons(port);
  245. //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  246. //addr.sin_addr.s_addr = htonl(INADDR_ANY);
  247. addr.sin_addr.s_addr = htonl(address);
  248. socklen_t socklen = sizeof(addr);
  249. int on = 1;
  250. if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
  251. close(fd);
  252. if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
  253. return;
  254. }
  255. if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
  256. close(fd);
  257. if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
  258. return;
  259. }
  260. if (bind(fd, (struct sockaddr*)&addr, socklen) != 0) {
  261. close(fd);
  262. if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
  263. return;
  264. }
  265. if (listen(fd, 512) != 0) {
  266. close(fd);
  267. if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
  268. return;
  269. }
  270. [self setDispatchSource:dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, protocol_.queue)];
  271. dispatch_source_set_event_handler(dispatchObj_source_, ^{
  272. unsigned long nconns = dispatch_source_get_data(self->dispatchObj_source_);
  273. while ([self acceptIncomingConnection:fd] && --nconns);
  274. });
  275. dispatch_source_set_cancel_handler(dispatchObj_source_, ^{
  276. // Captures *self*, effectively holding a reference to *self* until cancelled.
  277. self->dispatchObj_source_ = nil;
  278. close(fd);
  279. if (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
  280. [self->delegate_ ioFrameChannel:self didEndWithError:self->endError_];
  281. self->endError_ = nil;
  282. }
  283. });
  284. dispatch_resume(dispatchObj_source_);
  285. //NSLog(@"%@ opened on fd #%d", self, fd);
  286. connState_ = kConnStateListening;
  287. if (callback) callback(nil);
  288. }
  289. - (BOOL)acceptIncomingConnection:(dispatch_fd_t)serverSocketFD {
  290. struct sockaddr_in addr;
  291. socklen_t addrLen = sizeof(addr);
  292. dispatch_fd_t clientSocketFD = accept(serverSocketFD, (struct sockaddr*)&addr, &addrLen);
  293. if (clientSocketFD == -1) {
  294. perror("accept()");
  295. return NO;
  296. }
  297. // prevent SIGPIPE
  298. int on = 1;
  299. setsockopt(clientSocketFD, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
  300. if (fcntl(clientSocketFD, F_SETFL, O_NONBLOCK) == -1) {
  301. perror("fcntl(.. O_NONBLOCK)");
  302. close(clientSocketFD);
  303. return NO;
  304. }
  305. if (delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didAcceptConnection_fromAddress) {
  306. Lookin_PTChannel *peerChannel = [[Lookin_PTChannel alloc] initWithProtocol:protocol_ delegate:delegate_];
  307. __block Lookin_PTChannel *localChannelRef = self;
  308. dispatch_io_t dispatchChannel = dispatch_io_create(DISPATCH_IO_STREAM, clientSocketFD, protocol_.queue, ^(int error) {
  309. // Important note: This block captures *self*, thus a reference is held to
  310. // *self* until the fd is truly closed.
  311. localChannelRef = nil;
  312. close(clientSocketFD);
  313. if (peerChannel->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
  314. NSError *err = error == 0 ? peerChannel->endError_ : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil];
  315. [peerChannel->delegate_ ioFrameChannel:peerChannel didEndWithError:err];
  316. peerChannel->endError_ = nil;
  317. }
  318. });
  319. [peerChannel setConnState:kConnStateConnected];
  320. [peerChannel setDispatchChannel:dispatchChannel];
  321. assert(((struct sockaddr_storage*)&addr)->ss_len == addrLen);
  322. Lookin_PTAddress *address = [[Lookin_PTAddress alloc] initWithSockaddr:(struct sockaddr_storage*)&addr];
  323. [delegate_ ioFrameChannel:self didAcceptConnection:peerChannel fromAddress:address];
  324. NSError *err = nil;
  325. if (![peerChannel startReadingFromConnectedChannel:dispatchChannel error:&err]) {
  326. NSLog(@"startReadingFromConnectedChannel failed in accept: %@", err);
  327. }
  328. } else {
  329. close(clientSocketFD);
  330. }
  331. return YES;
  332. }
  333. #pragma mark - Closing the channel
  334. - (void)close {
  335. if ((connState_ == kConnStateConnecting || connState_ == kConnStateConnected) && dispatchObj_channel_) {
  336. dispatch_io_close(dispatchObj_channel_, DISPATCH_IO_STOP);
  337. [self setDispatchChannel:NULL];
  338. } else if (connState_ == kConnStateListening && dispatchObj_source_) {
  339. dispatch_source_cancel(dispatchObj_source_);
  340. }
  341. }
  342. - (void)cancel {
  343. if ((connState_ == kConnStateConnecting || connState_ == kConnStateConnected) && dispatchObj_channel_) {
  344. dispatch_io_close(dispatchObj_channel_, 0);
  345. [self setDispatchChannel:NULL];
  346. } else if (connState_ == kConnStateListening && dispatchObj_source_) {
  347. dispatch_source_cancel(dispatchObj_source_);
  348. }
  349. }
  350. #pragma mark - Reading
  351. - (BOOL)startReadingFromConnectedChannel:(dispatch_io_t)channel error:(__autoreleasing NSError**)error {
  352. if (connState_ != kConnStateNone && connState_ != kConnStateConnecting && connState_ != kConnStateConnected) {
  353. if (error) *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil];
  354. return NO;
  355. }
  356. if (dispatchObj_channel_ != channel) {
  357. [self close];
  358. [self setDispatchChannel:channel];
  359. }
  360. connState_ = kConnStateConnected;
  361. // helper
  362. BOOL(^handleError)(NSError*,BOOL) = ^BOOL(NSError *error, BOOL isEOS) {
  363. if (error) {
  364. //NSLog(@"Error while communicating: %@", error);
  365. self->endError_ = error;
  366. [self close];
  367. return YES;
  368. } else if (isEOS) {
  369. [self cancel];
  370. return YES;
  371. }
  372. return NO;
  373. };
  374. [protocol_ readFramesOverChannel:channel onFrame:^(NSError *error, uint32_t type, uint32_t tag, uint32_t payloadSize, dispatch_block_t resumeReadingFrames) {
  375. if (handleError(error, type == PTFrameTypeEndOfStream)) {
  376. return;
  377. }
  378. BOOL accepted = (channel == self->dispatchObj_channel_);
  379. if (accepted && (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_shouldAcceptFrameOfType_tag_payloadSize)) {
  380. accepted = [self->delegate_ ioFrameChannel:self shouldAcceptFrameOfType:type tag:tag payloadSize:payloadSize];
  381. }
  382. if (payloadSize == 0) {
  383. if (accepted && self->delegate_) {
  384. [self->delegate_ ioFrameChannel:self didReceiveFrameOfType:type tag:tag payload:nil];
  385. } else {
  386. // simply ignore the frame
  387. }
  388. resumeReadingFrames();
  389. } else {
  390. // has payload
  391. if (!accepted) {
  392. // Read and discard payload, ignoring frame
  393. [self->protocol_ readAndDiscardDataOfSize:payloadSize overChannel:channel callback:^(NSError *error, BOOL endOfStream) {
  394. if (!handleError(error, endOfStream)) {
  395. resumeReadingFrames();
  396. }
  397. }];
  398. } else {
  399. [self->protocol_ readPayloadOfSize:payloadSize overChannel:channel callback:^(NSError *error, dispatch_data_t contiguousData, const uint8_t *buffer, size_t bufferSize) {
  400. if (handleError(error, bufferSize == 0)) {
  401. return;
  402. }
  403. if (self->delegate_) {
  404. Lookin_PTData *payload = [[Lookin_PTData alloc] initWithMappedDispatchData:contiguousData data:(void*)buffer length:bufferSize];
  405. [self->delegate_ ioFrameChannel:self didReceiveFrameOfType:type tag:tag payload:payload];
  406. }
  407. resumeReadingFrames();
  408. }];
  409. }
  410. }
  411. }];
  412. return YES;
  413. }
  414. #pragma mark - Sending
  415. - (void)sendFrameOfType:(uint32_t)frameType tag:(uint32_t)tag withPayload:(dispatch_data_t)payload callback:(void(^)(NSError *error))callback {
  416. if (connState_ == kConnStateConnecting || connState_ == kConnStateConnected) {
  417. [protocol_ sendFrameOfType:frameType tag:tag withPayload:payload overChannel:dispatchObj_channel_ callback:callback];
  418. } else if (callback) {
  419. callback([NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil]);
  420. }
  421. }
  422. #pragma mark - NSObject
  423. - (NSString*)description {
  424. id userInfo = objc_getAssociatedObject(self, (void*)&kUserInfoKey);
  425. return [NSString stringWithFormat:@"<Lookin_PTChannel: %p (%@)%s%@>", self, ( connState_ == kConnStateConnecting ? @"connecting"
  426. : connState_ == kConnStateConnected ? @"connected"
  427. : connState_ == kConnStateListening ? @"listening"
  428. : @"closed"),
  429. userInfo ? " " : "", userInfo ? userInfo : @""];
  430. }
  431. @end
  432. #pragma mark -
  433. @implementation Lookin_PTAddress
  434. - (id)initWithSockaddr:(const struct sockaddr_storage*)addr {
  435. if (!(self = [super init])) return nil;
  436. assert(addr);
  437. memcpy((void*)&sockaddr_, (const void*)addr, addr->ss_len);
  438. return self;
  439. }
  440. - (NSString*)name {
  441. if (sockaddr_.ss_len) {
  442. const void *sin_addr = NULL;
  443. size_t bufsize = 0;
  444. if (sockaddr_.ss_family == AF_INET6) {
  445. bufsize = INET6_ADDRSTRLEN;
  446. sin_addr = (const void *)&((const struct sockaddr_in6*)&sockaddr_)->sin6_addr;
  447. } else {
  448. bufsize = INET_ADDRSTRLEN;
  449. sin_addr = (const void *)&((const struct sockaddr_in*)&sockaddr_)->sin_addr;
  450. }
  451. char *buf = CFAllocatorAllocate(kCFAllocatorDefault, bufsize+1, 0);
  452. if (inet_ntop(sockaddr_.ss_family, sin_addr, buf, (unsigned int)bufsize-1) == NULL) {
  453. CFAllocatorDeallocate(kCFAllocatorDefault, buf);
  454. return nil;
  455. }
  456. return [[NSString alloc] initWithBytesNoCopy:(void*)buf length:strlen(buf) encoding:NSUTF8StringEncoding freeWhenDone:YES];
  457. } else {
  458. return nil;
  459. }
  460. }
  461. - (NSInteger)port {
  462. if (sockaddr_.ss_len) {
  463. return ntohs(PT_SOCKADDR_ACCESS(&sockaddr_, sin_port, sin6_port));
  464. } else {
  465. return 0;
  466. }
  467. }
  468. - (NSString*)description {
  469. if (sockaddr_.ss_len) {
  470. return [NSString stringWithFormat:@"%@:%u", self.name, (unsigned)self.port];
  471. } else {
  472. return @"(?)";
  473. }
  474. }
  475. @end
  476. #pragma mark -
  477. @implementation Lookin_PTData
  478. @synthesize dispatchData = dispatchData_;
  479. @synthesize data = data_;
  480. @synthesize length = length_;
  481. - (id)initWithMappedDispatchData:(dispatch_data_t)mappedContiguousData data:(void*)data length:(size_t)length {
  482. if (!(self = [super init])) return nil;
  483. dispatchData_ = mappedContiguousData;
  484. #if PT_DISPATCH_RETAIN_RELEASE
  485. if (dispatchData_) dispatch_retain(dispatchData_);
  486. #endif
  487. data_ = data;
  488. length_ = length;
  489. return self;
  490. }
  491. - (void)dealloc {
  492. #if PT_DISPATCH_RETAIN_RELEASE
  493. if (dispatchData_) dispatch_release(dispatchData_);
  494. #endif
  495. data_ = NULL;
  496. length_ = 0;
  497. }
  498. #pragma mark - NSObject
  499. - (NSString*)description {
  500. return [NSString stringWithFormat:@"<Lookin_PTData: %p (%zu bytes)>", self, length_];
  501. }
  502. @end