https://gitlab.synchro.net/main/sbbs/-/commit/ab31f9f1c04c35ede2c86d15f44b1a4836a092c9#note_10872
[P2] A short successful pop can leave a pending TLS error
Setting `tls_drained` whenever `copied < len` can suppress a pending TLS error indefinitely while the underlying TCP connection remains open and idle. Cryptlib can return `CRYPT_OK` with a short byte count after copying valid plaintext and then encountering a fatal error on the next record; it saves that error for the next `cryptPopData()` call. No plaintext remains, but the TLS session still needs another pop to report the error.
I reproduced this against the available native cryptlib library with a local TLS 1.2 peer: send `hello`, then a corrupt TLS application-data record, and keep TCP open. The results were:
```
first cryptPopData(..., 4096, ...): status=0, copied=5
raw descriptor poll(POLLIN): 0
next cryptPopData(..., 1, ...): status=-33, copied=0
```
This assignment sets `tls_drained=true` after the first pop. Subsequent `js_socket_tls_readable()` calls therefore skip the pop that would expose the saved error, and descriptor polling cannot discover an error already consumed by cryptlib. Previously, the next probe exposed it and let the normal receive path handle it. An event-driven reader can now wait until additional network activity or TCP closure instead of reporting the TLS failure.
The drained-session optimization needs to preserve notification of pending TLS errors as well as buffered plaintext. The ordinary incoming-data path still works because the descriptor continues to be polled; this finding concerns the saved-error case. This reproduction exercises cryptlib directly, rather than the full JavaScript event loop.
--- SBBSecho 3.38-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)