aiocoap icon indicating copy to clipboard operation
aiocoap copied to clipboard

Server hangs

Open GeorgeCGV opened this issue 2 years ago • 2 comments

I am testing a basic server client example.

The server is done as per the existing example:

class TestRes(aiocoap.resource.ObservableResource):
    async def render_get(self, request):
        return aiocoap.Message(code=aiocoap.numbers.Code.BAD_REQUEST)

root = resource.Site()

root.add_resource(['.well-known', 'core'], resource.WKCResource(root.get_resources_as_linkheader))
root.add_resource(['some','res'], TestRes())

asyncio.Task(aiocoap.Context.create_server_context(bind=(addr,port), site=root))
asyncio.get_event_loop().run_forever()

I place a breakpoint within render_get and invoke a CoAP client that is then terminated while the server is waiting at the breakpoint.

The server code goes into (as it detects that the connection was terminated):

def error_received(self, exception):
    # This is why this whole implementation is a bad idea (but still the best we got on some platforms)
    self.log.warning("Ignoring error because it can not be mapped to any connection: %s", exception)

Unfortunately, the server won't be able to accept any incoming requests from the client anymore. The client goes into constant retransmissions when re-run.

I am not sure why the server is not able to recover... Would appreciate any help.

  • OS: Windows 10
  • Python: 3.8.0
  • aiocoap: 0.4.7
  • asyncio: 3.4.3

python3 -m aiocoap.cli.defaults:

Python version: 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:21:23) [MSC v.1916 32 bit (Intel)] aiocoap version: 0.4.7 Modules missing for subsystems: dtls: missing DTLSSocket oscore: missing cbor2, cryptography, filelock, ge25519 linkheader: everything there prettyprint: missing 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

GeorgeCGV avatar May 26 '23 16:05 GeorgeCGV

I can't quite reproduce and understand this:

You say the client is terminated while the server is waiting. Later you mention it's not accepting any requests from the client any more. Are you trying again from the same IP address? Same port? (Probably not, as the simple6 transport picks a random port for requests).

The way I've tested it is:

  • Run this server
import aiocoap
from aiocoap import resource
import asyncio

class TestRes(resource.ObservableResource):
    async def render_get(self, request):
        breakpoint()
        return aiocoap.Message(code=aiocoap.numbers.Code.BAD_REQUEST)

root = resource.Site()

root.add_resource(['.well-known', 'core'], resource.WKCResource(root.get_resources_as_linkheader))
root.add_resource(['some','res'], TestRes())

asyncio.Task(aiocoap.Context.create_server_context(bind=('::1', 5683), site=root))
asyncio.get_event_loop().run_forever()

(This is basically your example just with full imports and a concrete loopback address)

  • Run aiocoap-client coap://localhost/some/res
  • Kill the aiocoap-client process while the server is in the breakpoint
  • Continue the server (c)
  • Start the client again: It runs into the breakpoint again.

To test on Linux, I set the AIOCOAP_SERVER_TRANSPORT=tcpserver:tcpclient:tlsserver:tlsclient:simple6:simplesocketserver / AIOCOAP_CLIENT_TRANSPORT=tcpclient:tlsclient:simple6 environment variable to emulate your system's transport choices.

Can you test with these precise commands on Windows, with your full setup on Linux, to tell whether that's a reproducing or a Windows issue?

chrysn avatar May 30 '23 14:05 chrysn

@chrysn tried with IPv6 (per your example) and with IPv4 (127.0.0.1) using aiocoap-client. Tested on two Win 10 machines one with Python 3.8 and the other with Python 3.11. The same results.

Server code

class TestRes(aiocoap.resource.ObservableResource):
    async def render_get(self, request):
        return aiocoap.Message(code=aiocoap.numbers.Code.BAD_REQUEST)

root = resource.Site()

root.add_resource(['.well-known', 'core'], resource.WKCResource(root.get_resources_as_linkheader))
root.add_resource(['some','res'], TestRes())

asyncio.Task(aiocoap.Context.create_server_context(bind=('::1', 5683), site=root))
asyncio.get_event_loop().run_forever()

Client execution aiocoap-client coap://localhost:5683/some/res

Steps

  • Start the server, place a breakpoint on return aiocoap.Message(code=aiocoap.numbers.Code.BAD_REQUEST)
  • Start client
  • Terminate the client upon breakpoint hit
  • Resume the server
    • Observe Ignoring error because it can not be mapped to any connection: [WinError 1234] No service is operating at the destination network endpoint on the remote system
  • Retry client execution
  • Observe that breakpoint is no longer hit and client outputs (after some time) Network error: Retransmissions exceeded

GeorgeCGV avatar Jun 05 '23 09:06 GeorgeCGV