ObjFW  Check-in [d9586ed175]

Overview
Comment:Don't assume EWOULDBLOCK and EAGAIN are the same
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: d9586ed17526debf2145aaa34665d15fa65e14752c5dcffb021f835b3b52925a
User & Date: js on 2022-01-28 19:34:41
Other Links: manifest | tags
Context
2022-01-29
12:38
Add OpenSSL support for OFTLSStream check-in: c9b6dcad9e user: js tags: trunk
2022-01-28
19:34
Don't assume EWOULDBLOCK and EAGAIN are the same check-in: d9586ed175 user: js tags: trunk
2022-01-26
18:19
GitHub Actions: Disable TLS for 32 bit Ubuntu check-in: 4aa544351d user: js tags: trunk
Changes

Modified src/OFHTTPServer.m from [9d3b80f535] to [7cab88af66].

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
	if (!_headersSent)
		[self of_sendHeaders];

	if (!_chunked) {
		@try {
			[_socket writeBuffer: buffer length: length];
		} @catch (OFWriteFailedException *e) {
			if (e.errNo == EWOULDBLOCK)
				return e.bytesWritten;

			@throw e;
		}

		return length;
	}







|







228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
	if (!_headersSent)
		[self of_sendHeaders];

	if (!_chunked) {
		@try {
			[_socket writeBuffer: buffer length: length];
		} @catch (OFWriteFailedException *e) {
			if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN)
				return e.bytesWritten;

			@throw e;
		}

		return length;
	}

Modified src/OFLHAArchive.m from [6f31d26ec9] to [ff32dec968].

485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
		[_stream writeBuffer: buffer length: length];
	} @catch (OFWriteFailedException *e) {
		OFEnsure(e.bytesWritten <= length);

		_bytesWritten += (uint32_t)e.bytesWritten;
		_CRC16 = OFCRC16(_CRC16, buffer, e.bytesWritten);

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

		@throw e;
	}

	_bytesWritten += (uint32_t)length;
	_CRC16 = OFCRC16(_CRC16, buffer, length);







|







485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
		[_stream writeBuffer: buffer length: length];
	} @catch (OFWriteFailedException *e) {
		OFEnsure(e.bytesWritten <= length);

		_bytesWritten += (uint32_t)e.bytesWritten;
		_CRC16 = OFCRC16(_CRC16, buffer, e.bytesWritten);

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

		@throw e;
	}

	_bytesWritten += (uint32_t)length;
	_CRC16 = OFCRC16(_CRC16, buffer, length);

Modified src/OFRunLoop.m from [5f45cad885] to [652ae46855].

571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
	@try {
		const char *dataItems = _data.items;
		length = dataLength - _writtenLength;
		[object writeBuffer: dataItems + _writtenLength length: length];
	} @catch (OFWriteFailedException *e) {
		length = e.bytesWritten;

		if (e.errNo != EWOULDBLOCK)
			exception = e;
	} @catch (id e) {
		length = 0;
		exception = e;
	}

	_writtenLength += length;







|







571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
	@try {
		const char *dataItems = _data.items;
		length = dataLength - _writtenLength;
		[object writeBuffer: dataItems + _writtenLength length: length];
	} @catch (OFWriteFailedException *e) {
		length = e.bytesWritten;

		if (e.errNo != EWOULDBLOCK && e.errNo != EAGAIN)
			exception = e;
	} @catch (id e) {
		length = 0;
		exception = e;
	}

	_writtenLength += length;
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
	@try {
		const char *cString = [_string cStringWithEncoding: _encoding];
		length = cStringLength - _writtenLength;
		[object writeBuffer: cString + _writtenLength length: length];
	} @catch (OFWriteFailedException *e) {
		length = e.bytesWritten;

		if (e.errNo != EWOULDBLOCK)
			exception = e;
	} @catch (id e) {
		length = 0;
		exception = e;
	}

	_writtenLength += length;







|







