Lookin_PTChannel.m 21 KB

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