ObjFW  Check-in [a61e0594b4]

Overview
Comment:Add -[OFStream lowlevelIsAtEndOfStream]

This allows for a much cleaner solution to avoid the internal read
buffer of e.g. a TLS connection never being processed while waiting for
a delimiter.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a61e0594b4e17bcc9b652324434f4c9a49afb1a21fcfb9786c74d730299c3cfe
User & Date: js on 2023-10-15 12:32:29
Other Links: manifest | tags
Context
2023-10-15
12:34
Increase library versions check-in: 8f6a9a8ebb user: js tags: trunk
12:32
Add -[OFStream lowlevelIsAtEndOfStream] check-in: a61e0594b4 user: js tags: trunk
2023-10-09
20:16
README.md: Remove Gitter check-in: bdf340d188 user: js tags: trunk
Changes

Modified src/OFGZIPStream.m from [1ebfe8e246] to [9545f9339e].

302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	return _stream.atEndOfStream;
}

- (bool)hasDataInReadBuffer
{
	if (_state == OFGZIPStreamStateData)
		return (super.hasDataInReadBuffer ||
		    _inflateStream.hasDataInReadBuffer);

	return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer);
}

- (void)close
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	[_stream release];
	_stream = nil;

	[super close];
}
@end







|


<
|
|
|













302
303
304
305
306
307
308
309
310
311

312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	return _stream.atEndOfStream;
}

- (bool)lowlevelHasDataInReadBuffer
{
	if (_state == OFGZIPStreamStateData)

		return _inflateStream.hasDataInReadBuffer;
	else
		return _stream.hasDataInReadBuffer;
}

- (void)close
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	[_stream release];
	_stream = nil;

	[super close];
}
@end

Modified src/OFHTTPClient.m from [f5ef5b6f99] to [0348d66062].

1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
	if (_stream == nil)
		return -1;

	return ((OFStream <OFReadyForReadingObserving> *)_stream)
	    .fileDescriptorForReading;
}

- (bool)hasDataInReadBuffer
{
	return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer);
}

- (void)close
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];








|

|







1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
	if (_stream == nil)
		return -1;

	return ((OFStream <OFReadyForReadingObserving> *)_stream)
	    .fileDescriptorForReading;
}

- (bool)lowlevelHasDataInReadBuffer
{
	return _stream.hasDataInReadBuffer;
}

- (void)close
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

Modified src/OFHTTPServer.m from [df8e40fa8b] to [ab884b4ab8].

731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747

		objc_autoreleasePoolPop(pool);

		return 0;
	}
}

- (bool)hasDataInReadBuffer
{
	return (super.hasDataInReadBuffer || _socket.hasDataInReadBuffer);
}

- (int)fileDescriptorForReading
{
	return _socket.fileDescriptorForReading;
}








|

|







731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747

		objc_autoreleasePoolPop(pool);

		return 0;
	}
}

- (bool)lowlevelHasDataInReadBuffer
{
	return _socket.hasDataInReadBuffer;
}

- (int)fileDescriptorForReading
{
	return _socket.fileDescriptorForReading;
}

Modified src/OFInflateStream.m from [7aafb9081b] to [fd902a590d].

670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_stream)
	    .fileDescriptorForReading;
}

- (bool)hasDataInReadBuffer
{
	return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer ||
	    _bufferLength - _bufferIndex > 0);
}

- (void)close
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];







|

|







670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_stream)
	    .fileDescriptorForReading;
}

- (bool)lowlevelHasDataInReadBuffer
{
	return (_stream.hasDataInReadBuffer ||
	    _bufferLength - _bufferIndex > 0);
}

- (void)close
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

Modified src/OFKernelEventObserver.m from [65045f52e2] to [d1361f5797].

204
205
206
207
208
209
210
211
212
213




214
215

216
217
218
219
220
221
222

