123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624 |
- //
- // GCDAsyncSOCKSProxySocket.m
- //
- // Copyright © 2019 Threema GmbH. All rights reserved.
- // Derived from ProxyKit, Copyright (c) 2014 Chris Ballinger
- //
- #import "GCDAsyncSOCKSProxySocket.h"
- #if DEBUG
- static const int ddLogLevel = DDLogLevelVerbose;
- #else
- static const int ddLogLevel = DDLogLevelOff;
- #endif
- // Define various socket tags
- #define SOCKS_OPEN 10100
- #define SOCKS_CONNECT 10200
- #define SOCKS_CONNECT_REPLY_1 10300
- #define SOCKS_CONNECT_REPLY_2 10400
- #define SOCKS_AUTH_USERPASS 10500
- // Timeouts
- #define TIMEOUT_CONNECT 8.00
- #define TIMEOUT_READ 5.00
- #define TIMEOUT_TOTAL 80.00
- @interface GCDAsyncSOCKSProxySocket()
- @property (nonatomic, strong, readonly) GCDAsyncSocket *proxySocket;
- @property (nonatomic, readonly) dispatch_queue_t proxyDelegateQueue;
- @property (nonatomic, strong, readonly) NSString *destinationHost;
- @property (nonatomic, readonly) uint16_t destinationPort;
- @property (nonatomic, strong) NSError *lastDisconnectError;
- @end
- @implementation GCDAsyncSOCKSProxySocket
- - (void) setProxyHost:(NSString *)host port:(uint16_t)port version:(GCDAsyncSocketSOCKSVersion)version {
- _proxyHost = host;
- _proxyPort = port;
- _proxyVersion = version;
- }
- - (void) setProxyUsername:(NSString *)username password:(NSString *)password {
- _proxyUsername = username;
- _proxyPassword = password;
- }
- #pragma mark Overridden methods
- - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq {
- if (self = [super initWithDelegate:aDelegate delegateQueue:dq socketQueue:sq]) {
- _proxyHost = nil;
- _proxyPort = 0;
- _proxyVersion = -1;
- _destinationHost = nil;
- _destinationPort = 0;
- _proxyUsername = nil;
- _proxyPassword = nil;
- _proxyDelegateQueue = dispatch_queue_create("GCDAsyncSOCKSProxySocket delegate queue", 0);
-
- }
- return self;
- }
- - (BOOL)connectToHost:(NSString *)inHost
- onPort:(uint16_t)port
- viaInterface:(NSString *)inInterface
- withTimeout:(NSTimeInterval)timeout
- error:(NSError **)errPtr
- {
- if (!self.proxySocket) {
- _proxySocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:self.proxyDelegateQueue socketQueue:NULL];
- }
- _destinationHost = inHost;
- _destinationPort = port;
- return [self.proxySocket connectToHost:self.proxyHost onPort:self.proxyPort viaInterface:inInterface withTimeout:timeout error:errPtr];
- }
- /** Returns YES if tag is reserved for internal functions */
- - (BOOL) checkForReservedTag:(long)tag {
- if (tag == SOCKS_OPEN || tag == SOCKS_CONNECT || tag == SOCKS_CONNECT_REPLY_1 || tag == SOCKS_CONNECT_REPLY_2 || tag == SOCKS_AUTH_USERPASS) {
- return YES;
- } else {
- return NO;
- }
- }
- - (void) writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag {
- if ([self checkForReservedTag:tag]) {
- DDLogError(@"This tag is reserved and won't work: %ld", tag);
- return;
- }
- [self.proxySocket writeData:data withTimeout:timeout tag:tag];
- }
- - (void)readDataWithTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger)offset tag:(long)tag {
- if ([self checkForReservedTag:tag]) {
- DDLogError(@"This tag is reserved and won't work: %ld", tag);
- return;
- }
- [self.proxySocket readDataWithTimeout:timeout buffer:buffer bufferOffset:offset tag:tag];
- }
- - (void)readDataWithTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger)offset maxLength:(NSUInteger)length tag:(long)tag {
- if ([self checkForReservedTag:tag]) {
- DDLogError(@"This tag is reserved and won't work: %ld", tag);
- return;
- }
- [self.proxySocket readDataWithTimeout:timeout buffer:buffer bufferOffset:offset maxLength:length tag:tag];
- }
- - (void) readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag {
- if ([self checkForReservedTag:tag]) {
- DDLogError(@"This tag is reserved and won't work: %ld", tag);
- return;
- }
- [self.proxySocket readDataWithTimeout:timeout tag:tag];
- }
- - (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag {
- if ([self checkForReservedTag:tag]) {
- DDLogError(@"This tag is reserved and won't work: %ld", tag);
- return;
- }
- [self.proxySocket readDataToLength:length withTimeout:timeout tag:tag];
- }
- - (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger)offset tag:(long)tag {
- if ([self checkForReservedTag:tag]) {
- DDLogError(@"This tag is reserved and won't work: %ld", tag);
- return;
- }
- [self.proxySocket readDataToLength:length withTimeout:timeout buffer:buffer bufferOffset:offset tag:tag];
- }
- - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag {
- if ([self checkForReservedTag:tag]) {
- DDLogError(@"This tag is reserved and won't work: %ld", tag);
- return;
- }
- [self.proxySocket readDataToData:data withTimeout:timeout tag:tag];
- }
- - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger)offset tag:(long)tag {
- if ([self checkForReservedTag:tag]) {
- DDLogError(@"This tag is reserved and won't work: %ld", tag);
- return;
- }
- [self.proxySocket readDataToData:data withTimeout:timeout buffer:buffer bufferOffset:offset tag:tag];
- }
- - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag {
- if ([self checkForReservedTag:tag]) {
- DDLogError(@"This tag is reserved and won't work: %ld", tag);
- return;
- }
- [self.proxySocket readDataToData:data withTimeout:timeout maxLength:length tag:tag];
- }
- - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger)offset maxLength:(NSUInteger)length tag:(long)tag {
- if ([self checkForReservedTag:tag]) {
- DDLogError(@"This tag is reserved and won't work: %ld", tag);
- return;
- }
- [self.proxySocket readDataToData:data withTimeout:timeout buffer:buffer bufferOffset:offset maxLength:length tag:tag];
- }
- - (void) startTLS:(NSDictionary *)tlsSettings {
- NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithDictionary:tlsSettings];
- /*
- NSString *peerName = self.destinationHost;
- [settings setObject:peerName forKey:(NSString *)kCFStreamSSLPeerName];
- */
- [self.proxySocket startTLS:settings];
- }
- - (void) disconnect {
- self.lastDisconnectError = nil;
- [self.proxySocket disconnect];
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma mark SOCKS
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Sends the SOCKS5 open/handshake/authentication data, and starts reading the response.
- * We attempt to gain anonymous access (no authentication).
- **/
- - (void)socksOpen
- {
- // +-----+-----------+---------+
- // NAME | VER | NMETHODS | METHODS |
- // +-----+-----------+---------+
- // SIZE | 1 | 1 | 1 - 255 |
- // +-----+-----------+---------+
- //
- // Note: Size is in bytes
- //
- // Version = 5 (for SOCKS5)
- // NumMethods = 1
- // Method = 0 (No authentication, anonymous access)
-
- NSUInteger byteBufferLength = 3;
- uint8_t *byteBuffer = malloc(byteBufferLength * sizeof(uint8_t));
-
- uint8_t version = 5; // VER
- byteBuffer[0] = version;
-
- uint8_t numMethods = 1; // NMETHODS
- byteBuffer[1] = numMethods;
-
- uint8_t method = 0; // 0 == no auth
- if (self.proxyUsername.length || self.proxyPassword.length) {
- method = 2; // username/password
- }
- byteBuffer[2] = method;
-
- NSData *data = [NSData dataWithBytesNoCopy:byteBuffer length:byteBufferLength freeWhenDone:YES];
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: SOCKS_OPEN: %@", data);
-
- [self.proxySocket writeData:data withTimeout:-1 tag:SOCKS_OPEN];
-
- // +-----+--------+
- // NAME | VER | METHOD |
- // +-----+--------+
- // SIZE | 1 | 1 |
- // +-----+--------+
- //
- // Note: Size is in bytes
- //
- // Version = 5 (for SOCKS5)
- // Method = 0 (No authentication, anonymous access)
-
- [self.proxySocket readDataToLength:2 withTimeout:TIMEOUT_READ tag:SOCKS_OPEN];
- }
- /*
- For username/password authentication the client's authentication request is
-
- field 1: version number, 1 byte (must be 0x01)
- field 2: username length, 1 byte
- field 3: username
- field 4: password length, 1 byte
- field 5: password
- */
- - (void)socksUserPassAuth {
- NSData *usernameData = [self.proxyUsername dataUsingEncoding:NSUTF8StringEncoding];
- NSData *passwordData = [self.proxyPassword dataUsingEncoding:NSUTF8StringEncoding];
- uint8_t usernameLength = (uint8_t)usernameData.length;
- uint8_t passwordLength = (uint8_t)passwordData.length;
- NSMutableData *authData = [NSMutableData dataWithCapacity:1+1+usernameLength+1+passwordLength];
- uint8_t version[1] = {0x01};
- [authData appendBytes:version length:1];
- [authData appendBytes:&usernameLength length:1];
- [authData appendBytes:usernameData.bytes length:usernameLength];
- [authData appendBytes:&passwordLength length:1];
- [authData appendBytes:passwordData.bytes length:passwordLength];
- [self.proxySocket writeData:authData withTimeout:-1 tag:SOCKS_AUTH_USERPASS];
- [self.proxySocket readDataToLength:2 withTimeout:-1 tag:SOCKS_AUTH_USERPASS];
- }
- /**
- * Sends the SOCKS5 connect data (according to XEP-65), and starts reading the response.
- **/
- - (void)socksConnect
- {
- // +-----+-----+-----+------+------+------+
- // NAME | VER | CMD | RSV | ATYP | ADDR | PORT |
- // +-----+-----+-----+------+------+------+
- // SIZE | 1 | 1 | 1 | 1 | var | 2 |
- // +-----+-----+-----+------+------+------+
- //
- // Note: Size is in bytes
- //
- // Version = 5 (for SOCKS5)
- // Command = 1 (for Connect)
- // Reserved = 0
- // Address Type = 3 (1=IPv4, 3=DomainName 4=IPv6)
- // Address = P:D (P=LengthOfDomain D=DomainWithoutNullTermination)
- // Port = 0
-
- NSUInteger hostLength = [self.destinationHost length];
- NSData *hostData = [self.destinationHost dataUsingEncoding:NSUTF8StringEncoding];
- NSUInteger byteBufferLength = (uint)(4 + 1 + hostLength + 2);
- uint8_t *byteBuffer = malloc(byteBufferLength * sizeof(uint8_t));
- NSUInteger offset = 0;
-
- // VER
- uint8_t version = 0x05;
- byteBuffer[0] = version;
- offset++;
-
- /* CMD
- o CONNECT X'01'
- o BIND X'02'
- o UDP ASSOCIATE X'03'
- */
- uint8_t command = 0x01;
- byteBuffer[offset] = command;
- offset++;
-
- byteBuffer[offset] = 0x00; // Reserved, must be 0
- offset++;
- /* ATYP
- o IP V4 address: X'01'
- o DOMAINNAME: X'03'
- o IP V6 address: X'04'
- */
- uint8_t addressType = 0x03;
- byteBuffer[offset] = addressType;
- offset++;
- /* ADDR
- o X'01' - the address is a version-4 IP address, with a length of 4 octets
- o X'03' - the address field contains a fully-qualified domain name. The first
- octet of the address field contains the number of octets of name that
- follow, there is no terminating NUL octet.
- o X'04' - the address is a version-6 IP address, with a length of 16 octets.
- */
- byteBuffer[offset] = hostLength;
- offset++;
- memcpy(byteBuffer+offset, [hostData bytes], hostLength);
- offset+=hostLength;
- uint16_t port = htons(self.destinationPort);
- NSUInteger portLength = 2;
- memcpy(byteBuffer+offset, &port, portLength);
- offset+=portLength;
- NSData *data = [NSData dataWithBytesNoCopy:byteBuffer length:byteBufferLength freeWhenDone:YES];
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: SOCKS_CONNECT: %@", data);
-
- [self.proxySocket writeData:data withTimeout:-1 tag:SOCKS_CONNECT];
-
- // +-----+-----+-----+------+------+------+
- // NAME | VER | REP | RSV | ATYP | ADDR | PORT |
- // +-----+-----+-----+------+------+------+
- // SIZE | 1 | 1 | 1 | 1 | var | 2 |
- // +-----+-----+-----+------+------+------+
- //
- // Note: Size is in bytes
- //
- // Version = 5 (for SOCKS5)
- // Reply = 0 (0=Succeeded, X=ErrorCode)
- // Reserved = 0
- // Address Type = 3 (1=IPv4, 3=DomainName 4=IPv6)
- // Address = P:D (P=LengthOfDomain D=DomainWithoutNullTermination)
- // Port = 0
- //
- // It is expected that the SOCKS server will return the same address given in the connect request.
- // But according to XEP-65 this is only marked as a SHOULD and not a MUST.
- // So just in case, we'll read up to the address length now, and then read in the address+port next.
-
- [self.proxySocket readDataToLength:5 withTimeout:TIMEOUT_READ tag:SOCKS_CONNECT_REPLY_1];
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma mark AsyncSocket Delegate Methods
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
- {
- DDLogInfo(@"proxySocket did connect to %@:%d", host, port);
-
- // Start the SOCKS protocol stuff
- [self socksOpen];
- }
- - (void) socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag {
- DDLogVerbose(@"read partial data with tag %ld of length %d", tag, (int)partialLength);
- if (self.delegate && [self.delegate respondsToSelector:@selector(socket:didReadPartialDataOfLength:tag:)]) {
- dispatch_async(self.delegateQueue, ^{
- @autoreleasepool {
- [self.delegate socket:self didReadPartialDataOfLength:partialLength tag:tag];
- }
- });
- }
- }
- - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
- {
- DDLogVerbose(@"did read tag[%ld] data: %@", tag, data);
-
- if (tag == SOCKS_OPEN)
- {
- NSAssert(data.length == 2, @"SOCKS_OPEN reply length must be 2!");
- // See socksOpen method for socks reply format
- uint8_t *bytes = (uint8_t*)[data bytes];
- uint8_t version = bytes[0];
- uint8_t method = bytes[1];
-
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: SOCKS_OPEN: ver(%o) mtd(%o)", version, method);
-
- if(version == 5)
- {
- if (method == 0) { // No Auth
- [self socksConnect];
- } else if (method == 2) { // Username / password
- [self socksUserPassAuth];
- } else {
- // unsupported auth method
- self.lastDisconnectError = [NSError errorWithDomain:@"socks" code:100 userInfo:@{NSLocalizedDescriptionKey: @"Unsupported SOCKS auth method"}];
- [self.proxySocket disconnect];
- }
- }
- else
- {
- // Wrong version
- self.lastDisconnectError = [NSError errorWithDomain:@"socks" code:101 userInfo:@{NSLocalizedDescriptionKey: @"Wrong SOCKS version"}];
- [self.proxySocket disconnect];
- }
- }
- else if (tag == SOCKS_CONNECT_REPLY_1)
- {
- // See socksConnect method for socks reply format
- NSAssert(data.length == 5, @"SOCKS_CONNECT_REPLY_1 length must be 5!");
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: SOCKS_CONNECT_REPLY_1: %@", data);
- uint8_t *bytes = (uint8_t*)[data bytes];
-
- uint8_t ver = bytes[0];
- uint8_t rep = bytes[1];
-
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: SOCKS_CONNECT_REPLY_1: ver(%o) rep(%o)", ver, rep);
-
- if(ver == 5 && rep == 0)
- {
- // We read in 5 bytes which we expect to be:
- // 0: ver = 5
- // 1: rep = 0
- // 2: rsv = 0
- // 3: atyp = 3
- // 4: size = size of addr field
- //
- // However, some servers don't follow the protocol, and send a atyp value of 0.
-
- uint8_t addressType = bytes[3];
- uint8_t portLength = 2;
-
- if (addressType == 1) { // IPv4
- // only need to read 3 address bytes instead of 4 + portlength because we read an extra byte already
- [self.proxySocket readDataToLength:(3+portLength) withTimeout:TIMEOUT_READ tag:SOCKS_CONNECT_REPLY_2];
- }
- else if (addressType == 3) // Domain name
- {
- uint8_t addrLength = bytes[4];
-
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: addrLength: %o", addrLength);
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: portLength: %o", portLength);
-
- [self.proxySocket readDataToLength:(addrLength+portLength)
- withTimeout:TIMEOUT_READ
- tag:SOCKS_CONNECT_REPLY_2];
- } else if (addressType == 4) { // IPv6
- [self.proxySocket readDataToLength:(16+portLength) withTimeout:TIMEOUT_READ tag:SOCKS_CONNECT_REPLY_2];
- } else if (addressType == 0) {
- // The size field was actually the first byte of the port field
- // We just have to read in that last byte
- [self.proxySocket readDataToLength:1 withTimeout:TIMEOUT_READ tag:SOCKS_CONNECT_REPLY_2];
- } else {
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: Unknown atyp field in connect reply");
- self.lastDisconnectError = [NSError errorWithDomain:@"socks" code:102 userInfo:@{NSLocalizedDescriptionKey: @"Unknown atyp field in connect reply"}];
- [self.proxySocket disconnect];
- }
- }
- else
- {
- NSString *failureReason = nil;
- switch (rep) {
- case 1:
- failureReason = @"general SOCKS server failure";
- break;
- case 2:
- failureReason = @"connection not allowed by ruleset";
- break;
- case 3:
- failureReason = @"Network unreachable";
- break;
- case 4:
- failureReason = @"Host unreachable";
- break;
- case 5:
- failureReason = @"Connection refused";
- break;
- case 6:
- failureReason = @"TTL expired";
- break;
- case 7:
- failureReason = @"Command not supported";
- break;
- case 8:
- failureReason = @"Address type not supported";
- break;
- default: // X'09' to X'FF' unassigned
- failureReason = @"unknown socks error";
- break;
- }
- DDLogVerbose(@"SOCKS failed, disconnecting: %@", failureReason);
- self.lastDisconnectError = [NSError errorWithDomain:@"socks" code:103 userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"SOCKS failure: %@", failureReason]}];
- // Some kind of error occurred.
-
- [self.proxySocket disconnect];
- }
- }
- else if (tag == SOCKS_CONNECT_REPLY_2)
- {
- // See socksConnect method for socks reply format
-
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: SOCKS_CONNECT_REPLY_2: %@", data);
-
- if (self.delegate && [self.delegate respondsToSelector:@selector(socket:didConnectToHost:port:)]) {
- dispatch_async(self.delegateQueue, ^{
- @autoreleasepool {
- [self.delegate socket:self didConnectToHost:self.destinationHost port:self.destinationPort];
- }
- });
- }
- }
- else if (tag == SOCKS_AUTH_USERPASS) {
- /*
- Server response for username/password authentication:
-
- field 1: version, 1 byte
- field 2: status code, 1 byte.
- 0x00 = success
- any other value = failure, connection must be closed
- */
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: SOCKS_AUTH_USERPASS: %@", data);
- if (data.length == 2) {
- uint8_t *bytes = (uint8_t*)[data bytes];
- uint8_t status = bytes[1];
- if (status == 0x00) {
- [self socksConnect];
- } else {
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: Invalid SOCKS username/password auth");
- self.lastDisconnectError = [NSError errorWithDomain:@"socks" code:104 userInfo:@{NSLocalizedDescriptionKey: @"Invalid SOCKS username/password auth"}];
- [self.proxySocket disconnect];
- return;
- }
- } else {
- DDLogVerbose(@"GCDAsyncSOCKSProxySocket: Invalid SOCKS username/password response length");
- self.lastDisconnectError = [NSError errorWithDomain:@"socks" code:105 userInfo:@{NSLocalizedDescriptionKey: @"Invalid SOCKS username/password response length"}];
- [self.proxySocket disconnect];
- return;
- }
- }
- else {
- if (self.delegate && [self.delegate respondsToSelector:@selector(socket:didReadData:withTag:)]) {
- dispatch_async(self.delegateQueue, ^{
- @autoreleasepool {
- [self.delegate socket:self didReadData:data withTag:tag];
- }
- });
- }
- }
- }
- #pragma mark GCDAsyncSocketDelegate methods
- - (void) socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
- if (self.delegate && [self.delegate respondsToSelector:@selector(socket:didWriteDataWithTag:)]) {
- dispatch_async(self.delegateQueue, ^{
- @autoreleasepool {
- [self.delegate socket:self didWriteDataWithTag:tag];
- }
- });
- }
- }
- - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
- DDLogVerbose(@"proxySocket disconnected from proxy %@:%d / destination %@:%d", self.proxyHost, self.proxyPort, self.destinationHost, self.self.destinationPort);
- if (self.delegate && [self.delegate respondsToSelector:@selector(socketDidDisconnect:withError:)]) {
- dispatch_async(self.delegateQueue, ^{
- @autoreleasepool {
- [self.delegate socketDidDisconnect:self withError:(err != nil ? err : self.lastDisconnectError)];
- }
- });
- }
- }
- - (void) socketDidSecure:(GCDAsyncSocket *)sock {
- DDLogVerbose(@"didSecure proxy %@:%d / destination %@:%d", self.proxyHost, self.proxyPort, self.destinationHost, self.self.destinationPort);
-
- if (self.delegate && [self.delegate respondsToSelector:@selector(socketDidSecure:)]) {
- dispatch_async(self.delegateQueue, ^{
- @autoreleasepool {
- [self.delegate socketDidSecure:self];
- }
- });
- }
- }
- - (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock
- {
- if (self.delegate && [self.delegate respondsToSelector:@selector(socketDidCloseReadStream:)]) {
- dispatch_async(self.delegateQueue, ^{
- @autoreleasepool {
- [self.delegate socketDidCloseReadStream:self];
- }
- });
- }
- }
- - (void)socket:(GCDAsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag
- {
- if (self.delegate && [self.delegate respondsToSelector:@selector(socket:didWritePartialDataOfLength:tag:)]) {
- dispatch_async(self.delegateQueue, ^{
- @autoreleasepool {
- [self.delegate socket:self didWritePartialDataOfLength:partialLength tag:tag];
- }
- });
- }
- }
- - (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL))completionHandler
- {
- if (self.delegate && [self.delegate respondsToSelector:@selector(socket:didReceiveTrust:completionHandler:)]) {
- dispatch_async(self.delegateQueue, ^{
- @autoreleasepool {
- [self.delegate socket:self didReceiveTrust:trust completionHandler:completionHandler];
- }
- });
- }
- }
- @end
|