Lookin_PTChannel.m 20 KB

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