ObjFW  Check-in [0038b55229]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:OFOpenSSLTLSStream: Handle write errors
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 0038b5522994df1f22c367f74b45c675cf59672cd8852bba46d4f989a2313a02
User & Date: js 2025-06-07 20:42:00.040
Context
2025-06-07
21:14
OFRunLoop: Handle truncated writes properly check-in: 2a1d04e962 user: js tags: trunk
20:42
OFOpenSSLTLSStream: Handle write errors check-in: 0b4f45aad4 user: js tags: 1.3
20:42
OFOpenSSLTLSStream: Handle write errors check-in: 0038b55229 user: js tags: trunk
20:20
OFSecureTransportTLSStream: EPIPE & ECONNRESET check-in: 68aaebf332 user: js tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/OFTLSStream.h.
184
185
186
187
188
189
190


191
192
193
194
195
196
197

/**
 * @brief Performs the TLS client handshake for the specified host.
 *
 * @param host The host to perform the handshake with
 * @throw OFTLSHandshakeFailedException The TLS handshake failed
 * @throw OFAlreadyOpenException The handshake was already performed


 */
- (void)performClientHandshakeWithHost: (OFString *)host;

/**
 * @brief Asynchronously performs the TLS server handshake and calls the
 *	  delegate afterwards.
 *







>
>







184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

/**
 * @brief Performs the TLS client handshake for the specified host.
 *
 * @param host The host to perform the handshake with
 * @throw OFTLSHandshakeFailedException The TLS handshake failed
 * @throw OFAlreadyOpenException The handshake was already performed
 * @throw OFReadFailedException The underlying stream had a read error
 * @throw OFWriteFailedException The underlying stream had a write error
 */
- (void)performClientHandshakeWithHost: (OFString *)host;

/**
 * @brief Asynchronously performs the TLS server handshake and calls the
 *	  delegate afterwards.
 *
212
213
214
215
216
217
218


219
220
221
222
223
224
225
- (void)asyncPerformServerHandshakeWithRunLoopMode: (OFRunLoopMode)runLoopMode;

/**
 * @brief Performs the TLS server handshake.
 *
 * @throw OFTLSHandshakeFailedException The TLS handshake failed
 * @throw OFAlreadyOpenException The handshake was already performed


 */
- (void)performServerHandshake;
@end

#ifdef __cplusplus
extern "C" {
#endif







>
>







214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
- (void)asyncPerformServerHandshakeWithRunLoopMode: (OFRunLoopMode)runLoopMode;

/**
 * @brief Performs the TLS server handshake.
 *
 * @throw OFTLSHandshakeFailedException The TLS handshake failed
 * @throw OFAlreadyOpenException The handshake was already performed
 * @throw OFReadFailedException The underlying stream had a read error
 * @throw OFWriteFailedException The underlying stream had a write error
 */
- (void)performServerHandshake;
@end

#ifdef __cplusplus
extern "C" {
#endif
Changes to src/tls/OFOpenSSLTLSStream.m.
142
143
144
145
146
147
148

149

150




151
152
153
154
155
156
157
		SSL_shutdown(_SSL);

		while (BIO_ctrl_pending(_writeBIO) > 0) {
			int tmp = BIO_read(_writeBIO, _buffer, bufferSize);

			OFEnsure(tmp >= 0);


			[_underlyingStream writeBuffer: _buffer length: tmp];

			[_underlyingStream flushWriteBuffer];




		}
	}

	SSL_free(_SSL);
	_SSL = NULL;

	_handshakeDone = false;







>
|
>
|
>
>
>
>







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
		SSL_shutdown(_SSL);

		while (BIO_ctrl_pending(_writeBIO) > 0) {
			int tmp = BIO_read(_writeBIO, _buffer, bufferSize);

			OFEnsure(tmp >= 0);

			@try {
				[_underlyingStream writeBuffer: _buffer
							length: tmp];
				[_underlyingStream flushWriteBuffer];
			} @catch (OFWriteFailedException *e) {
				if (e.errNo != EPIPE && e.errNo != ECONNRESET)
					@throw e;
			}
		}
	}

	SSL_free(_SSL);
	_SSL = NULL;

	_handshakeDone = false;