648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
	@try {
		const char *cString = [_string cStringWithEncoding: _encoding];
		length = cStringLength - _writtenLength;
		[object writeBuffer: cString + _writtenLength length: length];
	} @catch (OFWriteFailedException *e) {
		length = e.bytesWritten;

		if (e.errNo != EWOULDBLOCK && e.errNo != EAGAIN)
			exception = e;
	} @catch (id e) {
		length = 0;
		exception = e;
	}

	_writtenLength += length;

Modified src/OFStream.h from [d8c22a2ea2] to [6e060142f4].

827
828
829
830
831
832
833


834
835
836
837
838
839
840
841
842
- (bool)flushWriteBuffer;

/**
 * @brief Writes from a buffer into the stream.
 *
 * In non-blocking mode, if less than the specified length could be written, an
 * @ref OFWriteFailedException is thrown with @ref OFWriteFailedException#errNo


 * being set to `EWOULDBLOCK` and @ref OFWriteFailedException#bytesWritten
 * being set to the number of bytes that were written, if any.
 *
 * @param buffer The buffer from which the data is written into the stream
 * @param length The length of the data that should be written
 */
- (void)writeBuffer: (const void *)buffer length: (size_t)length;

#ifdef OF_HAVE_SOCKETS







>
>
|
|







827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
- (bool)flushWriteBuffer;

/**
 * @brief Writes from a buffer into the stream.
 *
 * In non-blocking mode, if less than the specified length could be written, an
 * @ref OFWriteFailedException is thrown with @ref OFWriteFailedException#errNo
 * being set to `EWOULDBLOCK` or `EAGAIN` (you need to check for both, as they
 * are not the same on some systems) and
 * @ref OFWriteFailedException#bytesWritten being set to the number of bytes
 * that were written, if any.
 *
 * @param buffer The buffer from which the data is written into the stream
 * @param length The length of the data that should be written
 */
- (void)writeBuffer: (const void *)buffer length: (size_t)length;

#ifdef OF_HAVE_SOCKETS

Modified src/OFTarArchive.m from [80091b13c1] to [2761dfa7b5].

440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
	@try {
		[_stream writeBuffer: buffer length: length];
	} @catch (OFWriteFailedException *e) {
		OFEnsure(e.bytesWritten <= length);

		_toWrite -= e.bytesWritten;

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

		@throw e;
	}

	_toWrite -= length;








|







440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
	@try {
		[_stream writeBuffer: buffer length: length];
	} @catch (OFWriteFailedException *e) {
		OFEnsure(e.bytesWritten <= length);

		_toWrite -= e.bytesWritten;

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

		@throw e;
	}

	_toWrite -= length;

Modified src/OFZIPArchive.m from [eb9f1fb6fa] to [0b7b3518b4].

895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
		[_stream writeBuffer: buffer length: length];
	} @catch (OFWriteFailedException *e) {
		OFEnsure(e.bytesWritten <= length);

		_bytesWritten += (int64_t)e.bytesWritten;
		_CRC32 = OFCRC32(_CRC32, buffer, e.bytesWritten);

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

		@throw e;
	}

	_bytesWritten += (int64_t)length;
	_CRC32 = OFCRC32(_CRC32, buffer, length);







|







895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
		[_stream writeBuffer: buffer length: length];
	} @catch (OFWriteFailedException *e) {
		OFEnsure(e.bytesWritten <= length);

		_bytesWritten += (int64_t)e.bytesWritten;
		_CRC32 = OFCRC32(_CRC32, buffer, e.bytesWritten);

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

		@throw e;
	}

	_bytesWritten += (int64_t)length;
	_CRC32 = OFCRC32(_CRC32, buffer, length);

Modified src/tls/OFGnuTLSTLSStream.m from [e2b641b948] to [c3efe28992].

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
							  length: length];
	} @catch (OFReadFailedException *e) {
		gnutls_transport_set_errno(stream->_session, e.errNo);
		return -1;
	}

	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.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;
	}

	return length;
}







|
















