ObjFW  Check-in [3ed8cf7a52]

Overview
Comment:OFTLSStream: wrappedStream -> underlyingStream
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 3ed8cf7a5236bf395a6185a412f22ad309016d9475afae954476cb5fca4ea0b5
User & Date: js on 2021-11-21 10:40:27
Other Links: manifest | tags
Context
2021-11-21
20:50
Fix building with GnuTLS support on Windows (check-in: 2bdee7e97d user: js tags: trunk)
10:40
OFTLSStream: wrappedStream -> underlyingStream (check-in: 3ed8cf7a52 user: js tags: trunk)
10:18
OFSecureTransportTLSStream: Fix EWOULDBLOCK (check-in: 8cd4bd9fdd user: js tags: trunk)
Changes

Modified src/OFTLSStream.h from [b3a209020a] to [d05dc14c91].

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
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







-
-
-
+
+
+





-
+





-
+


-
+







 * if available.
 *
 * Subclasses need to override @ref lowlevelReadIntoBuffer:length:,
 * @ref lowlevelWriteBuffer:length: and
 * @ref asyncPerformClientHandshakeWithHost:runLoopMode:. The method
 * @ref hasDataInReadBuffer should be overridden to return `true` if the TLS
 * stream has cached unprocessed data internally, while returning
 * `self.wrappedStream.hasDataInReadBuffer` if it does not have any unprocessed
 * data. In order to get access to the wrapped stream, @ref wrappedStream can
 * be used.
 * `self.underlyingStream.hasDataInReadBuffer` if it does not have any
 * unprocessed data. In order to get access to the underlying stream,
 * @ref underlyingStream can be used.
 */
@interface OFTLSStream: OFStream <OFReadyForReadingObserving,
    OFReadyForWritingObserving>
{
	OFStream <OFReadyForReadingObserving, OFReadyForWritingObserving>
	    *_wrappedStream;
	    *_underlyingStream;
	bool _verifiesCertificates;
	OF_RESERVE_IVARS(OFTLSStream, 4)
}

/**
 * @brief The wrapped stream.
 * @brief The underlying stream.
 */
@property (readonly, nonatomic) OFStream <OFReadyForReadingObserving,
    OFReadyForWritingObserving> *wrappedStream;
    OFReadyForWritingObserving> *underlyingStream;

/**
 * @brief The delegate for asynchronous operations on the stream.
 *
 * @note The delegate is retained for as long as asynchronous operations are
 *	 still ongoing.
 */

Modified src/OFTLSStream.m from [659fa26933] to [de0cb549c8].

68
69
70
71
72
73
74
75

76
77
78
79
80
81
82
68
69
70
71
72
73
74

75
76
77
78
79
80
81
82







-
+







{
	_done = true;
	_exception = [exception retain];
}
@end

@implementation OFTLSStream
@synthesize wrappedStream = _wrappedStream;
@synthesize underlyingStream = _underlyingStream;
@dynamic delegate;
@synthesize verifiesCertificates = _verifiesCertificates;

+ (instancetype)alloc
{
	if (self == [OFTLSStream class]) {
		if (OFTLSStreamImplementation != Nil)
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
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







-
+











-
+






-
-
+
+

















-
+




-
+




-
+




-
+








- (instancetype)initWithStream: (OFStream <OFReadyForReadingObserving,
				     OFReadyForWritingObserving> *)stream
{
	self = [super init];

	@try {
		_wrappedStream = [stream retain];
		_underlyingStream = [stream retain];
		_verifiesCertificates = true;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_wrappedStream release];
	[_underlyingStream release];

	[super dealloc];
}

- (void)close
{
	[_wrappedStream release];
	_wrappedStream = nil;
	[_underlyingStream release];
	_underlyingStream = nil;

	[super close];
}

- (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);
	    _underlyingStream.hasDataInReadBuffer);
}

- (bool)lowlevelIsAtEndOfStream
{
	return _wrappedStream.atEndOfStream;
	return _underlyingStream.atEndOfStream;
}

- (int)fileDescriptorForReading
{
	return _wrappedStream.fileDescriptorForReading;
	return _underlyingStream.fileDescriptorForReading;
}

- (int)fileDescriptorForWriting
{
	return _wrappedStream.fileDescriptorForWriting;
	return _underlyingStream.fileDescriptorForWriting;
}

- (void)asyncPerformClientHandshakeWithHost: (OFString *)host
{
	[self asyncPerformClientHandshakeWithHost: host
				      runLoopMode: OFDefaultRunLoopMode];
}

Modified src/tls/OFGnuTLSTLSStream.m from [633e4da737] to [72367f1922].

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
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







-
+






-
+













-
+