- (bool)of_processReadBuffers
{
	void *pool = objc_autoreleasePoolPush();
	bool foundInReadBuffer = false;

	for (id object in [[_readObjects copy] autorelease]) {
		void *pool2 = objc_autoreleasePoolPush();

		if ([object isKindOfClass: [OFStream class]] &&




		    [object hasDataInReadBuffer] &&
		    ![(OFStream *)object of_isWaitingForDelimiter]) {

			if ([_delegate respondsToSelector:
			    @selector(objectIsReadyForReading:)])
				[_delegate objectIsReadyForReading: object];

			foundInReadBuffer = true;
		}








|

|
>
>
>
>
|
|
>







204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

- (bool)of_processReadBuffers
{
	void *pool = objc_autoreleasePoolPush();
	bool foundInReadBuffer = false;

	for (id object in [[_readObjects copy] autorelease]) {
		void *pool2;

		if (![object isKindOfClass: [OFStream class]])
			continue;

		pool2 = objc_autoreleasePoolPush();

		if ([object hasDataInReadBuffer] &&
		    (![object of_isWaitingForDelimiter] ||
		    [object lowlevelHasDataInReadBuffer])) {
			if ([_delegate respondsToSelector:
			    @selector(objectIsReadyForReading:)])
				[_delegate objectIsReadyForReading: object];

			foundInReadBuffer = true;
		}

Modified src/OFLHADecompressingStream.m from [a9c8d0ec12] to [94f1868a8f].

503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_stream)
	    .fileDescriptorForReading;
}

- (bool)hasDataInReadBuffer
{
	return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer ||
	    _bufferLength - _bufferIndex > 0);
}

- (void)close
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];







|

|







503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_stream)
	    .fileDescriptorForReading;
}

- (bool)lowlevelHasDataInReadBuffer
{
	return (_stream.hasDataInReadBuffer ||
	    _bufferLength - _bufferIndex > 0);
}

- (void)close
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

Modified src/OFStream.h from [99614e7bb2] to [bdf949a291].

1387
1388
1389
1390
1391
1392
1393












1394
1395
1396
 *
 * @note Override this method with your actual end of stream checking
 *	 implementation when subclassing!
 *
 * @return Whether the lowlevel is at the end of the stream
 */
- (bool)lowlevelIsAtEndOfStream;












@end

OF_ASSUME_NONNULL_END







>
>
>
>
>
>
>
>
>
>
>
>



1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
 *
 * @note Override this method with your actual end of stream checking
 *	 implementation when subclassing!
 *
 * @return Whether the lowlevel is at the end of the stream
 */
- (bool)lowlevelIsAtEndOfStream;

/**
 * @brief Returns whether the lowlevel has data in the read buffer.
 *
 * @warning Do not call this directly!
 *
 * @note Override this method in case your stream can buffer data itself, such
 *	 as when implementing @ref OFTLSStream. If not overridden, it always
 *	 returns false.
 * @return Whether the lowlevel has data in the read buffer
 */
- (bool)lowlevelHasDataInReadBuffer;
@end

OF_ASSUME_NONNULL_END

Modified src/OFStream.m from [15b8e35c16] to [be4eb53104].

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
{
	OFFreeMemory(_readBufferMemory);
	OFFreeMemory(_writeBuffer);

	[super dealloc];
}

- (bool)lowlevelIsAtEndOfStream
{
	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
}











- (id)copy
{
	return [self retain];
}

- (bool)isAtEndOfStream







<
<
<
<
<









>
>
>
>
>
>
>
>
>
>







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
{
	OFFreeMemory(_readBufferMemory);
	OFFreeMemory(_writeBuffer);

	[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)lowlevelIsAtEndOfStream
{
	OF_UNRECOGNIZED_SELECTOR
}

- (bool)lowlevelHasDataInReadBuffer
{
	return false;
}

- (id)copy
{
	return [self retain];
}

- (bool)isAtEndOfStream
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
	} @finally {
		free(UTF8String);
	}
}

- (bool)hasDataInReadBuffer
{
	return (_readBufferLength > 0);
}

- (bool)canBlock
{
	return _canBlock;
}








|







1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
	} @finally {
		free(UTF8String);
	}
}

- (bool)hasDataInReadBuffer
{
	return (_readBufferLength > 0 || [self lowlevelHasDataInReadBuffer]);
}

- (bool)canBlock
{
	return _canBlock;
}

Modified src/OFTLSStream.h from [f204428d75] to [db5ba510f8].

57
58
59
60
61
62
63
64

65
66
67
68

69
70
71
72
73
74
75
76
77
 *
 * @brief A class that provides Transport Layer Security on top of a stream.
 *
 * This class is a class cluster and returns a suitable OFTLSStream subclass,
 * 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.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>
	    *_underlyingStream;
	bool _verifiesCertificates;







|
>
|
<
<
<
>
|
|







57
58
59
60
61
62
63
64
65
66