366
367
368
369
370
371
372

373

374




375
376
377
378
379
380
381
	status = SSL_do_handshake(_SSL);

	while (BIO_ctrl_pending(_writeBIO) > 0) {
		int tmp = BIO_read(_writeBIO, _buffer, bufferSize);

		OFEnsure(tmp >= 0);


		[_underlyingStream writeBuffer: _buffer length: tmp];

		[_underlyingStream flushWriteBuffer];




	}

	if (status == 1)
		_handshakeDone = true;
	else {
		switch (SSL_get_error(_SSL, status)) {
		case SSL_ERROR_WANT_READ:







>
|
>
|
>
>
>
>







372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
	status = SSL_do_handshake(_SSL);

	while (BIO_ctrl_pending(_writeBIO) > 0) {
		int tmp = BIO_read(_writeBIO, _buffer, bufferSize);

		OFEnsure(tmp >= 0);

		@try {
			[_underlyingStream writeBuffer: _buffer
						length: tmp];
			[_underlyingStream flushWriteBuffer];
		} @catch (OFWriteFailedException *e) {
			exception = e;
			goto inform_delegate;
		}
	}

	if (status == 1)
		_handshakeDone = true;
	else {
		switch (SSL_get_error(_SSL, status)) {
		case SSL_ERROR_WANT_READ:
411
412
413
414
415
416
417

418
419
420
421
422
423
424
			    exceptionWithStream: self
					   host: host
				      errorCode: OFTLSStreamErrorCodeUnknown];
			break;
		}
	}


	if (server) {
		if ([_delegate respondsToSelector: @selector(
		    streamDidPerformServerHandshake:exception:)])
			[_delegate streamDidPerformServerHandshake: self
							 exception: exception];
	} else {
		if ([_delegate respondsToSelector: @selector(







>







423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
			    exceptionWithStream: self
					   host: host
				      errorCode: OFTLSStreamErrorCodeUnknown];
			break;
		}
	}

inform_delegate:
	if (server) {
		if ([_delegate respondsToSelector: @selector(
		    streamDidPerformServerHandshake:exception:)])
			[_delegate streamDidPerformServerHandshake: self
							 exception: exception];
	} else {
		if ([_delegate respondsToSelector: @selector(
464
465
466
467
468
469
470

471

472




473
474
475
476
477
478
479
		status = SSL_do_handshake(_SSL);

		while (BIO_ctrl_pending(_writeBIO) > 0) {
			int tmp = BIO_read(_writeBIO, buffer, bufferSize);

			OFEnsure(tmp >= 0);


			[_underlyingStream writeBuffer: _buffer length: tmp];

			[_underlyingStream flushWriteBuffer];




		}

		if (status == 1)
			_handshakeDone = true;
		else {
			switch (SSL_get_error(_SSL, status)) {
			case SSL_ERROR_WANT_READ:







>
|
>
|
>
>
>
>







477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
		status = SSL_do_handshake(_SSL);

		while (BIO_ctrl_pending(_writeBIO) > 0) {
			int tmp = BIO_read(_writeBIO, buffer, bufferSize);

			OFEnsure(tmp >= 0);

			@try {
				[_underlyingStream writeBuffer: _buffer
							length: tmp];
				[_underlyingStream flushWriteBuffer];
			} @catch (OFWriteFailedException *e) {
				exception = e;
				goto inform_delegate;
			}
		}

		if (status == 1)
			_handshakeDone = true;
		else {
			switch (SSL_get_error(_SSL, status)) {
			case SSL_ERROR_WANT_READ:
503
504
505
506
507
508
509

510
511
512
513
514
515
516
						   host: _host
					      errorCode: unknownErrorCode];
				break;
			}
		}
	}


	if (_server) {
		if ([_delegate respondsToSelector: @selector(
		    streamDidPerformServerHandshake:exception:)])
			[_delegate streamDidPerformServerHandshake: self
							 exception: exception];
	} else {
		if ([_delegate respondsToSelector: @selector(







>







522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
						   host: _host
					      errorCode: unknownErrorCode];
				break;
			}
		}
	}

inform_delegate:
	if (_server) {
		if ([_delegate respondsToSelector: @selector(
		    streamDidPerformServerHandshake:exception:)])
			[_delegate streamDidPerformServerHandshake: self
							 exception: exception];
	} else {
		if ([_delegate respondsToSelector: @selector(
537
538
539
540
541
542
543

544

545




546
547
548
549
550
551
552
553
554
555

556

557




558
559
560
561
562
563
564
		OFRunLoopMode runLoopMode;

		while (BIO_ctrl_pending(_writeBIO) > 0) {
			int tmp = BIO_read(_writeBIO, _buffer, bufferSize);

			OFEnsure(tmp >= 0);


			[_underlyingStream writeBuffer: _buffer length: tmp];

			[_underlyingStream flushWriteBuffer];




		}

		ERR_clear_error();
		status = SSL_do_handshake(_SSL);

		while (BIO_ctrl_pending(_writeBIO) > 0) {
			int tmp = BIO_read(_writeBIO, _buffer, bufferSize);

			OFEnsure(tmp >= 0);


			[_underlyingStream writeBuffer: _buffer length: tmp];

			[_underlyingStream flushWriteBuffer];




		}

		if (status == 1)
			_handshakeDone = true;
		else {
			switch (SSL_get_error(_SSL, status)) {
			case SSL_ERROR_WANT_READ:







>
|
>
|
>
>
>
>










>
|
>
|
>
>
>
>







557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
		OFRunLoopMode runLoopMode;

		while (BIO_ctrl_pending(_writeBIO) > 0) {
			int tmp = BIO_read(_writeBIO, _buffer, bufferSize);

			OFEnsure(tmp >= 0);

			@try {
				[_underlyingStream writeBuffer: _buffer
							length: tmp];
				[_underlyingStream flushWriteBuffer];
			} @catch (OFWriteFailedException *e) {
				exception = e;
				goto inform_delegate;
			}
		}

		ERR_clear_error();
		status = SSL_do_handshake(_SSL);

		while (BIO_ctrl_pending(_writeBIO) > 0) {
			int tmp = BIO_read(_writeBIO, _buffer, bufferSize);

			OFEnsure(tmp >= 0);

			@try {
				[_underlyingStream writeBuffer: _buffer
							length: tmp];
				[_underlyingStream flushWriteBuffer];
			} @catch (OFWriteFailedException *e) {
				exception = e;
				goto inform_delegate;
			}
		}

		if (status == 1)
			_handshakeDone = true;
		else {
			switch (SSL_get_error(_SSL, status)) {
			case SSL_ERROR_WANT_READ:
583
584
585
586
587
588
589

590
591
592
593
594
595
596
						   host: _host
					      errorCode: unknownErrorCode];
				break;
			}
		}
	}


	if (_server) {
		if ([_delegate respondsToSelector: @selector(
		    streamDidPerformServerHandshake:exception:)])
			[_delegate streamDidPerformServerHandshake: self
							 exception: exception];
	} else {
		if ([_delegate respondsToSelector: @selector(







>







615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
						   host: _host
					      errorCode: unknownErrorCode];
				break;
			}
		}
	}

inform_delegate:
	if (_server) {
		if ([_delegate respondsToSelector: @selector(
		    streamDidPerformServerHandshake:exception:)])
			[_delegate streamDidPerformServerHandshake: self
							 exception: exception];
	} else {
		if ([_delegate respondsToSelector: @selector(