Merge pull request #42 from Moballo-LLC/codex/py-08a1-completed-handshake
fix(protocol): retain completed DTLS handshakes
This commit is contained in:
4 files changed
+23
-11
No files matched your search
@@ -57,6 +57,10 @@ retransmissions within that same deadline:
|
|||||||
sess.connect(timeout=4.0)
|
sess.connect(timeout=4.0)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The deadline stops further setup, retries, and network waits. If OpenSSL
|
||||||
|
reports that the handshake completed at the deadline boundary, the completed
|
||||||
|
session is retained rather than torn down as a timeout.
|
||||||
|
|
||||||
Connection attempts can also use a one-way cancellation signal. The signal is
|
Connection attempts can also use a one-way cancellation signal. The signal is
|
||||||
backed by a socketpair, so setting it wakes the network wait immediately while
|
backed by a socketpair, so setting it wakes the network wait immediately while
|
||||||
OpenSSL retains control of DTLS retransmission timing:
|
OpenSSL retains control of DTLS retransmission timing:
|
||||||
|
|||||||
@@ -34,14 +34,16 @@ def _drive_dtls_handshake(
|
|||||||
bounded only by its deadline, while the diagnostic probe retains its
|
bounded only by its deadline, while the diagnostic probe retains its
|
||||||
explicit retry budget.
|
explicit retry budget.
|
||||||
|
|
||||||
Return ``True`` only when the handshake completes before the deadline.
|
Return ``True`` once OpenSSL reports the handshake complete. The deadline
|
||||||
TLS and socket failures are left to the caller to classify.
|
prevents another setup, retry, or network-wait iteration; it does not tear
|
||||||
|
down a session that completed while ``do_handshake()`` was running. TLS and
|
||||||
|
socket failures are left to the caller to classify.
|
||||||
"""
|
"""
|
||||||
retransmits = 0
|
retransmits = 0
|
||||||
while time.monotonic() < deadline:
|
while time.monotonic() < deadline:
|
||||||
try:
|
try:
|
||||||
connection.do_handshake()
|
connection.do_handshake()
|
||||||
return time.monotonic() < deadline
|
return True
|
||||||
except SSL.WantReadError:
|
except SSL.WantReadError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -322,13 +322,15 @@ class DtlsCoapSession:
|
|||||||
timeout: float | None = None,
|
timeout: float | None = None,
|
||||||
cancel: ConnectCancellation | None = None,
|
cancel: ConnectCancellation | None = None,
|
||||||
):
|
):
|
||||||
"""Perform a cancellable DTLS handshake within a monotonic deadline.
|
"""Perform a cancellable DTLS handshake using a monotonic deadline.
|
||||||
|
|
||||||
``timeout`` overrides ``HANDSHAKE_TIMEOUT_S`` for this call. OpenSSL
|
``timeout`` overrides ``HANDSHAKE_TIMEOUT_S`` for this call. OpenSSL
|
||||||
owns DTLS retransmission timing while every receive is capped by the
|
owns DTLS retransmission timing while every receive is capped by the
|
||||||
remaining budget, so wall-clock adjustments cannot change the bound.
|
remaining budget, so wall-clock adjustments cannot change the bound.
|
||||||
A ``ConnectCancellation`` wakes the network wait immediately and does
|
Once OpenSSL reports completion, that completed session is retained
|
||||||
not alter an already established session.
|
even if the call returns just after the deadline. A
|
||||||
|
``ConnectCancellation`` wakes the network wait immediately and does not
|
||||||
|
alter an already established session.
|
||||||
"""
|
"""
|
||||||
handshake_timeout = _validate_handshake_timeout(
|
handshake_timeout = _validate_handshake_timeout(
|
||||||
timeout, self.HANDSHAKE_TIMEOUT_S)
|
timeout, self.HANDSHAKE_TIMEOUT_S)
|
||||||
|
|||||||
@@ -323,12 +323,12 @@ def test_connect_services_openssl_retransmit_timer(monkeypatch):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("success_delay", (0.1, 0.2))
|
@pytest.mark.parametrize("success_delay", (0.1, 0.2))
|
||||||
def test_handshake_success_at_or_after_deadline_is_rejected(
|
def test_handshake_success_at_or_after_deadline_is_retained(
|
||||||
monkeypatch,
|
monkeypatch,
|
||||||
success_delay,
|
success_delay,
|
||||||
):
|
):
|
||||||
clock = _Clock()
|
clock = _Clock()
|
||||||
connection, sock, _endpoint, _open_calls = _install_handshake(
|
connection, sock, endpoint, _open_calls = _install_handshake(
|
||||||
monkeypatch,
|
monkeypatch,
|
||||||
clock,
|
clock,
|
||||||
)
|
)
|
||||||
@@ -338,7 +338,11 @@ def test_handshake_success_at_or_after_deadline_is_rejected(
|
|||||||
|
|
||||||
connection.do_handshake = late_success
|
connection.do_handshake = late_success
|
||||||
|
|
||||||
with pytest.raises(SessionTimeoutError):
|
session = _session()
|
||||||
_session().connect(timeout=0.1)
|
session.connect(timeout=0.1)
|
||||||
|
|
||||||
assert sock.closed
|
assert session.conn is connection
|
||||||
|
assert session.sock is sock
|
||||||
|
assert session.endpoint is endpoint
|
||||||
|
assert session.dest == endpoint.sockaddr
|
||||||
|
assert not sock.closed
|
||||||
Reference in new issue
Block a user