67
68
69
70
71
72
73
74
75
76
 *
 * @brief A class that provides Transport Layer Security on top of a stream.
 *
 * This class is a class cluster and returns a suitable OFTLSStream subclass,
 * if available.
 *
 * Subclasses need to override @ref lowlevelReadIntoBuffer:length:,
 * @ref lowlevelWriteBuffer:length:,
 * @ref lowlevelHasDataInReadBuffer and
 * @ref asyncPerformClientHandshakeWithHost:runLoopMode:.



 *
 * In order to get access to the underlying stream, @ref underlyingStream can
 * be used.
 */
@interface OFTLSStream: OFStream <OFReadyForReadingObserving,
    OFReadyForWritingObserving>
{
	OFStream <OFReadyForReadingObserving, OFReadyForWritingObserving>
	    *_underlyingStream;
	bool _verifiesCertificates;
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
 *	  stream.
 *
 * @param stream The stream to use as underlying stream. Must not be closed
 *		 before the TLS stream is closed.
 * @return A new, autoreleased TLS stream
 */
+ (instancetype)streamWithStream: (OFStream <OFReadyForReadingObserving,
				       OFReadyForWritingObserving> *)stream;

/**
 * @brief Initializes the TLS stream with the specified stream as its
 *	  underlying stream.
 *
 * @param stream The stream to use as underlying stream. Must not be closed
 *		 before the TLS stream is closed.
 * @return An initialized TLS stream
 */
- (instancetype)initWithStream: (OFStream <OFReadyForReadingObserving,
				     OFReadyForWritingObserving> *)stream
    OF_DESIGNATED_INITIALIZER;

/**
 * @brief Asynchronously performs the TLS client handshake for the specified
 *	  host and calls the delegate afterwards.
 *
 * @param host The host to perform the handshake with







|










|







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
 *	  stream.
 *
 * @param stream The stream to use as underlying stream. Must not be closed
 *		 before the TLS stream is closed.
 * @return A new, autoreleased TLS stream
 */
+ (instancetype)streamWithStream: (OFStream <OFReadyForReadingObserving,
				      OFReadyForWritingObserving> *)stream;

/**
 * @brief Initializes the TLS stream with the specified stream as its
 *	  underlying stream.
 *
 * @param stream The stream to use as underlying stream. Must not be closed
 *		 before the TLS stream is closed.
 * @return An initialized TLS stream
 */
- (instancetype)initWithStream: (OFStream <OFReadyForReadingObserving,
				    OFReadyForWritingObserving> *)stream
    OF_DESIGNATED_INITIALIZER;

/**
 * @brief Asynchronously performs the TLS client handshake for the specified
 *	  host and calls the delegate afterwards.
 *
 * @param host The host to perform the handshake with

Modified src/OFTLSStream.m from [4de584ae09] to [0b19f7bfbb].

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
}

- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length
{
	OF_UNRECOGNIZED_SELECTOR
}

- (bool)hasDataInReadBuffer
{
	return (super.hasDataInReadBuffer ||
	    _underlyingStream.hasDataInReadBuffer);
}

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

- (int)fileDescriptorForReading
{







<
<
<
<
<
<







137
138
139
140
141
142
143






144
145
146
147
148
149
150
}

- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length
{
	OF_UNRECOGNIZED_SELECTOR
}







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

- (int)fileDescriptorForReading
{

Modified src/OFTarArchive.m from [0ba99f6e66] to [1c76370f81].

358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	return _atEndOfStream;
}

- (bool)hasDataInReadBuffer
{
	return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer);
}

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_stream)
	    .fileDescriptorForReading;
}







|

|







358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	return _atEndOfStream;
}

- (bool)lowlevelHasDataInReadBuffer
{
	return _stream.hasDataInReadBuffer;
}

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_stream)
	    .fileDescriptorForReading;
}

Modified src/OFZIPArchive.m from [03f366c882] to [76b549ca53].

937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
				       expectedChecksum: expectedChecksum];
		}
	}

	return ret;
}

- (bool)hasDataInReadBuffer
{
	return (super.hasDataInReadBuffer ||
	    [_decompressedStream hasDataInReadBuffer]);
}

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_decompressedStream)
	    .fileDescriptorForReading;
}







|

|
<







937
938
939
940
941
942
943
944
945
946

947
948
949
950
951
952
953
				       expectedChecksum: expectedChecksum];
		}
	}

	return ret;
}

- (bool)lowlevelHasDataInReadBuffer
{
	return _decompressedStream.hasDataInReadBuffer;

}

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_decompressedStream)
	    .fileDescriptorForReading;
}

Modified src/tls/OFGnuTLSTLSStream.m from [ba84ecba17] to [3f3e9b7029].

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#include "config.h"

#include <errno.h>

#import "OFGnuTLSTLSStream.h"
#import "OFData.h"
#import "OFStream+Private.h"

#import "OFAlreadyOpenException.h"
#import "OFInitializationFailedException.h"
#import "OFNotOpenException.h"
#import "OFReadFailedException.h"
#import "OFTLSHandshakeFailedException.h"
#import "OFWriteFailedException.h"







<







15
16
17
18
19
20
21

22
23
24
25
26
27
28

#include "config.h"

#include <errno.h>

#import "OFGnuTLSTLSStream.h"
#import "OFData.h"


#import "OFAlreadyOpenException.h"
#import "OFInitializationFailedException.h"
#import "OFNotOpenException.h"
#import "OFReadFailedException.h"
#import "OFTLSHandshakeFailedException.h"
#import "OFWriteFailedException.h"
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
						      bytesWritten: ret
							     errNo: 0];
	}

	return ret;
}

- (bool)hasDataInReadBuffer
{
	if (gnutls_record_check_pending(_session) > 0)
		return true;

	return super.hasDataInReadBuffer;
}

- (bool)of_isWaitingForDelimiter
{
	/* FIXME: There should be a non-private API for this. */

	/*
	 * If we still have pending data in the session, we haven't processed
	 * it yet to see if our delimiter is in there. So return false here, as
	 * that will signal the stream as ready for reading, which in turn will
	 * cause a read and checking for the delimiter.
	 */
	if (gnutls_record_check_pending(_session) > 0)
		return false;

	return super.of_waitingForDelimiter;
}

