Mon 21 Jul 22:43:21 CEST 2025

This commit is contained in:
sbosse 2025-07-21 23:29:30 +02:00
parent 6f55d53b70
commit f864e27e47

View File

@ -0,0 +1,735 @@
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ChromeSocketsTcp.h"
#import "GCDAsyncSocket.h"
#ifndef CHROME_SOCKETS_TCP_VERBOSE_LOGGING
#define CHROME_SOCKETS_TCP_VERBOSE_LOGGING 0
#endif
#if CHROME_SOCKETS_TCP_VERBOSE_LOGGING
#define VERBOSE_LOG NSLog
#else
#define VERBOSE_LOG(args...) do {} while (false)
#endif
#if CHROME_SOCKETS_TCP_VERBOSE_LOGGING
static NSString* stringFromData(NSData* data) {
NSUInteger len = [data length];
if (len > 200) {
len = 200;
}
char* buf = (char*)malloc(len + 1);
memcpy(buf, [data bytes], len);
buf[len] = 0;
NSString* ret = [NSString stringWithUTF8String:buf];
free(buf);
return ret;
}
#endif // CHROME_SOCKETS_TCP_VERBOSE_LOGGING
#pragma mark ChromeSocketsTcpSocket interface
@interface ChromeSocketsTcpSocket : NSObject {
@public
__weak ChromeSocketsTcp* _plugin;
NSUInteger _socketId;
NSNumber* _persistent;
NSString* _name;
NSNumber* _bufferSize;
// pipeToFile options
NSNumber* _append;
NSString* _uri;
NSFileHandle* _uriFileHandle;
NSInteger _numBytes;
id _pipeToFileCompleteCallback;
long _bytesReadNotSend;
NSTimeInterval _lastProgressTimestamp;
NSUInteger _readTag;
NSUInteger _receivedTag;
NSNumber* _paused;
NSMutableArray* _pausedBuffers;
GCDAsyncSocket* _socket;
NSMutableArray* _sendCallbacks;
id _connectCallback;
id _disconnectCallback;
id _secureCallback;
}
@end
#pragma mark ChromeSocketsTcp interface
@interface ChromeSocketsTcp() {
NSMutableDictionary* _sockets;
NSUInteger _nextSocketId;
NSString* _receiveEventsCallbackId;
@public
NSInteger _pendingReceive;
}
- (void)create:(CDVInvokedUrlCommand*)command;
- (void)update:(CDVInvokedUrlCommand*)command;
- (void)setPaused:(CDVInvokedUrlCommand*)command;
// - (void)setKeepAlive:(CDVInvokedUrlCommand*)command;
// - (void)setNoDelay:(CDVInvokedUrlCommand*)command;
- (void)connect:(CDVInvokedUrlCommand*)command;
- (void)disconnect:(CDVInvokedUrlCommand*)command;
- (void)secure:(CDVInvokedUrlCommand*)command;
- (void)send:(CDVInvokedUrlCommand*)command;
- (void)close:(CDVInvokedUrlCommand*)command;
- (void)getInfo:(CDVInvokedUrlCommand*)command;
- (void)getSockets:(CDVInvokedUrlCommand*)command;
- (void)pipeToFile:(CDVInvokedUrlCommand*)command;
- (void)registerReceiveEvents:(CDVInvokedUrlCommand*)command;
- (void)readyToRead:(CDVInvokedUrlCommand*)command;
- (void)fireReceiveEventsWithSocketId:(NSUInteger)theSocketId data:(NSData*)theData;
- (void)fireReceiveEventsWithInfo:(NSDictionary*)theInfo waitReadyToRead:(BOOL)waitReadyToRead;
- (void)fireReceiveErrorEventsWithSocketId:(NSUInteger)theSocketId errorCode:(NSUInteger)theErrorCode message:(NSString*)theMessage;
@end
@implementation ChromeSocketsTcpSocket
NSTimeInterval const PIPE_TO_FILE_PROGRESS_INTERVAL = 0.1;
- (ChromeSocketsTcpSocket*)initWithId:(NSUInteger)theSocketId plugin:(ChromeSocketsTcp*)thePlugin properties:(NSDictionary*)theProperties
{
self = [super init];
if (self) {
_socketId = theSocketId;
_plugin = thePlugin;
_paused = [NSNumber numberWithBool:NO];
_socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
[self resetSocket];
[self setProperties:theProperties];
}
return self;
}
- (ChromeSocketsTcpSocket*)initAcceptedSocketWithId:(NSUInteger)theSocketId plugin:(ChromeSocketsTcp*)thePlugin socket:(GCDAsyncSocket*)theSocket
{
self = [super init];
if (self) {
_socketId = theSocketId;
_plugin = thePlugin;
_socket = theSocket;
[_socket setDelegate:self];
_paused = [NSNumber numberWithBool:YES];
[self resetSocket];
[self setProperties:nil];
}
return self;
}
- (void)resetSocket
{
_readTag = 0;
_receivedTag = 0;
_pausedBuffers = [NSMutableArray array];
_sendCallbacks = [NSMutableArray array];
_connectCallback = nil;
_disconnectCallback = nil;
_secureCallback = nil;
[self resetPipeToFileProperties];
}
- (void)resetPipeToFileProperties
{
if (_uriFileHandle) {
[_uriFileHandle closeFile];
_uriFileHandle = nil;
_uri = nil;
}
_append = nil;
_pipeToFileCompleteCallback = nil;
_numBytes = 0;
_bytesReadNotSend = 0;
}
- (NSDictionary*)getInfo
{
NSString* localAddress = [_socket localHost];
NSNumber* localPort = [NSNumber numberWithUnsignedInt:[_socket localPort]];
NSString* peerAddress = [_socket connectedHost];
NSNumber* peerPort = [NSNumber numberWithUnsignedInt:[_socket connectedPort]];
NSMutableDictionary* socketInfo = [@{
@"socketId": [NSNumber numberWithUnsignedInteger:_socketId],
@"persistent": _persistent,
@"name": _name,
@"bufferSize": _bufferSize,
@"connected": [NSNumber numberWithBool:[_socket isConnected]],
@"paused": _paused,
} mutableCopy];
if (localAddress) {
socketInfo[@"localAddress"] = localAddress;
socketInfo[@"localPort"] = localPort;
}
if (peerAddress) {
socketInfo[@"peerAddress"] = peerAddress;
socketInfo[@"peerPort"] = peerPort;
}
return [socketInfo copy];
}
- (void)setProperties:(NSDictionary*)theProperties
{
NSNumber* persistent = theProperties[@"persistent"];
NSString* name = theProperties[@"name"];
NSNumber* bufferSize = theProperties[@"bufferSize"];
if (persistent)
_persistent = persistent;
if (name)
_name = name;
if (bufferSize && _bufferSize == 0 && ![_paused boolValue]) // read delegate method won't be called when _bufferSize == 0
[_socket readDataWithTimeout:-1 buffer:nil bufferOffset:0 maxLength:[bufferSize unsignedIntegerValue] tag:++_readTag];
if (bufferSize)
_bufferSize = bufferSize;
// Set undefined properties to default value
if (_persistent == nil)
_persistent = [NSNumber numberWithBool:NO];
if (_name == nil)
_name = @"";
if (_bufferSize == nil)
_bufferSize = [NSNumber numberWithUnsignedInteger:4096];
}
- (BOOL)setPipeToFileProperties:(NSDictionary*)theProperties
{
NSNumber* append = theProperties[@"append"];
NSNumber* numBytes = theProperties[@"numBytes"];
NSString* uri = theProperties[@"uri"];
[self resetPipeToFileProperties];
if (append) {
_append = append;
} else {
_append = [NSNumber numberWithBool:NO];
}
if (numBytes && [numBytes integerValue] > 0) {
_numBytes = [numBytes integerValue];
} else {
return NO;
}
if (uri && uri.length > 0) {
NSString* filePath = [[NSURL URLWithString:uri] path];
if(![NSFileManager.defaultManager fileExistsAtPath:filePath]) {
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
}
_uriFileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
if (append.boolValue) {
[_uriFileHandle seekToEndOfFile];
}
if (_uriFileHandle) {
_uri = uri;
} else {
return NO;
}
} else {
return NO;
}
_lastProgressTimestamp = [[NSDate date] timeIntervalSince1970];
return YES;
}
- (void)resumeReadIfNotReading
{
if (_readTag == _receivedTag && _plugin->_pendingReceive == 0 && [_socket isConnected] && ![_paused boolValue]) {
[_socket readDataWithTimeout:-1 buffer:nil bufferOffset:0 maxLength:[_bufferSize unsignedIntegerValue] tag:++_readTag];
}
}
- (void)setPaused:(NSNumber*)paused
{
if (![_paused isEqualToNumber:paused]) {
_paused = paused;
if (![_paused boolValue]) {
for (NSData* data in _pausedBuffers) {
[self sendReceivedData:data];
}
[_pausedBuffers removeAllObjects];
[self resumeReadIfNotReading];
}
}
}
- (void)sendReceivedData:(NSData*)data
{
if (_uriFileHandle) {
NSUInteger bytesRead = 0;
// extra data that need to send to the webveiw
NSData* extraData = nil;
if (_numBytes >= [data length]) {
[_uriFileHandle writeData:data];
bytesRead = data.length;
} else {
NSData* writeData = [data subdataWithRange:NSMakeRange(0, _numBytes)];
extraData = [data subdataWithRange:NSMakeRange(_numBytes, data.length - _numBytes)];
[_uriFileHandle writeData:writeData];
bytesRead = writeData.length;
}
_numBytes -= bytesRead;
NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970];
_bytesReadNotSend += bytesRead;
if (_numBytes == 0 || timestamp - _lastProgressTimestamp > PIPE_TO_FILE_PROGRESS_INTERVAL) {
NSDictionary *info = @{
@"socketId": [NSNumber numberWithUnsignedInteger:_socketId],
@"uri": _uri,
@"bytesRead": [NSNumber numberWithUnsignedInteger:_bytesReadNotSend],
};
[_plugin fireReceiveEventsWithInfo:info waitReadyToRead:NO];
_bytesReadNotSend = 0;
_lastProgressTimestamp = timestamp;
}
if (_numBytes == 0) {
void (^callback)() = _pipeToFileCompleteCallback;
[self resetPipeToFileProperties];
assert(callback != nil);
callback();
}
if (extraData) {
[_plugin fireReceiveEventsWithSocketId:_socketId data:extraData];
} else {
[self resumeReadIfNotReading];
}
} else {
[_plugin fireReceiveEventsWithSocketId:_socketId data:data];
}
}
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
VERBOSE_LOG(@"socket:didConnectToHost socketId: %u", _socketId);
void (^callback)(BOOL, NSError*) = _connectCallback;
assert(callback != nil);
_connectCallback = nil;
callback(YES, nil);
if (![_paused boolValue])
[_socket readDataWithTimeout:-1 buffer:nil bufferOffset:0 maxLength:[_bufferSize unsignedIntegerValue] tag:++_readTag];
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
VERBOSE_LOG(@"socket:didReadDataWithTag socketId: %u", _socketId);
_receivedTag = tag;
if ([_paused boolValue]) {
[_pausedBuffers addObject:data];
} else {
[self sendReceivedData:data];
}
}
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
assert([_sendCallbacks count] != 0);
void (^callback)() = _sendCallbacks[0];
assert(callback != nil);
[_sendCallbacks removeObjectAtIndex:0];
callback();
[_socket readDataWithTimeout:-1 buffer:nil bufferOffset:0 maxLength:[_bufferSize unsignedIntegerValue] tag:-1];
}
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
if (_disconnectCallback) {
void (^callback)() = _disconnectCallback;
assert(_disconnectCallback != nil);
_disconnectCallback = nil;
callback();
} else if (_connectCallback) {
void(^callback)(BOOL, NSError*) = _connectCallback;
callback(NO, err);
_connectCallback = nil;
} else if (err) {
[_plugin fireReceiveErrorEventsWithSocketId:_socketId errorCode:[err code] message:[err localizedDescription]];
}
[self resetSocket];
}
- (void)socketDidSecure:(GCDAsyncSocket *)sock
{
VERBOSE_LOG(@"socketDidSecure socketId: %u", _socketId);
assert(_secureCallback != nil);
void (^callback)() = _secureCallback;
_secureCallback = nil;
callback();
}
@end
@implementation ChromeSocketsTcp
- (void)pluginInitialize
{
_sockets = [NSMutableDictionary dictionary];
_nextSocketId = 1;
_receiveEventsCallbackId = nil;
_pendingReceive = 0;
}
- (void)onReset
{
for (NSNumber* socketId in _sockets) {
[self closeSocketWithId:socketId callbackId:nil];
}
}
- (NSDictionary*)buildErrorInfoWithErrorCode:(NSInteger)theErrorCode message:(NSString*)message
{
return @{
@"resultCode": [NSNumber numberWithInteger:theErrorCode],
@"message": message,
};
}
- (void)create:(CDVInvokedUrlCommand*)command
{
NSDictionary* properties = [command argumentAtIndex:0];
ChromeSocketsTcpSocket* socket = [[ChromeSocketsTcpSocket alloc] initWithId:_nextSocketId++ plugin:self properties:properties];
_sockets[[NSNumber numberWithUnsignedInteger:socket->_socketId]] = socket;
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(int)socket->_socketId] callbackId:command.callbackId];
}
- (void)update:(CDVInvokedUrlCommand*)command
{
NSNumber* socketId = [command argumentAtIndex:0];
NSDictionary* properties = [command argumentAtIndex:1];
ChromeSocketsTcpSocket *socket = _sockets[socketId];
if (socket == nil)
return;
[socket setProperties:properties];
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK] callbackId:command.callbackId];
}
- (void)setPaused:(CDVInvokedUrlCommand*)command
{
NSNumber* socketId = [command argumentAtIndex:0];
NSNumber* paused = [command argumentAtIndex:1];
ChromeSocketsTcpSocket* socket = _sockets[socketId];
if (socket == nil)
return;
[socket setPaused:paused];
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK] callbackId:command.callbackId];
}
- (void)connect:(CDVInvokedUrlCommand*)command
{
NSNumber* socketId = [command argumentAtIndex:0];
NSString* peerAddress = [command argumentAtIndex:1];
NSUInteger peerPort = [[command argumentAtIndex:2] unsignedIntegerValue];
ChromeSocketsTcpSocket* socket = _sockets[socketId];
if (socket == nil) {
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self buildErrorInfoWithErrorCode:ENOTSOCK message:@"Invalid Argument"]] callbackId:command.callbackId];
return;
}
id<CDVCommandDelegate> commandDelegate = self.commandDelegate;
socket->_connectCallback = [^(BOOL success, NSError* error) {
if (success) {
[commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK] callbackId:command.callbackId];
} else {
[commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self buildErrorInfoWithErrorCode:[error code] message:[error localizedDescription]]] callbackId:command.callbackId];
}
} copy];
NSError* err = nil;
BOOL success = [socket->_socket connectToHost:peerAddress onPort:peerPort withTimeout:2 error:&err];
if (!success) {
void(^callback)(BOOL, NSError*) = socket->_connectCallback;
callback(NO, err);
socket->_connectCallback = nil;
}
}
- (void)disconnectSocketWithId:(NSNumber*)socketId callbackId:(NSString*)theCallbackId close:(BOOL)close
{
ChromeSocketsTcpSocket* socket = _sockets[socketId];
if (socket == nil)
return;
id<CDVCommandDelegate> commandDelegate = self.commandDelegate;
socket->_disconnectCallback = [^(){
if (theCallbackId)
[commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK] callbackId:theCallbackId];
if (close)
[_sockets removeObjectForKey:socketId];
} copy];
if ([socket->_socket isDisconnected]) {
void (^callback)() = socket->_disconnectCallback;
socket->_disconnectCallback = nil;
callback();
} else {
[socket->_socket disconnect];
}
}
- (void)disconnect:(CDVInvokedUrlCommand*)command
{
NSNumber* socketId = [command argumentAtIndex:0];
[self disconnectSocketWithId:socketId callbackId:command.callbackId close:NO];
}
- (NSNumber*)getSecureVersion:(NSString*)versionString
{
if ([versionString isEqualToString:@"ssl3"]) {
return [NSNumber numberWithInt:kSSLProtocol3];
} else if ([versionString isEqualToString:@"tls1"]) {
return [NSNumber numberWithInt:kTLSProtocol1];
} else if ([versionString isEqualToString:@"tls1.1"]) {
return [NSNumber numberWithInt:kTLSProtocol11];
} else if ([versionString isEqualToString:@"tls1.2"]) {
return [NSNumber numberWithInt:kTLSProtocol12];
} else {
return nil;
}
}
- (void)secure:(CDVInvokedUrlCommand *)command
{
NSNumber* socketId = [command argumentAtIndex:0];
NSDictionary* options = [command argumentAtIndex:1];
ChromeSocketsTcpSocket* socket = _sockets[socketId];
if (socket == nil) {
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self buildErrorInfoWithErrorCode:ENOTSOCK message:@"Invalid Argument"]] callbackId:command.callbackId];
return;
}
id<CDVCommandDelegate> commandDelegate = self.commandDelegate;
socket->_secureCallback = [^() {
[commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK] callbackId:command.callbackId];
} copy];
NSMutableDictionary* settings = [NSMutableDictionary dictionaryWithCapacity:2];
NSDictionary* tlsVersion = options[@"tlsVersion"];
if (tlsVersion) {
NSNumber* minVersion = [self getSecureVersion:tlsVersion[@"min"]];
NSNumber* maxVersion = [self getSecureVersion:tlsVersion[@"max"]];
if (minVersion) {
settings[GCDAsyncSocketSSLProtocolVersionMin] = minVersion;
}
if (maxVersion) {
settings[GCDAsyncSocketSSLProtocolVersionMax] = maxVersion;
}
}
[socket->_socket startTLS:settings];
}
- (void)send:(CDVInvokedUrlCommand*)command
{
NSNumber* socketId = [command argumentAtIndex:0];
NSData* data = [command argumentAtIndex:1];
ChromeSocketsTcpSocket* socket = _sockets[socketId];
if (socket == nil) {
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self buildErrorInfoWithErrorCode:ENOTSOCK message:@"Invalid Argument"]] callbackId:command.callbackId];
return;
}
if ([socket->_socket isConnected]) {
id<CDVCommandDelegate> commandDelegate = self.commandDelegate;
[socket->_sendCallbacks addObject:[^() {
VERBOSE_LOG(@"ACK %@.%@ Write", socketId, command.callbackId);
[commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(int)[data length]] callbackId:command.callbackId];
} copy]];
[socket->_socket writeData:data withTimeout:-1 tag:-1];
} else {
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self buildErrorInfoWithErrorCode:ENOTCONN message:@"Socket Not Connected"]] callbackId:command.callbackId];
}
}
- (void)closeSocketWithId:(NSNumber*)socketId callbackId:(NSString*)theCallbackId
{
[self disconnectSocketWithId:socketId callbackId:theCallbackId close:YES];
}
- (void)close:(CDVInvokedUrlCommand*)command
{
NSNumber* socketId = [command argumentAtIndex:0];
[self closeSocketWithId:socketId callbackId:command.callbackId];
}
- (void)getInfo:(CDVInvokedUrlCommand*)command
{
NSNumber* socketId = [command argumentAtIndex:0];
ChromeSocketsTcpSocket* socket = _sockets[socketId];
if (socket == nil)
return;
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[socket getInfo]] callbackId:command.callbackId];
}
- (void)getSockets:(CDVInvokedUrlCommand*)command
{
NSArray* sockets = [_sockets allValues];
NSMutableArray* socketsInfo = [NSMutableArray arrayWithCapacity:[sockets count]];
for (ChromeSocketsTcpSocket* socket in sockets) {
[socketsInfo addObject:[socket getInfo]];
}
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:socketsInfo] callbackId:command.callbackId];
}
- (void)pipeToFile:(CDVInvokedUrlCommand *)command
{
NSNumber* socketId = [command argumentAtIndex:0];
NSDictionary* options = [command argumentAtIndex:1];
ChromeSocketsTcpSocket* socket = _sockets[socketId];
if (socket == nil)
return;
if ([socket setPipeToFileProperties:options]) {
id<CDVCommandDelegate> commandDelegate = self.commandDelegate;
socket->_pipeToFileCompleteCallback = [^() {
[commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK] callbackId:command.callbackId];
} copy];
} else {
[self fireReceiveErrorEventsWithSocketId:socket->_socketId errorCode:-1000 message:@"Failed to start pipeToFile"];
}
}
- (void)registerReceiveEvents:(CDVInvokedUrlCommand*)command
{
VERBOSE_LOG(@"registerReceiveEvents: ");
_receiveEventsCallbackId = command.callbackId;
}
- (void)fireReceiveEventsWithSocketId:(NSUInteger)theSocketId data:(NSData*)theData
{
NSArray* multipart = @[
@{@"socketId":[NSNumber numberWithUnsignedInteger:theSocketId]},
theData,
];
[self fireReceiveEventsWithMultiPart:multipart waitReadyToRead:YES];
}
- (void)fireReceiveEventsWithInfo:(NSDictionary*)theInfo waitReadyToRead:(BOOL)waitReadyToRead
{
[self fireReceiveEventsWithMultiPart:@[theInfo] waitReadyToRead:waitReadyToRead];
}
- (void)fireReceiveEventsWithMultiPart:(NSArray*)theMultiPart waitReadyToRead:(BOOL)waitReadyToRead
{
assert(_receiveEventsCallbackId != nil);
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsMultipart:theMultiPart];
[result setKeepCallbackAsBool:YES];
if (waitReadyToRead) {
_pendingReceive++;
}
[self.commandDelegate sendPluginResult:result callbackId:_receiveEventsCallbackId];
}
- (void)fireReceiveErrorEventsWithSocketId:(NSUInteger)theSocketId errorCode:(NSUInteger)theErrorCode message:(NSString*)theMessage
{
assert(_receiveEventsCallbackId != nil);
NSDictionary* info = @{
@"socketId": [NSNumber numberWithUnsignedInteger:theSocketId],
@"resultCode": [NSNumber numberWithUnsignedInteger:theErrorCode],
@"message": theMessage,
};
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:info];
[result setKeepCallbackAsBool:YES];
[self.commandDelegate sendPluginResult:result callbackId:_receiveEventsCallbackId];
}
- (NSUInteger)registerAcceptedSocket:(GCDAsyncSocket*)theSocket
{
ChromeSocketsTcpSocket* socket = [[ChromeSocketsTcpSocket alloc] initAcceptedSocketWithId:_nextSocketId++ plugin:self socket:theSocket];
_sockets[[NSNumber numberWithUnsignedInteger:socket->_socketId]] = socket;
[socket setPaused:[NSNumber numberWithBool:YES]];
return socket->_socketId;
}
- (void)readyToRead:(CDVInvokedUrlCommand*)command
{
_pendingReceive--;
if (_pendingReceive == 0) {
for (ChromeSocketsTcpSocket* socket in [_sockets allValues]) {
[socket resumeReadIfNotReading];
}
}
}
@end