|







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
							  length: length];
	} @catch (OFReadFailedException *e) {
		gnutls_transport_set_errno(stream->_session, e.errNo);
		return -1;
	}

	if (length == 0 && !stream.underlyingStream.atEndOfStream) {
		gnutls_transport_set_errno(stream->_session, EAGAIN);
		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.underlyingStream writeBuffer: buffer length: length];
	} @catch (OFWriteFailedException *e) {
		gnutls_transport_set_errno(stream->_session, e.errNo);

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

		return -1;
	}

	return length;
}
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

	if ((ret = gnutls_record_recv(_session, buffer, length)) < 0) {
		/*
		 * The underlying stream might have had data ready, but not
		 * enough for GnuTLS to return decrypted data. This means the
		 * caller might have observed the TLS stream for reading, got a
		 * ready signal and read - and expects the read to succeed, not
		 * to fail with EWOULDBLOCK, as it was signaled ready.
		 * Therefore, return 0, as we could read 0 decrypted bytes, but
		 * cleared the ready signal of the underlying stream.
		 */
		if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
			return 0;

		/* FIXME: Translate error to errNo */







|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

	if ((ret = gnutls_record_recv(_session, buffer, length)) < 0) {
		/*
		 * The underlying stream might have had data ready, but not
		 * enough for GnuTLS to return decrypted data. This means the
		 * caller might have observed the TLS stream for reading, got a
		 * ready signal and read - and expects the read to succeed, not
		 * to fail with EWOULDBLOCK/EAGAIN, as it was signaled ready.
		 * Therefore, return 0, as we could read 0 decrypted bytes, but
		 * cleared the ready signal of the underlying stream.
		 */
		if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
			return 0;

		/* FIXME: Translate error to errNo */
168
169
170
171
172
173
174
175
176
177
178
179

180

181
182
183
184
185
186
187
188
189
190
191
{
	ssize_t ret;

	if (!_handshakeDone)
		@throw [OFNotOpenException exceptionWithObject: self];

	if ((ret = gnutls_record_send(_session, buffer, length)) < 0) {
		/* FIXME: Translate error to errNo */
		int errNo = 0;

		if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
			errNo = EWOULDBLOCK;



		@throw [OFWriteFailedException exceptionWithObject: self
						   requestedLength: length
						      bytesWritten: ret
							     errNo: errNo];
	}

	return ret;
}

- (bool)hasDataInReadBuffer
{







<
<
<

<
>

>



|







168
169
170
171
172
173
174



175

176
177
178
179
180
181
182
183
184
185
186
187
188
189
{
	ssize_t ret;

	if (!_handshakeDone)
		@throw [OFNotOpenException exceptionWithObject: self];

	if ((ret = gnutls_record_send(_session, buffer, length)) < 0) {



		if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)

			return 0;

		/* FIXME: Translate error to errNo */
		@throw [OFWriteFailedException exceptionWithObject: self
						   requestedLength: length
						      bytesWritten: ret
							     errNo: 0];
	}

	return ret;
}

- (bool)hasDataInReadBuffer
{

Modified src/tls/OFSecureTransportTLSStream.m from [30fa947c05] to [ed55ad491c].

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
	size_t length;

	@try {
		length = [((OFTLSStream *)connection).underlyingStream
		    readIntoBuffer: data
			    length: *dataLength];
	} @catch (OFReadFailedException *e) {
		if (e.errNo == EWOULDBLOCK) {
			*dataLength = 0;
			return errSSLWouldBlock;
		}

		@throw e;
	}








|







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
	size_t length;

	@try {
		length = [((OFTLSStream *)connection).underlyingStream
		    readIntoBuffer: data
			    length: *dataLength];
	} @catch (OFReadFailedException *e) {
		if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) {
			*dataLength = 0;
			return errSSLWouldBlock;
		}

		@throw e;
	}

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
	@try {
		[((OFTLSStream *)connection).underlyingStream
		    writeBuffer: data
			 length: *dataLength];
	} @catch (OFWriteFailedException *e) {
		*dataLength = e.bytesWritten;

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

		@throw e;
	}

	return noErr;
}







|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
	@try {
		[((OFTLSStream *)connection).underlyingStream
		    writeBuffer: data
			 length: *dataLength];
	} @catch (OFWriteFailedException *e) {
		*dataLength = e.bytesWritten;

		if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN)
			return errSSLWouldBlock;

		@throw e;
	}

	return noErr;
}