- (void)asyncPerformClientHandshakeWithHost: (OFString *)host
				runLoopMode: (OFRunLoopMode)runLoopMode
{
	static const OFTLSStreamErrorCode initFailedErrorCode =
	    OFTLSStreamErrorCodeInitializationFailed;







|

<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<







181
182
183
184
185
186
187
188
189



190












191



192
193
194
195
196
197
198
						      bytesWritten: ret
							     errNo: 0];
	}

	return ret;
}

- (bool)lowlevelHasDataInReadBuffer
{



	return (_underlyingStream.hasDataInReadBuffer ||












	    gnutls_record_check_pending(_session) > 0);



}

- (void)asyncPerformClientHandshakeWithHost: (OFString *)host
				runLoopMode: (OFRunLoopMode)runLoopMode
{
	static const OFTLSStreamErrorCode initFailedErrorCode =
	    OFTLSStreamErrorCodeInitializationFailed;

Modified src/tls/OFOpenSSLTLSStream.m from [4f42a57c0b] to [175948cb73].

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#include "config.h"

#include <errno.h>

#import "OFOpenSSLTLSStream.h"
#import "OFData.h"
#import "OFStream+Private.h"

#import "OFAlreadyOpenException.h"
#import "OFInitializationFailedException.h"
#import "OFNotOpenException.h"
#import "OFReadFailedException.h"
#import "OFTLSHandshakeFailedException.h"
#import "OFWriteFailedException.h"







<







15
16
17
18
19
20
21

22
23
24
25
26
27
28

#include "config.h"

#include <errno.h>

#import "OFOpenSSLTLSStream.h"
#import "OFData.h"


#import "OFAlreadyOpenException.h"
#import "OFInitializationFailedException.h"
#import "OFNotOpenException.h"
#import "OFReadFailedException.h"
#import "OFTLSHandshakeFailedException.h"
#import "OFWriteFailedException.h"
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
		[_underlyingStream writeBuffer: _buffer length: tmp];
		[_underlyingStream flushWriteBuffer];
	}

	return bytesWritten;
}

- (bool)hasDataInReadBuffer
{
	if (SSL_pending(_SSL) > 0 || BIO_ctrl_pending(_readBIO) > 0)
		return true;

	return super.hasDataInReadBuffer;
}

