chrysn / aiocoap

The Python CoAP library
Other
267 stars 120 forks source link

Get bound port of a server #274

Open kamrup opened 2 years ago

kamrup commented 2 years ago

I'm using aiocoap in a test setup where I would like to create a server context bound to a random port. The device I'm testing should then send requests to that server, but how do I get the server port?

Example:

protocol = await Context.create_server_context(site=my_site, bind=("127.0.0.1", 0))

device.set_coap_server_address(("127.0.0.1", get_bound_port(protocol)))

On Windows I haven't found a way to get it, but on Linux I can get it using the following piece of code, but I guess that's not how you're supposed to do it:

remote_and_interface = await protocol.find_remote_and_interface(Message(code=GET, uri="coap://127.0.0.1"))

server_port = remote_and_interface.token_interface.message_interface._local_port()
# or
server_port = remote_and_interface.token_interface.message_interface.transport.get_extra_info('socket').getsockname()[1]

Output of python3 -m aiocoap.cli.defaults:

Windows:

Python version: 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:58:18) [MSC v.1900 64 bit (AMD64)]
aiocoap version: 0.4.3
Modules missing for subsystems:
    dtls: missing DTLSSocket
    oscore: missing cbor2, cryptography, ge25519
    linkheader: missing LinkHeader
    prettyprint: missing LinkHeader, cbor2, termcolor, pygments
Python platform: win32
Default server transports:  tcpserver:tcpclient:tlsserver:tlsclient:simple6:simplesocketserver
Selected server transports: tcpserver:tcpclient:tlsserver:tlsclient:simple6:simplesocketserver
Default client transports:  tcpclient:tlsclient:simple6
Selected client transports: tcpclient:tlsclient:simple6
SO_REUSEPORT available (default, selected): False, False

Linux:

Python version: 3.7.3 (default, Jul 25 2020, 13:03:44)
[GCC 8.3.0]
aiocoap version: 0.4.3
Modules missing for subsystems:
    dtls: missing DTLSSocket
    oscore: missing cbor2, cryptography, filelock, ge25519
    linkheader: missing LinkHeader
    prettyprint: missing LinkHeader, cbor2, termcolor, pygments
Python platform: linux
Default server transports:  tcpserver:tcpclient:tlsserver:tlsclient:udp6
Selected server transports: tcpserver:tcpclient:tlsserver:tlsclient:udp6
Default client transports:  tcpclient:tlsclient:udp6
Selected client transports: tcpclient:tlsclient:udp6
SO_REUSEPORT available (default, selected): True, True
chrysn commented 2 years ago

Binding to a random port is generally not well supported or documented yet, but I'm open to adding that.

I think it should work the same way on Windows in principle, but what makes it break with you concrete approach is that due to Windows' lack of PKTINFO, the server and client portion of the context uses different socket(s), so the server's port is inaccessible through the client socket obtained through find_remote_and_interface.