@implementation OFGnuTLSTLSStream
static ssize_t
readFunc(gnutls_transport_ptr_t transport, void *buffer, size_t length)
{
	OFGnuTLSTLSStream *stream = (OFGnuTLSTLSStream *)transport;

	@try {
		length = [stream.wrappedStream readIntoBuffer: buffer
		length = [stream.underlyingStream readIntoBuffer: buffer
						       length: length];
	} @catch (OFReadFailedException *e) {
		gnutls_transport_set_errno(stream->_session, e.errNo);
		return -1;
	}

	if (length == 0 && !stream.wrappedStream.atEndOfStream) {
	if (length == 0 && !stream.underlyingStream.atEndOfStream) {
		gnutls_transport_set_errno(stream->_session, EWOULDBLOCK);
		return -1;
	}

	return length;
}

static ssize_t
writeFunc(gnutls_transport_ptr_t transport, const void *buffer, size_t length)
{
	OFGnuTLSTLSStream *stream = (OFGnuTLSTLSStream *)transport;

	@try {
		[stream.wrappedStream writeBuffer: buffer length: length];
		[stream.underlyingStream writeBuffer: buffer length: length];
	} @catch (OFWriteFailedException *e) {
		gnutls_transport_set_errno(stream->_session, e.errNo);

		if (e.errNo == EWOULDBLOCK)
			return e.bytesWritten;

		return -1;
90
91
92
93
94
95
96
97

98
99
100
101
102
103
104
90
91
92
93
94
95
96

97
98
99
100
101
102
103
104







-
+








- (instancetype)initWithStream: (OFStream <OFReadyForReadingObserving,
				     OFReadyForWritingObserving> *)stream
{
	self = [super initWithStream: stream];

	@try {
		_wrappedStream.delegate = self;
		_underlyingStream.delegate = self;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
234
235
236
237
238
239
240
241

242
243
244
245

246
247
248
249
250
251
252
234
235
236
237
238
239
240

241
242
243
244

245
246
247
248
249
250
251
252







-
+



-
+







	if (_verifiesCertificates)
		gnutls_session_set_verify_cert(_session, _host.UTF8String, 0);

	status = gnutls_handshake(_session);

	if (status == GNUTLS_E_INTERRUPTED || status == GNUTLS_E_AGAIN) {
		if (gnutls_record_get_direction(_session) == 1)
			[_wrappedStream
			[_underlyingStream
			    asyncWriteData: [OFData dataWithItems: "" count: 0]
			       runLoopMode: runLoopMode];
		else
			[_wrappedStream asyncReadIntoBuffer: (void *)"" 
			[_underlyingStream asyncReadIntoBuffer: (void *)"" 
						     length: 0
						runLoopMode: runLoopMode];

		[_delegate retain];
		return;
	}

277
278
279
280
281
282
283
284

285
286
287
288
289
290
291
277
278
279
280
281
282
283

284
285
286
287
288
289
290
291







-
+







		if (status == GNUTLS_E_INTERRUPTED ||
		    status == GNUTLS_E_AGAIN) {
			if (gnutls_record_get_direction(_session) == 1) {
				OFData *data = [OFData dataWithItems: ""
							       count: 0];
				OFRunLoopMode runLoopMode =
				    [OFRunLoop currentRunLoop].currentMode;
				[_wrappedStream asyncWriteData: data
				[_underlyingStream asyncWriteData: data
						   runLoopMode: runLoopMode];
				return false;
			} else
				return true;
		}

		if (status != GNUTLS_E_SUCCESS)
319
320
321
322
323
324
325
326

327
328
329
330
331
332
333
319
320
321
322
323
324
325

326
327
328
329
330
331
332
333







-
+







		if (status == GNUTLS_E_INTERRUPTED ||
		    status == GNUTLS_E_AGAIN) {
			if (gnutls_record_get_direction(_session) == 1)
				return data;
			else {
				OFRunLoopMode runLoopMode =
				    [OFRunLoop currentRunLoop].currentMode;
				[_wrappedStream
				[_underlyingStream
				    asyncReadIntoBuffer: (void *)"" 
						 length: 0
					    runLoopMode: runLoopMode];
				return nil;
			}
		}

Modified src/tls/OFSecureTransportTLSStream.m from [e80afd9547] to [446883c227].

30
31
32
33
34
35
36
37

38
39
40
41
42
43
44
30
31
32
33
34
35
36

37
38
39
40
41
42
43
44







-
+







static OSStatus
readFunc(SSLConnectionRef connection, void *data, size_t *dataLength)
{
	bool incomplete;
	size_t length;

	@try {
		length = [((OFTLSStream *)connection).wrappedStream
		length = [((OFTLSStream *)connection).underlyingStream
		    readIntoBuffer: data
			    length: *dataLength];
	} @catch (OFReadFailedException *e) {
		if (e.errNo == EWOULDBLOCK) {
			*dataLength = 0;
			return errSSLWouldBlock;
		}
52
53
54
55
56
57
58
59

60
61
62
63
64
65
66
52
53
54
55
56
57
58

59
60
61
62
63
64
65
66







-
+







	return (incomplete ? errSSLWouldBlock : noErr);
}

static OSStatus
writeFunc(SSLConnectionRef connection, const void *data, size_t *dataLength)
{
	@try {
		[((OFTLSStream *)connection).wrappedStream
		[((OFTLSStream *)connection).underlyingStream
		    writeBuffer: data
			 length: *dataLength];
	} @catch (OFWriteFailedException *e) {
		*dataLength = e.bytesWritten;

		if (e.errNo == EWOULDBLOCK)
			return errSSLWouldBlock;
87
88
89
90
91
92
93
94

95
96
97
98
99
100
101
87
88
89
90
91
92
93

94
95
96
97
98
99
100
101







-
+








- (instancetype)initWithStream: (OFStream <OFReadyForReadingObserving,
				     OFReadyForWritingObserving> *)stream
{
	self = [super initWithStream: stream];

	@try {
		_wrappedStream.delegate = self;
		_underlyingStream.delegate = self;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
215
216
217
218
219
220
221
222

223
224
225
226
227
228
229
215
216
217
218
219
220
221

222
223
224
225
226
227
228
229







-
+







		 * Theoretically it is possible we block because Secure
		 * Transport cannot write without blocking. But unfortunately,
		 * Secure Transport does not tell us whether it's blocked on
		 * reading or writing. Waiting for the stream to be either
		 * readable or writable doesn't work either, as the stream is
		 * almost always at least ready for one of the two.
		 */
		[_wrappedStream asyncReadIntoBuffer: (void *)"" 
		[_underlyingStream asyncReadIntoBuffer: (void *)"" 
					     length: 0
					runLoopMode: runLoopMode];
		[_delegate retain];
		return;
	}

	if (status != noErr)