From 12e617112b29bed67aa1a2921f3fc67921e6b87b Mon Sep 17 00:00:00 2001 From: Saurabh Sawant Date: Fri, 30 Nov 2018 11:54:13 +0530 Subject: [PATCH] Resolves PeelTechnologies#86 --- ios/CocoaAsyncSocket/GCDAsyncSocket.h | 2 - ios/CocoaAsyncSocket/GCDAsyncSocket.m | 15 +--- ios/TcpSocketClient.h | 10 +-- ios/TcpSocketClient.m | 106 +++----------------------- ios/TcpSockets.h | 0 ios/TcpSockets.m | 94 ++++++++++++++--------- 6 files changed, 75 insertions(+), 152 deletions(-) mode change 100644 => 100755 ios/CocoaAsyncSocket/GCDAsyncSocket.h mode change 100644 => 100755 ios/CocoaAsyncSocket/GCDAsyncSocket.m mode change 100644 => 100755 ios/TcpSocketClient.h mode change 100644 => 100755 ios/TcpSocketClient.m mode change 100644 => 100755 ios/TcpSockets.h mode change 100644 => 100755 ios/TcpSockets.m diff --git a/ios/CocoaAsyncSocket/GCDAsyncSocket.h b/ios/CocoaAsyncSocket/GCDAsyncSocket.h old mode 100644 new mode 100755 index ab89543..828951f --- a/ios/CocoaAsyncSocket/GCDAsyncSocket.h +++ b/ios/CocoaAsyncSocket/GCDAsyncSocket.h @@ -790,8 +790,6 @@ typedef NS_ENUM(NSInteger, GCDAsyncSocketError) { **/ - (void)startTLS:(nullable NSDictionary *)tlsSettings; -- (void)startTLSCancelCurrentRead:(nullable NSDictionary *)tlsSettings; - #pragma mark Advanced /** diff --git a/ios/CocoaAsyncSocket/GCDAsyncSocket.m b/ios/CocoaAsyncSocket/GCDAsyncSocket.m old mode 100644 new mode 100755 index 8c34008..abf2a8a --- a/ios/CocoaAsyncSocket/GCDAsyncSocket.m +++ b/ios/CocoaAsyncSocket/GCDAsyncSocket.m @@ -6407,7 +6407,7 @@ - (void)doWriteTimeoutWithExtension:(NSTimeInterval)timeoutExtension #pragma mark Security //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -- (void)doStartTLS:(NSDictionary *)tlsSettings withCancelCurrentRead:(BOOL)cancelCurrentRead +- (void)startTLS:(NSDictionary *)tlsSettings { LogTrace(); @@ -6430,11 +6430,6 @@ - (void)doStartTLS:(NSDictionary *)tlsSettings withCancelCurrentRead:(BOOL)cance if ((flags & kSocketStarted) && !(flags & kQueuedTLS) && !(flags & kForbidReadsWrites)) { - // dirty hack to fix that the client has already added a read with no timeout which we need to finish - if (currentRead && cancelCurrentRead) { - LogInfo(@"Cancelling current read as requested"); - [self completeCurrentRead]; - } [readQueue addObject:packet]; [writeQueue addObject:packet]; @@ -6447,14 +6442,6 @@ - (void)doStartTLS:(NSDictionary *)tlsSettings withCancelCurrentRead:(BOOL)cance } -- (void)startTLSCancelCurrentRead:(NSDictionary *)tlsSettings -{ - [self doStartTLS:tlsSettings withCancelCurrentRead:TRUE]; -} -- (void)startTLS:(NSDictionary *)tlsSettings { - [self doStartTLS:tlsSettings withCancelCurrentRead:FALSE]; -} - - (void)maybeStartTLS { // We can't start TLS until: diff --git a/ios/TcpSocketClient.h b/ios/TcpSocketClient.h old mode 100644 new mode 100755 index dda7fd2..a4eff2a --- a/ios/TcpSocketClient.h +++ b/ios/TcpSocketClient.h @@ -31,7 +31,10 @@ typedef enum RCTTCPError RCTTCPError; - (void)onData:(NSNumber *)clientID data:(NSData *)data; - (void)onClose:(TcpSocketClient*)client withError:(NSError *)err; - (void)onError:(TcpSocketClient*)client withError:(NSError *)err; -- (void)onSecureConnect:(TcpSocketClient*)client; +- (NSNumber*)getNextTag; +- (void)setPendingSend:(RCTResponseSenderBlock)callback forKey:(NSNumber *)key; +- (RCTResponseSenderBlock)getPendingSend:(NSNumber *)key; +- (void)dropPendingSend:(NSNumber *)key; - (NSNumber*)getNextId; @end @@ -40,7 +43,6 @@ typedef enum RCTTCPError RCTTCPError; @property (nonatomic, retain) NSNumber * id; @property (nonatomic, weak) id clientDelegate; -@property (nonatomic) BOOL useSsl; ///--------------------------------------------------------------------------------------- /// @name Class Methods @@ -64,14 +66,10 @@ typedef enum RCTTCPError RCTTCPError; * @param port * @param host ip address * @param options NSDictionary which can have @"localAddress" and @"localPort" to specify the local interface - * @param useSsl BOOL Use SSL/TLS connection * @return true if connected, false if there was an error */ -- (BOOL)connect:(NSString *)host port:(int)port withOptions:(NSDictionary *)options useSsl:(BOOL)useSsl error:(NSError **)error; - (BOOL)connect:(NSString *)host port:(int)port withOptions:(NSDictionary *)options error:(NSError **)error; -- (void)upgradeToSecure:(NSString *)host port:(int)port callback:(RCTResponseSenderBlock) callback; - /** * Starts listening on a local host and port * diff --git a/ios/TcpSocketClient.m b/ios/TcpSocketClient.m old mode 100644 new mode 100755 index 4b3477e..12852f1 --- a/ios/TcpSocketClient.m +++ b/ios/TcpSocketClient.m @@ -15,11 +15,6 @@ @interface TcpSocketClient() { @private GCDAsyncSocket *_tcpSocket; - NSString *_host; - NSMutableDictionary *_pendingSends; - RCTResponseSenderBlock _pendingUpgrade; - NSLock *_lock; - long _sendTag; } - (id)initWithClientId:(NSNumber *)clientID andConfig:(id)aDelegate; @@ -45,8 +40,6 @@ - (id)initWithClientId:(NSNumber *)clientID andConfig:(id) if (self) { _id = clientID; _clientDelegate = aDelegate; - _pendingSends = [NSMutableDictionary dictionary]; - _lock = [[NSLock alloc] init]; _tcpSocket = tcpSocket; [_tcpSocket setUserData: clientID]; } @@ -56,12 +49,6 @@ - (id)initWithClientId:(NSNumber *)clientID andConfig:(id) - (BOOL)connect:(NSString *)host port:(int)port withOptions:(NSDictionary *)options error:(NSError **)error { - return [self connect:host port:port withOptions:options useSsl:NO error:error]; -} - -- (BOOL)connect:(NSString *)host port:(int)port withOptions:(NSDictionary *)options useSsl:(BOOL)useSsl error:(NSError **)error -{ - self.useSsl = useSsl; if (_tcpSocket) { if (error) { *error = [self badInvocationError:@"this client's socket is already connected"]; @@ -70,7 +57,6 @@ - (BOOL)connect:(NSString *)host port:(int)port withOptions:(NSDictionary *)opti return false; } - _host = host; _tcpSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:[self methodQueue]]; [_tcpSocket setUserData: _id]; @@ -97,16 +83,6 @@ - (BOOL)connect:(NSString *)host port:(int)port withOptions:(NSDictionary *)opti return result; } -- (void)upgradeToSecure:(NSString *)host port:(int)port callback:(RCTResponseSenderBlock) callback; -{ - if (callback) { - self->_pendingUpgrade = callback; - } - NSMutableDictionary *settings = [NSMutableDictionary dictionary]; - - [_tcpSocket startTLSCancelCurrentRead:settings]; -} - - (NSDictionary *)getAddress { if (_tcpSocket) @@ -153,58 +129,26 @@ - (BOOL)listen:(NSString *)host port:(int)port error:(NSError **)error return isListening; } -- (void)setPendingSend:(RCTResponseSenderBlock)callback forKey:(NSNumber *)key -{ - [_lock lock]; - @try { - [_pendingSends setObject:callback forKey:key]; - } - @finally { - [_lock unlock]; - } -} - -- (RCTResponseSenderBlock)getPendingSend:(NSNumber *)key -{ - [_lock lock]; - @try { - return [_pendingSends objectForKey:key]; - } - @finally { - [_lock unlock]; - } -} - -- (void)dropPendingSend:(NSNumber *)key -{ - [_lock lock]; - @try { - [_pendingSends removeObjectForKey:key]; - } - @finally { - [_lock unlock]; - } -} - - (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)msgTag { NSNumber* tagNum = [NSNumber numberWithLong:msgTag]; - RCTResponseSenderBlock callback = [self getPendingSend:tagNum]; + RCTResponseSenderBlock callback = [_clientDelegate getPendingSend:tagNum]; if (callback) { callback(@[]); - [self dropPendingSend:tagNum]; + [_clientDelegate dropPendingSend:tagNum]; } } - (void) writeData:(NSData *)data callback:(RCTResponseSenderBlock)callback { + NSNumber *sendTag = [_clientDelegate getNextTag]; if (callback) { - [self setPendingSend:callback forKey:@(_sendTag)]; + [_clientDelegate setPendingSend:callback forKey:sendTag]; } - [_tcpSocket writeData:data withTimeout:-1 tag:_sendTag]; - - _sendTag++; + [_tcpSocket writeData:data withTimeout:-1 tag:sendTag.longValue]; + + [_tcpSocket readDataWithTimeout:-1 tag:_id.longValue]; } - (void)end @@ -222,13 +166,10 @@ - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)t RCTLogWarn(@"didReadData with nil clientDelegate for %@", [sock userData]); return; } - + [_clientDelegate onData:@(tag) data:data]; - if (!_pendingUpgrade) { - // if we add a read, the special packet will not be picked up in time - [sock readDataWithTimeout:-1 tag:tag]; - } + [sock readDataWithTimeout:-1 tag:tag]; } - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket @@ -248,34 +189,11 @@ - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(ui return; } - if (self.useSsl) - { - NSMutableDictionary *settings = [NSMutableDictionary dictionary]; - [sock startTLS:settings]; - - [_clientDelegate onConnect:self]; - } - else - { - [_clientDelegate onConnect:self]; - [sock readDataWithTimeout:-1 tag:_id.longValue]; - } -} + [_clientDelegate onConnect:self]; -- (void)socketDidSecure:(GCDAsyncSocket *)sock { - RCTLogInfo(@"socket secured"); - if (self->_pendingUpgrade) { - self.useSsl= true; - self->_pendingUpgrade(@[]); - self->_pendingUpgrade = nil; - [_clientDelegate onSecureConnect:self]; - } - // start receiving messages - if (self.useSsl) - { - [sock readDataWithTimeout:-1 tag:_id.longValue]; - } + [sock readDataWithTimeout:-1 tag:_id.longValue]; } + - (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock { // TODO : investigate for half-closed sockets diff --git a/ios/TcpSockets.h b/ios/TcpSockets.h old mode 100644 new mode 100755 diff --git a/ios/TcpSockets.m b/ios/TcpSockets.m old mode 100644 new mode 100755 index 4076824..6f88605 --- a/ios/TcpSockets.m +++ b/ios/TcpSockets.m @@ -14,6 +14,15 @@ // offset native ids by 5000 #define COUNTER_OFFSET 5000 +@interface TcpSockets() { + +@private + NSMutableDictionary *_pendingSends; + NSLock *_lock; + long _tag; +} +@end + @implementation TcpSockets { NSMutableDictionary *_clients; @@ -22,13 +31,25 @@ @implementation TcpSockets RCT_EXPORT_MODULE() +- (id)init { + self = [super init]; + if (self) { + _pendingSends = [NSMutableDictionary dictionary]; + _lock = [[NSLock alloc] init]; + } + return self; +} + +- (NSNumber*)getNextTag { + return [NSNumber numberWithLong:_tag++]; +} + - (NSArray *)supportedEvents { return @[@"connect", @"connection", @"data", @"close", - @"secureConnect", @"error"]; } @@ -86,39 +107,12 @@ - (TcpSocketClient *)createSocket:(nonnull NSNumber*)cId } } -RCT_EXPORT_METHOD(connectTls:(nonnull NSNumber*)cId - host:(NSString *)host - port:(int)port - withOptions:(NSDictionary *)options) -{ - TcpSocketClient *client = _clients[cId]; - if (!client) { - client = [self createSocket:cId]; - } - - NSError *error = nil; - if (![client connect:host port:port withOptions:options useSsl:YES error:&error]) - { - [self onError:client withError:error]; - return; - } -} - -RCT_EXPORT_METHOD(upgradeToSecure:(nonnull NSNumber*)cId - host:(NSString *)host - port:(int)port - callback:(RCTResponseSenderBlock)callback) { - TcpSocketClient* client = [self findClient:cId]; - if (!client) return; - [client upgradeToSecure:host port:port callback:callback]; -} - RCT_EXPORT_METHOD(write:(nonnull NSNumber*)cId string:(NSString *)base64String callback:(RCTResponseSenderBlock)callback) { TcpSocketClient* client = [self findClient:cId]; if (!client) return; - + // iOS7+ // TODO: use https://github.com/nicklockwood/Base64 for compatibility with earlier iOS versions NSData *data = [[NSData alloc] initWithBase64EncodedString:base64String options:0]; @@ -156,15 +150,9 @@ - (void)onConnect:(TcpSocketClient*) client body:@{ @"id": client.id, @"address" : [client getAddress] }]; } -- (void)onSecureConnect:(TcpSocketClient*) client -{ - [self sendEventWithName:@"secureConnect" - body:@{ @"id": client.id }]; -} - -(void)onConnection:(TcpSocketClient *)client toClient:(NSNumber *)clientID { _clients[client.id] = client; - + [self sendEventWithName:@"connection" body:@{ @"id": clientID, @"info": @{ @"id": client.id, @"address" : [client getAddress] } }]; } @@ -234,4 +222,38 @@ -(NSNumber*)getNextId { return @(_counter++ + COUNTER_OFFSET); } + +- (void)setPendingSend:(RCTResponseSenderBlock)callback forKey:(NSNumber *)key +{ + [_lock lock]; + @try { + [_pendingSends setObject:callback forKey:key]; + } + @finally { + [_lock unlock]; + } +} + +- (RCTResponseSenderBlock)getPendingSend:(NSNumber *)key +{ + [_lock lock]; + @try { + return [_pendingSends objectForKey:key]; + } + @finally { + [_lock unlock]; + } +} + +- (void)dropPendingSend:(NSNumber *)key +{ + [_lock lock]; + @try { + [_pendingSends removeObjectForKey:key]; + } + @finally { + [_lock unlock]; + } +} + @end