- (bool)of_isWaitingForDelimiter
{
	/* FIXME: There should be a non-private API for this. */

	/*
	 * If we still have pending data in the SSL connection, we haven't
	 * processed it yet to see if our delimiter is in there. So return
	 * false here, as that will signal the stream as ready for reading,
	 * which in turn will cause a read and checking for the delimiter.
	 */
	if (SSL_pending(_SSL))
		return false;

	/*
	 * If we still have data in our read BIO, it hasn't been processed by
	 * OpenSSL yet. As we have no idea what's in there, return false to
	 * signal the stream as ready for reading, which in turn will cause a
	 * read to check for the delimiter and in turn make OpenSSL process the
	 * data in the read BIO.
	 */
	if (BIO_ctrl_pending(_readBIO) > 0)
		return false;

	return super.of_waitingForDelimiter;
}

- (void)asyncPerformClientHandshakeWithHost: (OFString *)host
				runLoopMode: (OFRunLoopMode)runLoopMode
{
	static const OFTLSStreamErrorCode initFailedErrorCode =
	    OFTLSStreamErrorCodeInitializationFailed;







|

<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<







192
193
194
195
196
197
198
199
200



201






















202



203
204
205
206
207
208
209
		[_underlyingStream writeBuffer: _buffer length: tmp];
		[_underlyingStream flushWriteBuffer];
	}

	return bytesWritten;
}

- (bool)lowlevelHasDataInReadBuffer
{



	return (_underlyingStream.hasDataInReadBuffer ||






















	    SSL_has_pending(_SSL) || BIO_ctrl_pending(_readBIO) > 0);



}

- (void)asyncPerformClientHandshakeWithHost: (OFString *)host
				runLoopMode: (OFRunLoopMode)runLoopMode
{
	static const OFTLSStreamErrorCode initFailedErrorCode =
	    OFTLSStreamErrorCodeInitializationFailed;

Modified src/tls/OFSecureTransportTLSStream.m from [4775886a79] to [89fd642a80].

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 */

#include "config.h"

#include <errno.h>

#import "OFSecureTransportTLSStream.h"
#import "OFStream+Private.h"

#import "OFAlreadyOpenException.h"
#import "OFNotOpenException.h"
#import "OFReadFailedException.h"
#import "OFTLSHandshakeFailedException.h"
#import "OFWriteFailedException.h"








<







14
15
16
17
18
19
20

21
22
23
24
25
26
27
 */

#include "config.h"

#include <errno.h>

#import "OFSecureTransportTLSStream.h"


#import "OFAlreadyOpenException.h"
#import "OFNotOpenException.h"
#import "OFReadFailedException.h"
#import "OFTLSHandshakeFailedException.h"
#import "OFWriteFailedException.h"

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
						   requestedLength: length
						      bytesWritten: bytesWritten
							     errNo: 0];

	return bytesWritten;
}

- (bool)hasDataInReadBuffer
{
	size_t bufferSize;

	if (SSLGetBufferedReadSize(_context, &bufferSize) == noErr &&
	    bufferSize > 0)
		return true;

	return super.hasDataInReadBuffer;
}

- (bool)of_isWaitingForDelimiter
{
	size_t bufferSize;

	/* FIXME: There should be a non-private API for this. */

	/*
	 * If we still have pending data in the context, we haven't processed
	 * it yet to see if our delimiter is in there. So return false here, as
	 * that will signal the stream as ready for reading, which in turn will
	 * cause a read and checking for the delimiter.
	 */
	if (SSLGetBufferedReadSize(_context, &bufferSize) == noErr &&
	    bufferSize > 0)
		return false;

	return super.of_waitingForDelimiter;
}

- (void)asyncPerformClientHandshakeWithHost: (OFString *)host
				runLoopMode: (OFRunLoopMode)runLoopMode
{
	static const OFTLSStreamErrorCode initFailedErrorCode =
	    OFTLSStreamErrorCodeInitializationFailed;







|



<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
<
<
<







164
165
166
167
168
169
170
171
172
173
174




175














176
177



178
179
180
181
182
183
184
						   requestedLength: length
						      bytesWritten: bytesWritten
							     errNo: 0];

	return bytesWritten;
}

- (bool)lowlevelHasDataInReadBuffer
{
	size_t bufferSize;





	return (_underlyingStream.hasDataInReadBuffer ||














	    (SSLGetBufferedReadSize(_context, &bufferSize) == noErr &&
	    bufferSize > 0));



}

- (void)asyncPerformClientHandshakeWithHost: (OFString *)host
				runLoopMode: (OFRunLoopMode)runLoopMode
{
	static const OFTLSStreamErrorCode initFailedErrorCode =
	    OFTLSStreamErrorCodeInitializationFailed;