pydtls/dtls/test/echo_seq.py
Ray Brown 22083e8221 SSL standard library module wire-in
A patch implementation is provided, which augments and alters the Python
standard library's ssl module to support passing of datagram sockets, in which
case this package's DTLS protocol support will be activated. The ssl module's
interface is intended to operate identically regardless of whether the DTLS
protocol or another protocol is chosen.

The following features of the ssl module are explicitly supported with
datagram sockets:

    * socket wrapping, unwrapping, and re-wrapping
    * threaded UDP servers
    * asynchronous UDP servers (asyncore integration)
    * socket servers (SocketServer integration)

The following modules have been added:

    * dtls.patch: standard library module patching code and substitution
                  functions and methods
    * unit.py:    this is a port of the standard library's testing module
                  test_ssl.py for datagram sockets; all tests pass at this time;
                  a couple of inapplicable tests have been dropped; a few other
                  tests have been added

Also note that the err module's exception raising mechanism has been
augmented so as to raise exceptions of type ssl.SSLError (as opposed to
dtls.err.SSLError) when instructed to do so through activation of the patching
mechanism. This allows code written against the standard library module's
interface to remain unchanged. In some cases, types derived from
ssl.SSLError are raised.
2012-11-21 11:23:03 -08:00

103 lines
3.2 KiB
Python

# PyDTLS sequential echo. Written by Ray Brown.
"""PyDTLS sequential echo
This script runs a sequential echo server. It is sequential in that it will
respond without error only to a single sclient that invokes the following steps
in order:
* DTLS cookie exchange on port 28000 of localhost
* DTLS handshake (application-default ciphers)
* Write and receive echo back for an arbitrary number of datagrams
* Isue shutdown notification and receive the shutdown notification response
Note that this script's operation is slow and inefficient on purpose: it
invokes the demux without socket select, but with 5-second timeouts after
the cookie exchange; this is done so that one can follow the debug logs when
operating this server from a client shell interactively.
"""
import socket
from os import path
from logging import basicConfig, DEBUG
basicConfig(level=DEBUG) # set now for dtls import code
from dtls.sslconnection import SSLConnection
from dtls.err import SSLError, SSL_ERROR_WANT_READ, SSL_ERROR_ZERO_RETURN
def main():
sck = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sck.bind(("127.0.0.1", 28000))
sck.settimeout(30)
cert_path = path.join(path.abspath(path.dirname(__file__)), "certs")
scn = SSLConnection(
sck,
keyfile=path.join(cert_path, "server-key.pem"),
certfile=path.join(cert_path, "server-cert.pem"),
server_side=True,
ca_certs=path.join(cert_path, "ca-cert.pem"),
do_handshake_on_connect=False)
cnt = 0
while True:
cnt += 1
print "Listen invocation: %d" % cnt
peer_address = scn.listen()
if peer_address:
print "Completed listening for peer: %s" % str(peer_address)
break
print "Accepting..."
conn = scn.accept()[0]
sck.settimeout(5)
conn.get_socket(True).settimeout(5)
cnt = 0
while True:
cnt += 1
print "Listen invocation: %d" % cnt
peer_address = scn.listen()
assert not peer_address
print "Handshake invocation: %d" % cnt
try:
conn.do_handshake()
except SSLError as err:
if len(err.args) > 1 and err.args[1].args[0] == SSL_ERROR_WANT_READ:
continue
raise
print "Completed handshaking with peer"
break
cnt = 0
while True:
cnt += 1
print "Listen invocation: %d" % cnt
peer_address = scn.listen()
assert not peer_address
print "Read invocation: %d" % cnt
try:
message = conn.read()
except SSLError as err:
if err.args[0] == SSL_ERROR_WANT_READ:
continue
if err.args[0] == SSL_ERROR_ZERO_RETURN:
break
raise
print message
conn.write("Back to you: " + message)
cnt = 0
while True:
cnt += 1
print "Listen invocation: %d" % cnt
peer_address = scn.listen()
assert not peer_address
print "Shutdown invocation: %d" % cnt
try:
conn.shutdown()
except SSLError as err:
if err.args[0] == SSL_ERROR_WANT_READ:
continue
raise
break
if __name__ == "__main__":
main()