Mon 21 Jul 22:43:21 CEST 2025
This commit is contained in:
parent
6f55d53b70
commit
f864e27e47
|
@ -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
|
Loading…
Reference in New Issue
Block a user