/* * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #import "OFTLSSocket.h" #import "OFSocket.h" #import "OFSocket+Private.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotImplementedException.h" Class OFTLSSocketImplementation = Nil; @interface OFTLSSocketAsyncConnector: OFObject <OFTLSSocketDelegate> { OFTLSSocket *_socket; OFString *_host; uint16_t _port; id <OFTLSSocketDelegate> _delegate; } - (instancetype)initWithSocket: (OFTLSSocket *)sock host: (OFString *)host port: (uint16_t)port delegate: (id <OFTLSSocketDelegate>)delegate; @end @implementation OFTLSSocketAsyncConnector - (instancetype)initWithSocket: (OFTLSSocket *)sock host: (OFString *)host port: (uint16_t)port delegate: (id <OFTLSSocketDelegate>)delegate { self = [super init]; @try { _socket = [sock retain]; _host = [host copy]; _port = port; _delegate = [delegate retain]; _socket.delegate = self; } @catch (id e) { [self release]; @throw e; } return self; } - (void)dealloc { if (_socket.delegate == self) _socket.delegate = _delegate; [_socket release]; [_delegate release]; [super dealloc]; } - (void)socket: (OFTCPSocket *)sock didConnectToHost: (OFString *)host port: (uint16_t)port exception: (id)exception { if (exception == nil) { @try { [(OFTLSSocket *)sock startTLSForHost: _host port: _port]; } @catch (id e) { [self release]; @throw e; } } _socket.delegate = _delegate; [_delegate socket: sock didConnectToHost: host port: port exception: exception]; } @end @implementation OFTLSSocket @dynamic delegate; @synthesize verifiesCertificates = _verifiesCertificates; + (instancetype)alloc { if (self == [OFTLSSocket class]) { if (OFTLSSocketImplementation == nil) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; return [OFTLSSocketImplementation alloc]; } return [super alloc]; } - (instancetype)init { self = [super init]; _verifiesCertificates = true; return self; } - (instancetype)initWithSocket: (OFTCPSocket *)socket { self = [super init]; @try { if ([socket isKindOfClass: [OFTLSSocket class]]) @throw [OFInvalidArgumentException exception]; if ((_socket = dup(socket->_socket)) == OFInvalidSocketHandle) @throw [OFInitializationFailedException exception]; _verifiesCertificates = true; } @catch (id e) { [self release]; @throw e; } return self; } - (void)startTLSForHost: (OFString *)host port: (uint16_t)port { OF_UNRECOGNIZED_SELECTOR } - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode { void *pool = objc_autoreleasePoolPush(); [[[OFTLSSocketAsyncConnector alloc] initWithSocket: self host: host port: port delegate: _delegate] autorelease]; [super asyncConnectToHost: host port: port runLoopMode: runLoopMode]; objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_BLOCKS - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode block: (OFTCPSocketAsyncConnectBlock)block { [super asyncConnectToHost: host port: port runLoopMode: runLoopMode block: ^ (id exception) { if (exception == nil) { @try { [self startTLSForHost: host port: port]; } @catch (id e) { block(e); return; } } block(exception); }]; } #endif - (instancetype)accept { OF_UNRECOGNIZED_SELECTOR } - (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { OF_UNRECOGNIZED_SELECTOR } - (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { OF_UNRECOGNIZED_SELECTOR } - (bool)lowlevelIsAtEndOfStream { OF_UNRECOGNIZED_SELECTOR } - (instancetype)TCPAccept { return [super accept]; } - (size_t)lowlevelTCPReadIntoBuffer: (void *)buffer length: (size_t)length { return [super lowlevelReadIntoBuffer: buffer length: length]; } - (size_t)lowlevelTCPWriteBuffer: (const void *)buffer length: (size_t)length { return [super lowlevelWriteBuffer: buffer length: length]; } - (bool)lowlevelTCPIsAtEndOfStream { return [super lowlevelIsAtEndOfStream]; } @end