PageRenderTime 183ms CodeModel.GetById 37ms RepoModel.GetById 1ms app.codeStats 0ms

/ep-020/test_longpress_pinch/build/iphone/Classes/TiNetworkTCPSocketProxy.mm

https://gitlab.com/intelij/Forging-Titanium
Objective C++ | 761 lines | 604 code | 136 blank | 21 comment | 100 complexity | 3c2c00be19f350656b0d1b3eda75db2b MD5 | raw file
Possible License(s): Apache-2.0
  1. /**
  2. * Appcelerator Titanium Mobile
  3. * Copyright (c) 2009-2012 by Appcelerator, Inc. All Rights Reserved.
  4. * Licensed under the terms of the Apache Public License
  5. * Please see the LICENSE included with this distribution for details.
  6. *
  7. * WARNING: This is generated code. Modify at your own risk and without support.
  8. */
  9. #ifdef USE_TI_NETWORK
  10. #import "TiNetworkTCPSocketProxy.h"
  11. #import <sys/socket.h>
  12. #import <netinet/in.h>
  13. #import <netdb.h>
  14. #include <CFNetwork/CFSocketStream.h>
  15. extern NSString* const INADDR_ANY_token;
  16. #pragma mark Forward declarations
  17. // Size of the read buffer; ideally should be a multiple of 1024 (1k), up to 4096 (4k, page size)
  18. const NSUInteger bufferSize = 4096;
  19. // TODO: Add host information for better error reporting
  20. typedef struct {
  21. CFReadStreamRef inputStream;
  22. CFWriteStreamRef outputStream;
  23. NSRecursiveLock* writeLock;
  24. NSMutableArray* writeBuffer;
  25. NSUInteger bufferPos;
  26. } SocketStreams;
  27. void handleSocketConnection(CFSocketRef socket, CFSocketCallBackType type,
  28. CFDataRef address, const void* data, void* info);
  29. void handleReadData(CFReadStreamRef input,
  30. CFStreamEventType event,
  31. void* info);
  32. void handleWriteData(CFWriteStreamRef input,
  33. CFStreamEventType event,
  34. void* info);
  35. const CFOptionFlags readStreamEventFlags =
  36. kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered | kCFStreamEventOpenCompleted;
  37. const CFOptionFlags writeStreamEventFlags =
  38. kCFStreamEventCanAcceptBytes | kCFStreamEventErrorOccurred | kCFStreamEventOpenCompleted;
  39. @implementation TiNetworkTCPSocketProxy
  40. #pragma mark Macros
  41. #define VALID (socket!=NULL) && [[self isValid] boolValue]
  42. #pragma mark Private
  43. -(void)closeRemoteSocket:(CFSocketNativeHandle)remoteSocket
  44. {
  45. NSNumber* remoteSocketObject = [NSNumber numberWithInt:remoteSocket];
  46. NSData* socketStreamsObject = [remoteSocketDictionary objectForKey:remoteSocketObject];
  47. SocketStreams* streams = (SocketStreams*)[socketStreamsObject bytes];
  48. if (streams->inputStream) {
  49. if (!(CFReadStreamGetStatus(streams->inputStream) == kCFStreamStatusClosed)) {
  50. CFReadStreamClose(streams->inputStream);
  51. }
  52. CFRelease(streams->inputStream);
  53. }
  54. if (streams->outputStream) {
  55. if (!(CFWriteStreamGetStatus(streams->outputStream) == kCFStreamStatusClosed)) {
  56. CFWriteStreamClose(streams->outputStream);
  57. }
  58. CFRelease(streams->outputStream);
  59. }
  60. [streams->writeBuffer release];
  61. [streams->writeLock release];
  62. [remoteSocketDictionary removeObjectForKey:remoteSocketObject];
  63. }
  64. -(CFDataRef)createAddressData
  65. {
  66. struct sockaddr_in address;
  67. memset(&address, 0, sizeof(address)); // THIS is the finnicky bit: sockaddr_in needs to have 8 bytes of 0 at the end to be compatible with sockaddr
  68. address.sin_len = sizeof(address);
  69. address.sin_port = htons(port);
  70. address.sin_family = AF_INET;
  71. if ([hostName isEqual:INADDR_ANY_token]) {
  72. address.sin_addr.s_addr = htonl(INADDR_ANY);
  73. }
  74. else {
  75. struct hostent *host;
  76. host = gethostbyname([hostName cStringUsingEncoding:[NSString defaultCStringEncoding]]);
  77. if (host == NULL) {
  78. if (socket) {
  79. CFSocketInvalidate(socket);
  80. CFRelease(socket);
  81. socket = NULL;
  82. }
  83. [self throwException:[NSString stringWithFormat:@"Couldn't resolve host %@: %d", hostName, h_errno]
  84. subreason:nil
  85. location:CODELOCATION];
  86. }
  87. memcpy(&address.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
  88. }
  89. return CFDataCreate(kCFAllocatorDefault,
  90. (UInt8*)&address,
  91. sizeof(address));
  92. }
  93. -(void)configureSocketForHandle:(CFSocketNativeHandle)fd
  94. {
  95. if (socket) {
  96. return; // Socket already configured, either by listener or previous action
  97. }
  98. socket = CFSocketCreateWithNative(NULL,
  99. fd,
  100. kCFSocketNoCallBack,
  101. NULL,
  102. NULL);
  103. CFSocketSetSocketFlags(socket, CFSocketGetSocketFlags(socket) & ~kCFSocketCloseOnInvalidate);
  104. }
  105. -(void)handleError:(NSStream*)stream
  106. {
  107. NSError* error = [stream streamError];
  108. NSString* event = ([stream isKindOfClass:[NSInputStream class]]) ? @"readError" : @"writeError";
  109. [stream close];
  110. [configureCondition lock];
  111. [configureCondition signal];
  112. [configureCondition unlock];
  113. [self fireEvent:event
  114. withObject:[NSDictionary dictionaryWithObjectsAndKeys:[error localizedDescription], @"error",
  115. [NSNumber numberWithInt:[error code]], @"code",
  116. nil]];
  117. }
  118. -(CFSocketNativeHandle)getHandleFromStream:(NSStream*)stream
  119. {
  120. CFSocketNativeHandle remoteSocket;
  121. CFDataRef remoteSocketData;
  122. if ([stream isKindOfClass:[NSInputStream class]]) {
  123. remoteSocketData = (CFDataRef)CFReadStreamCopyProperty((CFReadStreamRef)stream, kCFStreamPropertySocketNativeHandle);
  124. }
  125. else {
  126. remoteSocketData = (CFDataRef)CFWriteStreamCopyProperty((CFWriteStreamRef)stream, kCFStreamPropertySocketNativeHandle);
  127. }
  128. if (remoteSocketData == NULL) {
  129. return -1;
  130. }
  131. CFDataGetBytes(remoteSocketData, CFRangeMake(0, CFDataGetLength(remoteSocketData)), (UInt8*)&remoteSocket);
  132. CFRelease(remoteSocketData);
  133. return remoteSocket;
  134. }
  135. -(void)initializeReadStream:(NSInputStream*)input
  136. {
  137. CFSocketNativeHandle remoteSocket = [self getHandleFromStream:input];
  138. if (remoteSocket == -1) {
  139. [self handleError:input];
  140. return;
  141. }
  142. SocketStreams* streams =
  143. (SocketStreams*)[[remoteSocketDictionary objectForKey:[NSNumber numberWithInt:remoteSocket]] bytes];
  144. if (!streams) {
  145. streams = (SocketStreams*)malloc(sizeof(SocketStreams));
  146. streams->outputStream = NULL;
  147. streams->writeBuffer = nil;
  148. streams->writeLock = nil;
  149. [remoteSocketDictionary setObject:[NSData dataWithBytesNoCopy:streams length:sizeof(SocketStreams)]
  150. forKey:[NSNumber numberWithInt:remoteSocket]];
  151. }
  152. streams->inputStream = (CFReadStreamRef)input;
  153. CFReadStreamSetProperty((CFReadStreamRef)input, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
  154. [self configureSocketForHandle:remoteSocket];
  155. if (mode && WRITE_MODE) {
  156. if (streams->outputStream) {
  157. [configureCondition lock];
  158. [configureCondition signal];
  159. [configureCondition unlock];
  160. }
  161. }
  162. else {
  163. [configureCondition lock];
  164. [configureCondition signal];
  165. [configureCondition unlock];
  166. }
  167. }
  168. -(void)initializeWriteStream:(NSOutputStream*)output
  169. {
  170. CFSocketNativeHandle remoteSocket = [self getHandleFromStream:output];
  171. if (remoteSocket == -1) {
  172. [self handleError:output];
  173. return;
  174. }
  175. SocketStreams* streams =
  176. (SocketStreams*)[[remoteSocketDictionary objectForKey:[NSNumber numberWithInt:remoteSocket]] bytes];
  177. if (!streams) {
  178. streams = (SocketStreams*)malloc(sizeof(SocketStreams));
  179. streams->inputStream = NULL;
  180. [remoteSocketDictionary setObject:[NSData dataWithBytesNoCopy:streams length:sizeof(SocketStreams)]
  181. forKey:[NSNumber numberWithInt:remoteSocket]];
  182. }
  183. streams->outputStream = (CFWriteStreamRef)output;
  184. streams->writeBuffer = [[NSMutableArray alloc] init];
  185. streams->writeLock = [[NSRecursiveLock alloc] init];
  186. streams->bufferPos = 0;
  187. CFWriteStreamSetProperty((CFWriteStreamRef)output, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
  188. [self configureSocketForHandle:remoteSocket];
  189. if (mode && READ_MODE) {
  190. if (streams->inputStream) {
  191. [configureCondition lock];
  192. [configureCondition signal];
  193. [configureCondition unlock];
  194. }
  195. }
  196. else {
  197. [configureCondition lock];
  198. [configureCondition signal];
  199. [configureCondition unlock];
  200. }
  201. }
  202. -(void)readFromStream:(NSInputStream*)input
  203. {
  204. CFSocketNativeHandle remoteSocket = [self getHandleFromStream:input];
  205. if (remoteSocket == -1) {
  206. [self handleError:input];
  207. return;
  208. }
  209. // We can't just use -[NSInputStream getBuffer:length:] because the input stream is secretly
  210. // based on sockets, according to the CFReadStream it comes from.
  211. // NOTE: Without sentenels, this could result in some weird behavior (for example, if two images are transmitted back-to-back with no break).
  212. NSMutableData* data = [[[NSMutableData alloc] init] autorelease];
  213. while ([input hasBytesAvailable]) {
  214. uint8_t* buffer = (uint8_t*)malloc(bufferSize * sizeof(uint8_t));
  215. NSInteger bytesRead = [input read:buffer maxLength:bufferSize];
  216. // Not clear whether the failure condition is 0 or -1 from documentation
  217. if (bytesRead == 0 || bytesRead == -1) {
  218. free(buffer);
  219. [self handleError:input];
  220. return;
  221. }
  222. [data appendBytes:buffer length:bytesRead];
  223. free(buffer);
  224. }
  225. TiBlob* dataBlob = [[[TiBlob alloc] initWithData:data mimetype:@"application/octet-stream"] autorelease];
  226. [self fireEvent:@"read" withObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:remoteSocket], @"from",
  227. dataBlob, @"data",
  228. nil]];
  229. }
  230. -(void)writeToStream:(NSOutputStream*)output
  231. {
  232. CFSocketNativeHandle remoteSocket = [self getHandleFromStream:output];
  233. if (remoteSocket == -1) {
  234. [self handleError:output];
  235. return;
  236. }
  237. SocketStreams* streams =
  238. (SocketStreams*)[[remoteSocketDictionary objectForKey:[NSNumber numberWithInt:remoteSocket]] bytes];
  239. [streams->writeLock lock];
  240. if ([streams->writeBuffer count] == 0) {
  241. [streams->writeLock unlock];
  242. return;
  243. }
  244. do {
  245. NSInteger wroteBytes = 0;
  246. NSData* data = [streams->writeBuffer objectAtIndex:0];
  247. const uint8_t* startPos = (const uint8_t*)[data bytes] + streams->bufferPos;
  248. NSUInteger length = [data length] - streams->bufferPos;
  249. wroteBytes = [output write:startPos maxLength:length];
  250. if (wroteBytes == -1) {
  251. [self handleError:output];
  252. [streams->writeLock unlock];
  253. break;
  254. }
  255. if (wroteBytes != length) {
  256. streams->bufferPos += wroteBytes;
  257. }
  258. else {
  259. [streams->writeBuffer removeObjectAtIndex:0];
  260. streams->bufferPos = 0;
  261. }
  262. } while ([output hasSpaceAvailable] &&
  263. streams->bufferPos == 0 &&
  264. [streams->writeBuffer count] > 0);
  265. [streams->writeLock unlock];
  266. }
  267. #pragma mark Public
  268. -(void)_configure
  269. {
  270. [super _configure];
  271. socket = NULL;
  272. remoteSocketDictionary = [[NSMutableDictionary alloc] init];
  273. configureCondition = [[NSCondition alloc] init];
  274. mode = READ_WRITE_MODE;
  275. }
  276. -(void)_destroy
  277. {
  278. if (VALID) {
  279. [self close:nil];
  280. }
  281. RELEASE_TO_NIL(hostName);
  282. RELEASE_TO_NIL(remoteSocketDictionary);
  283. RELEASE_TO_NIL(configureCondition);
  284. [super _destroy];
  285. }
  286. -(NSNumber*)mode
  287. {
  288. return [NSNumber numberWithInt:mode];
  289. }
  290. -(void)setMode:(NSNumber*)mode_
  291. {
  292. switch ([mode_ intValue]) {
  293. case READ_MODE:
  294. case WRITE_MODE:
  295. case READ_WRITE_MODE:
  296. mode = (SocketMode)[mode_ intValue];
  297. break;
  298. default:
  299. [self throwException:TiExceptionRangeError
  300. subreason:@"Invalid socket mode"
  301. location:CODELOCATION];
  302. break;
  303. }
  304. }
  305. -(NSString*)hostName
  306. {
  307. return hostName;
  308. }
  309. -(void)setHostName:(NSString*)hostName_
  310. {
  311. if (hostName == hostName_) {
  312. return;
  313. }
  314. [hostName release];
  315. hostName = [hostName_ retain];
  316. }
  317. -(NSNumber*)port
  318. {
  319. return [NSNumber numberWithInt:port];
  320. }
  321. -(void)setPort:(NSNumber*)port_
  322. {
  323. port = [port_ intValue];
  324. }
  325. -(void)setStripTerminator:(NSNumber *)stripTerminator_
  326. {
  327. stripTerminator = [TiUtils boolValue:stripTerminator_ def:NO];
  328. }
  329. -(NSNumber*)stripTerminator
  330. {
  331. return NUMBOOL(stripTerminator);
  332. }
  333. -(NSNumber*)isValid
  334. {
  335. if (socket!=NULL) {
  336. return [NSNumber numberWithBool:CFSocketIsValid(socket)];
  337. }
  338. return [NSNumber numberWithBool:false];
  339. }
  340. -(void)listen:(id)unused
  341. {
  342. if (VALID) {
  343. [self throwException:@"Socket already opened"
  344. subreason:nil
  345. location:CODELOCATION];
  346. }
  347. if (hostName == nil) {
  348. [self throwException:@"Host is null"
  349. subreason:nil
  350. location:CODELOCATION];
  351. }
  352. CFSocketContext socketContext;
  353. socketContext.version = 0;
  354. socketContext.info = self;
  355. socketContext.retain = NULL;
  356. socketContext.release = NULL;
  357. socketContext.copyDescription = NULL;
  358. // SocketContext is copied
  359. socket = CFSocketCreate(kCFAllocatorDefault,
  360. PF_INET,
  361. SOCK_STREAM,
  362. IPPROTO_TCP,
  363. kCFSocketAcceptCallBack,
  364. handleSocketConnection,
  365. &socketContext);
  366. if (!socket) {
  367. [self throwException:[NSString stringWithFormat:@"Failed to create socket: %d", errno]
  368. subreason:nil
  369. location:CODELOCATION];
  370. }
  371. CFDataRef addressData = (CFDataRef)[self createAddressData];
  372. int reuseOn = 1;
  373. setsockopt(CFSocketGetNative(socket), SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
  374. setsockopt(CFSocketGetNative(socket), SOL_SOCKET, SO_REUSEPORT, &reuseOn, sizeof(reuseOn));
  375. CFSocketError sockError = CFSocketSetAddress(socket,
  376. addressData);
  377. switch (sockError) {
  378. case kCFSocketError: {
  379. CFSocketInvalidate(socket);
  380. CFRelease(socket);
  381. socket = NULL;
  382. CFRelease(addressData);
  383. [self throwException:[NSString stringWithFormat:@"Failed to listen on %@:%d: %d", hostName, port, errno]
  384. subreason:nil
  385. location:CODELOCATION];
  386. break;
  387. }
  388. }
  389. CFRelease(addressData);
  390. socketRunLoop = CFSocketCreateRunLoopSource(kCFAllocatorDefault,
  391. socket,
  392. 1);
  393. CFRunLoopAddSource(CFRunLoopGetMain(),
  394. socketRunLoop,
  395. kCFRunLoopCommonModes);
  396. }
  397. -(void)connect:(id)unused
  398. {
  399. if (VALID) {
  400. [self throwException:@"Socket already opened"
  401. subreason:nil
  402. location:CODELOCATION];
  403. }
  404. if (hostName == nil) {
  405. [self throwException:@"Host is null"
  406. subreason:nil
  407. location:CODELOCATION];
  408. }
  409. CFSocketSignature signature;
  410. signature.protocolFamily = PF_INET;
  411. signature.socketType = SOCK_STREAM;
  412. signature.protocol = IPPROTO_TCP;
  413. signature.address = [self createAddressData]; // Follows create rule; clean up later
  414. CFReadStreamRef inputStream;
  415. CFWriteStreamRef outputStream;
  416. CFStreamCreatePairWithPeerSocketSignature(NULL,
  417. &signature,
  418. (mode & READ_MODE) ? &inputStream : NULL,
  419. (mode & WRITE_MODE) ? &outputStream : NULL);
  420. CFStreamClientContext context;
  421. context.version = 0;
  422. context.info = self;
  423. context.retain = NULL;
  424. context.release = NULL;
  425. context.copyDescription = NULL;
  426. // TODO: Do we catch errors in the stream opening because the stream FD will be NULL in the callback?
  427. if (mode & READ_MODE) {
  428. CFReadStreamSetClient(inputStream, readStreamEventFlags | kCFStreamEventOpenCompleted, handleReadData, &context);
  429. CFReadStreamScheduleWithRunLoop(inputStream, CFRunLoopGetMain(), kCFRunLoopCommonModes);
  430. CFReadStreamOpen(inputStream);
  431. }
  432. if (mode & WRITE_MODE) {
  433. CFWriteStreamSetClient(outputStream, writeStreamEventFlags | kCFStreamEventOpenCompleted, handleWriteData, &context);
  434. CFWriteStreamScheduleWithRunLoop(outputStream, CFRunLoopGetMain(), kCFRunLoopCommonModes);
  435. CFWriteStreamOpen(outputStream);
  436. }
  437. CFRelease(signature.address);
  438. if (!VALID &&
  439. !(inputStream && (CFReadStreamGetStatus(inputStream) == kCFStreamStatusError)) &&
  440. !(outputStream && (CFWriteStreamGetStatus(outputStream) == kCFStreamStatusError))) {
  441. [configureCondition lock];
  442. [configureCondition wait];
  443. [configureCondition unlock];
  444. }
  445. }
  446. -(void)close:(id)unused
  447. {
  448. @synchronized(self)
  449. {
  450. if (!VALID) {
  451. [self throwException:@"Socket is not open"
  452. subreason:nil
  453. location:CODELOCATION];
  454. }
  455. if (socketRunLoop!=NULL)
  456. {
  457. CFRunLoopRemoveSource(CFRunLoopGetMain(),
  458. socketRunLoop,
  459. kCFRunLoopCommonModes);
  460. CFRelease(socketRunLoop);
  461. socketRunLoop=NULL;
  462. }
  463. NSEnumerator* keys = [[remoteSocketDictionary allKeys] objectEnumerator];
  464. id remoteSocketObject;
  465. // Shut down all of the streams and remote connections
  466. while ((remoteSocketObject = [keys nextObject]))
  467. {
  468. CFSocketNativeHandle remoteSocket = [remoteSocketObject intValue];
  469. [self closeRemoteSocket:remoteSocket];
  470. }
  471. if (socket!=NULL)
  472. {
  473. CFSocketInvalidate(socket);
  474. CFRelease(socket);
  475. }
  476. socket = NULL;
  477. }
  478. }
  479. -(void)write:(id)args;
  480. {
  481. if (!(mode & WRITE_MODE)) {
  482. [self throwException:@"Socket does not support writing"
  483. subreason:nil
  484. location:CODELOCATION];
  485. }
  486. else if (!VALID) {
  487. [self throwException:@"Socket is invalid"
  488. subreason:nil
  489. location:CODELOCATION];
  490. }
  491. NSData* data = nil;
  492. id arg = [args objectAtIndex:0];
  493. if ([arg isKindOfClass:[TiBlob class]]) {
  494. data = [arg data];
  495. }
  496. else if ([arg isKindOfClass:[NSString class]]) {
  497. NSUInteger length = (stripTerminator) ? [arg length] : [arg length] + 1;
  498. data = [NSData dataWithBytes:[arg UTF8String] length:length];
  499. }
  500. else {
  501. NSString* errorStr = [NSString stringWithFormat:@"expected: %@ or %@, was: %@", [TiBlob class], [NSString class], [arg class]];
  502. THROW_INVALID_ARG(errorStr)
  503. }
  504. NSNumber* key = nil;
  505. NSEnumerator* keyEnum = [[remoteSocketDictionary allKeys] objectEnumerator];
  506. BOOL broadcast = YES;
  507. if ([args count] > 1) {
  508. ENSURE_CLASS([args objectAtIndex:1], [NSNumber class])
  509. key = [args objectAtIndex:1];
  510. broadcast = NO;
  511. }
  512. else {
  513. key = [keyEnum nextObject];
  514. // Short-circut to avoid degenerate case where there are 0 sockets attached to a listener
  515. if (key == nil) {
  516. return;
  517. }
  518. }
  519. do {
  520. NSData* streamData = [remoteSocketDictionary objectForKey:key];
  521. if (streamData == nil) {
  522. [self throwException:[NSString stringWithFormat:@"Invalid socket descriptor (%@)", key]
  523. subreason:nil
  524. location:CODELOCATION];
  525. }
  526. SocketStreams* streams = (SocketStreams*)[streamData bytes];
  527. if (streams->writeBuffer == nil) {
  528. [configureCondition lock];
  529. [configureCondition wait];
  530. [configureCondition unlock];
  531. }
  532. [streams->writeLock lock];
  533. [streams->writeBuffer addObject:data];
  534. if (CFWriteStreamCanAcceptBytes(streams->outputStream)) {
  535. [self writeToStream:(NSOutputStream*)(streams->outputStream)];
  536. }
  537. [streams->writeLock unlock];
  538. } while (broadcast && (key = [keyEnum nextObject]));
  539. }
  540. @end
  541. #pragma mark CFSocket/CFStream data handling
  542. void handleSocketConnection(CFSocketRef socket, CFSocketCallBackType type,
  543. CFDataRef address, const void* data, void* info) {
  544. switch (type) {
  545. case kCFSocketAcceptCallBack: {
  546. TiNetworkTCPSocketProxy* hostSocket = (TiNetworkTCPSocketProxy*)info;
  547. CFSocketNativeHandle sock = *(CFSocketNativeHandle*)data;
  548. CFReadStreamRef inputStream;
  549. CFWriteStreamRef outputStream;
  550. SocketMode mode = (SocketMode)[[hostSocket mode] intValue];
  551. CFStreamCreatePairWithSocket(kCFAllocatorDefault,
  552. sock,
  553. (mode & READ_MODE) ? &inputStream : NULL,
  554. (mode & WRITE_MODE) ? &outputStream : NULL);
  555. CFStreamClientContext context;
  556. context.version = 0;
  557. context.info = hostSocket;
  558. context.retain = NULL;
  559. context.release = NULL;
  560. context.copyDescription = NULL;
  561. if (mode & READ_MODE) {
  562. CFReadStreamSetClient(inputStream, readStreamEventFlags, handleReadData, &context);
  563. CFReadStreamScheduleWithRunLoop(inputStream, CFRunLoopGetMain(), kCFRunLoopCommonModes);
  564. CFReadStreamOpen(inputStream);
  565. }
  566. if (mode & WRITE_MODE) {
  567. CFWriteStreamSetClient(outputStream, writeStreamEventFlags, handleWriteData, &context);
  568. CFWriteStreamScheduleWithRunLoop(outputStream, CFRunLoopGetMain(), kCFRunLoopCommonModes);
  569. CFWriteStreamOpen(outputStream);
  570. }
  571. break;
  572. }
  573. }
  574. }
  575. void handleReadData(CFReadStreamRef input,
  576. CFStreamEventType event,
  577. void* info)
  578. {
  579. TiNetworkTCPSocketProxy* hostSocket = (TiNetworkTCPSocketProxy*)info;
  580. switch (event) {
  581. case kCFStreamEventOpenCompleted: {
  582. [hostSocket initializeReadStream:(NSInputStream*)input];
  583. break;
  584. }
  585. case kCFStreamEventEndEncountered: {
  586. CFSocketNativeHandle remoteSocket = [hostSocket getHandleFromStream:(NSInputStream*)input];
  587. if (remoteSocket != -1) {
  588. [hostSocket closeRemoteSocket:remoteSocket];
  589. }
  590. break;
  591. }
  592. // There's not very much information you can get out of an error like this, other than
  593. // that it occurred. It's not recoverable without the direct stream information, most likely.
  594. case kCFStreamEventErrorOccurred: {
  595. [hostSocket handleError:(NSInputStream*)input];
  596. break;
  597. }
  598. // This event is NOT necessarily fired until all current available data has been read. Gotta clear that buffer first!
  599. case kCFStreamEventHasBytesAvailable: {
  600. [hostSocket readFromStream:(NSInputStream*)input];
  601. break;
  602. }
  603. }
  604. }
  605. void handleWriteData(CFWriteStreamRef output,
  606. CFStreamEventType event,
  607. void* info)
  608. {
  609. TiNetworkTCPSocketProxy* hostSocket = (TiNetworkTCPSocketProxy*)info;
  610. switch (event) {
  611. case kCFStreamEventOpenCompleted: {
  612. [hostSocket initializeWriteStream:(NSOutputStream*)output];
  613. break;
  614. }
  615. case kCFStreamEventErrorOccurred: {
  616. [hostSocket handleError:(NSOutputStream*)output];
  617. break;
  618. }
  619. case kCFStreamEventCanAcceptBytes: {
  620. [hostSocket writeToStream:(NSOutputStream*)output];
  621. break;
  622. }
  623. }
  624. }
  625. #endif