django / daphne

Django Channels HTTP/WebSocket server
BSD 3-Clause "New" or "Revised" License
2.32k stars 256 forks source link

Unix File Socket Argument #498

Open sourcesolver opened 5 months ago

sourcesolver commented 5 months ago

It appears there is a bug in daphne using file sockets on debian bookworm.

When I do the following from my service file:

/usr/bin/python3 /usr/bin/daphne -u /var/run/{app_name}/socket {app_name}.asgi:application

the log file says:

2024-02-05 04:44:20,299 INFO Starting server at unix:/var/run/{_appname}/socket 2024-02-05 04:44:20,299 INFO HTTP/2 support enabled 2024-02-05 04:44:20,299 INFO Configuring endpoint unix:/var/run/{_appname}/socket 2024-02-05 04:44:20,300 CRITICAL Listen failure: [Errno 22] Invalid argument: b'/var/run/{_app_name_}/socket.lock'

[Note: the folder "/var/run/{_appname}" and file "/var/run/{_appname}/socket.lock" has been created beforehand by tmpfiles.d, with ample username+group permissions, as used by the service; I confirmed this with an ls -l...]

Note the:

 b'/var/run/{app_name}/socket.lock'

It appears a bytestring is getting passed to twisted when it should be a utf8 string?

The code in endpoints.py at startup does:

 if unix_socket:
    socket_descriptions.append("unix:%s" % unix_socket)

In server.py we have an error callback:

def listen_error(self, failure):
    logger.critical("Listen failure: %s", failure.getErrorMessage())
    self.stop()

How can this be corrected, either by command switch fixup or component installation or hotfix, so that we do not get this error when we use a unix file socket?

python version is 3.11.2 Daphne version is 4.0.0 twisted version is 23.10.0

Running on debian 12/bookworm

Thanks much!

carltongibson commented 5 months ago

Is the /{app_name}/ a literal?

sourcesolver commented 4 months ago

{app_name} is not a literal. It is pseudo-code for the name of the app on the path.

carltongibson commented 4 months ago

OK, then I'm not sure what to say.

This works AFAICS:

% daphne -u app.socket app:application

... so it's something particular about your setup.

sourcesolver commented 4 months ago

I tried ExecStart=/usr/bin/python3 /usr/bin/daphne -u socket {_app_name_}.asgi:application

I get back:

CRITICAL Listen failure: [Errno 22] Invalid argument: b'socket.lock'

Yes, it's something particular about my setup. Most likely it's the implementation of twisted on debian 12 vs. daphne. Twisted use to be python2. It appears to be a mismatch in argument passing between a bytestring and a utf8 one. For some reason the daphne looks like it's passing the file socket parameter as a bytestring to twisted when it should be passing it as utf8

sourcesolver commented 4 months ago

When I do:

/usr/bin/python3 /usr/bin/daphne -u socket.lock {_app_name_}.asgi:application

(add the .lock extension to the unix file...), I get:

2024-02-07 19:42:43,032 INFO Starting server at unix:socket.lock 2024-02-07 19:42:43,033 INFO HTTP/2 support enabled 2024-02-07 19:42:43,033 INFO Configuring endpoint unix:socket.lock 2024-02-07 19:42:43,033 CRITICAL Listen failure: [Errno 13] Permission denied: '276285' -> b'socket.lock.lock'

So based on that doubling-up of the lock extension in the log, it appears I should not include it...

sourcesolver commented 4 months ago

Also tried quoting the socket file argument; same error...

/usr/bin/python3 /usr/bin/daphne -u "socket.lock" {_app_name_}.asgi:application

carltongibson commented 4 months ago

Does it work if you run Daphne manually rather than via systemd?

(To be honest, without a reproduce I'm going to struggle to help you )

sourcesolver commented 4 months ago

I did try it interactively in the context of the username the service uses and the WorkingDirectory -same error

sourcesolver commented 4 months ago

I tried a random socket file name (that does not exist):

/usr/bin/python3 /usr/bin/daphne -u blah {_app_name_}.asgi:application

/usr/bin/python3 /usr/bin/daphne -u blah {_app_name_}.asgi:application 2024-02-07 20:12:32,346 INFO Starting server at unix:blah 2024-02-07 20:12:32,346 INFO HTTP/2 support enabled 2024-02-07 20:12:32,346 INFO Configuring endpoint unix:blah 2024-02-07 20:12:32,347 CRITICAL Listen failure: [Errno 13] Permission denied: '278322' -> b'blah.lock'

Got that permission error. When you have it reference a socket file that exists, has the service's user and group ownership, and rwx permissions for both the user and group, you still get that invalid argument error, showing that a bytestring is being passed

sourcesolver commented 4 months ago

The socket file argument SHOULD be able to take a fully qualified path; and I tested that I can touch the socket file, so a permissions thing doesn't appear to be coming into play. It's saying the path is bad. Only thing I can come up with is that twisted is being passed a bytestring when it now expects utf8

sourcesolver commented 4 months ago

What distro are you using?

carltongibson commented 4 months ago

You can examine the socket_description here:

https://github.com/django/daphne/blob/9a282dd6277f4b921e494a9fc30a534a7f0d6ca6/daphne/server.py#L130C1-L131C1

It's definitely a string type when it leaves Daphne. Whatever is going on beyond that is inside twisted.