Differences From Artifact [dab6e3fd2b]:
- File src/OFTLSSocket.m — part of check-in [79ac3fe177] at 2021-11-07 19:39:32 on branch trunk — OFTLSSocket: Reduce methods to override (user: js, size: 4646) [annotate] [blame] [check-ins using]
To Artifact [53f8754aca]:
- File
src/OFTLSStream.m
— part of check-in
[d30efa8bbf]
at
2021-11-13 13:04:13
on branch trunk
— Completely rework the TLS/SSL API
The previous API could never work cleanly and would always require
hacks, as it needed intercepting all interactions of OFTCPSocket with
the raw socket and did not work at all if the OFTCPSocket had anything
in its read buffer before starting the TLS handshake. This also could
not be fixed easily, as it would have required the object to contain two
read buffers, one for the unencrypted connection and one for the
encrypted connection. There was also no clean way to perform the
handshake in a non-blocking way.The new API is a lot cleaner and requires none of the hacks, but using
it requires slightly more work. But this is more than made up for by
making a fully asynchronous handshake possible. It uses the concept of a
stream wrapping another stream, meaning the entire connecting part is
being handled by OFTCPSocket and then the connected socket is passed off
to OFTLSStream to wrap it. This also makes for a lot cleaner separation
of concerns. (user: js, size: 3817) [annotate] [blame] [check-ins using]
︙ | ︙ | |||
11 12 13 14 15 16 17 | * 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" | | | < < < | > > | > | > > | | | > > > | > | | > | < | > > > > | > > > > | > > > > | > > > | > > | > > > > > > > > > > > > > | < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > | > | > > > > | > > > | > > > > > > > > > | > > > > > > | > > > | > > > > | > | > > | > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | * 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 "OFTLSStream.h" #import "OFDate.h" #import "OFNotImplementedException.h" Class OFTLSStreamImplementation = Nil; static const OFRunLoopMode handshakeRunLoopMode = @"OFTLSStreamHandshakeRunLoopMode"; @interface OFTLSStreamHandshakeDelegate: OFObject <OFTLSStreamDelegate> { @public bool _done; id _exception; } @end @implementation OFTLSStreamHandshakeDelegate - (void)dealloc { [_exception release]; [super dealloc]; } - (void)stream: (OFTLSStream *)stream didPerformClientHandshakeWithHost: (OFString *)host exception: (id)exception { _done = true; _exception = [exception retain]; } @end @implementation OFTLSStream @synthesize wrappedStream = _wrappedStream; @dynamic delegate; @synthesize verifiesCertificates = _verifiesCertificates; + (instancetype)alloc { if (self == [OFTLSStream class]) { if (OFTLSStreamImplementation != Nil) return [OFTLSStreamImplementation alloc]; @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; } return [super alloc]; } + (instancetype)streamWithStream: (OFStream <OFReadyForReadingObserving, OFReadyForWritingObserving> *)stream { return [[[self alloc] initWithStream: stream] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } - (instancetype)initWithStream: (OFStream <OFReadyForReadingObserving, OFReadyForWritingObserving> *)stream { self = [super init]; @try { _wrappedStream = [stream retain]; _verifiesCertificates = true; } @catch (id e) { [self release]; @throw e; } return self; } - (void)dealloc { [_wrappedStream release]; [super dealloc]; } - (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)hasDataInReadBuffer { return (super.hasDataInReadBuffer || _wrappedStream.hasDataInReadBuffer); } - (bool)lowlevelIsAtEndOfStream { return _wrappedStream.atEndOfStream; } - (int)fileDescriptorForReading { return _wrappedStream.fileDescriptorForReading; } - (int)fileDescriptorForWriting { return _wrappedStream.fileDescriptorForWriting; } - (void)asyncPerformClientHandshakeWithHost: (OFString *)host { [self asyncPerformClientHandshakeWithHost: host runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncPerformClientHandshakeWithHost: (OFString *)host runLoopMode: (OFRunLoopMode)runLoopMode { OF_UNRECOGNIZED_SELECTOR } - (void)performClientHandshakeWithHost: (OFString *)host { void *pool = objc_autoreleasePoolPush(); id <OFTLSStreamDelegate> delegate = _delegate; OFTLSStreamHandshakeDelegate *handshakeDelegate = [[[OFTLSStreamHandshakeDelegate alloc] init] autorelease]; OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; _delegate = handshakeDelegate; [self asyncPerformClientHandshakeWithHost: host runLoopMode: handshakeRunLoopMode]; while (!handshakeDelegate->_done) [runLoop runMode: handshakeRunLoopMode beforeDate: nil]; /* Cleanup */ [runLoop runMode: handshakeRunLoopMode beforeDate: [OFDate date]]; _delegate = delegate; if (handshakeDelegate->_exception != nil) @throw handshakeDelegate->_exception; objc_autoreleasePoolPop(pool); } @end |