Coder Social home page Coder Social logo

Adopt listening socket fd about libwebsockets HOT 13 CLOSED

alex3d avatar alex3d commented on June 10, 2024
Adopt listening socket fd

from libwebsockets.

Comments (13)

lws-team avatar lws-team commented on June 10, 2024

How about this kind of thing?

diff --git a/include/libwebsockets/lws-context-vhost.h b/include/libwebsockets/lws-context-vhost.h
index b48a3200..d4f60289 100644
--- a/include/libwebsockets/lws-context-vhost.h
+++ b/include/libwebsockets/lws-context-vhost.h
@@ -959,6 +959,14 @@ struct lws_context_creation_info {
 	 * selected default loglevel can then be cleanly overridden using -d 1039 etc
 	 * commandline switch */
 
+	lws_sockfd_type		vh_listen_sockfd;
+	/**< VHOST: 0 for normal vhost listen socket fd creation, if any.
+	 * Nonzero to force the selection of an already-existing fd for the
+	 * vhost's listen socket, which is already prepared.  This is intended
+	 * for an external process having chosen the fd, which cannot then be
+	 * zero.
+	 */
+
 	/* Add new things just above here ---^
 	 * This is part of the ABI, don't needlessly break compatibility
 	 *
diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c
index 44e7c1ef..6a89ba5a 100644
--- a/lib/roles/http/server/server.c
+++ b/lib/roles/http/server/server.c
@@ -72,6 +72,10 @@ check_extant(struct lws_dll2 *d, void *user)
 	if (wsi->af != a ->af)
 		return 0;
 
+	if (a->info && a->info->vh_listen_sockfd &&
+	    wsi->desc.sockfd != a->info->vh_listen_sockfd)
+		return 0;
+
 	lwsl_notice(" using listen skt from vhost %s\n", wsi->a.vhost->name);
 
 	return 1;
@@ -107,7 +111,7 @@ deal:
 	if (!san--)
 		return -1;
 
-	if (a->vhost->iface) {
+	if (a->vhost->iface && (!a->info || !a->info->vh_listen_sockfd)) {
 
 		/*
 		 * let's check before we do anything else about the disposition
@@ -202,7 +206,10 @@ done_list:
 
 	for (m = 0; m < limit; m++) {
 
-		sockfd = lws_fi(&a->vhost->fic, "listenskt") ?
+		if (a->info && a->info->vh_listen_sockfd)
+			sockfd = a->info->vh_listen_sockfd;
+		else
+			sockfd = lws_fi(&a->vhost->fic, "listenskt") ?
 					LWS_SOCK_INVALID :
 					socket(a->af, SOCK_STREAM, 0);
 
@@ -274,28 +281,30 @@ done_list:
 #endif
 		lws_plat_set_socket_options(a->vhost, sockfd, 0);
 
-		is = lws_socket_bind(a->vhost, NULL, sockfd,
-				     a->vhost->listen_port,
-				     a->vhost->iface, a->af);
+		if (!a->info || !a->info->vh_listen_sockfd) {
+			is = lws_socket_bind(a->vhost, NULL, sockfd,
+					     a->vhost->listen_port,
+					     a->vhost->iface, a->af);
 
-		if (is == LWS_ITOSA_BUSY) {
-			/* treat as fatal */
-			compatible_close(sockfd);
+			if (is == LWS_ITOSA_BUSY) {
+				/* treat as fatal */
+				compatible_close(sockfd);
 
-			return -1;
-		}
+				return -1;
+			}
 
-		/*
-		 * There is a race where the network device may come up and then
-		 * go away and fail here.  So correctly handle unexpected failure
-		 * here despite we earlier confirmed it.
-		 */
-		if (is < 0) {
-			lwsl_info("%s: lws_socket_bind says %d\n", __func__, is);
-			compatible_close(sockfd);
-			if (a->vhost->iface)
-				goto deal;
-			return -1;
+			/*
+			 * There is a race where the network device may come up and then
+			 * go away and fail here.  So correctly handle unexpected failure
+			 * here despite we earlier confirmed it.
+			 */
+			if (is < 0) {
+				lwsl_info("%s: lws_socket_bind says %d\n", __func__, is);
+				compatible_close(sockfd);
+				if (a->vhost->iface)
+					goto deal;
+				return -1;
+			}
 		}
 
 		/*

If / when it works it'd be great to have a little patch on a minimal or the test sever (eg, adding --systemd or whatever) and a procedure to test it with systemd.

from libwebsockets.

alex3d avatar alex3d commented on June 10, 2024

Thanks for the quick reply!

If / when it works it'd be great to have a little patch on a minimal or the test sever (eg, adding --systemd or whatever) and a procedure to test it with systemd.

Maybe it is better to make a new example to not pull new dependencies to existing cross-platform examples?
Systemd activation example would pull libsystemd dependency (sd_listen_fds) or at least a getenv/getpid/fcntl calls.
What do you recommend as base for new example? minimal-examples-lowlevel/http-server/minimal-http-server is OK?

I've made a simple POC and it seems everything works as intended: #3038

$ systemctl --user link $PWD/lws-test.service $PWD/lws-test.socket 
Created symlink ~/.config/systemd/user/lws-test.service → .../lws-test.service.
Created symlink ~/.config/systemd/user/lws-test.socket → .../lws-test.socket.
$ systemctl --user start lws-test.socket

$ ss -lptn sport 7681
State            Recv-Q           Send-Q                       Local Address:Port                       Peer Address:Port           Process           
LISTEN           0                4096                                     *:7681                                  *:*               users:(("systemd",pid=16734,fd=32))

$ curl http://127.0.0.1:7681/
<meta charset="UTF-8"> 
<html>
        <body>
                <img src="libwebsockets.org-logo.svg"><br>
                <h1>404</h1>
                Sorry, that file doesn't exist.
        </body>
</html>

$ ss -lptn sport 7681
State            Recv-Q           Send-Q                       Local Address:Port                       Peer Address:Port           Process           
LISTEN           0                4096                                     *:7681                                  *:*               users:(("lws-minimal-htt",pid=434298,fd=3),("systemd",pid=16734,fd=32))

from libwebsockets.

alex3d avatar alex3d commented on June 10, 2024
  1. After a few more tests I have found a small cosmetic issue: lws_get_vhost_listen_port returns garbage for adopted listening socket. Probably random port auto-detection from lws_socket_bind (getsockname) can be re-used for adopted listening sockets.
  2. Is lws_plat_set_socket_options guaranteed to be called on adopted listening fd's? Systemd config have a bunch of socket options (nodelay, noblocking, etc) but it seems lws sets all needed options on adopted fd.

from libwebsockets.

lws-team avatar lws-team commented on June 10, 2024

Yes lws will modify the fd according to what's needed (nonblocking, no nagle etc) as part of the normal flow.

It seems systemd can hand it anything, unix socket, fifo or whatever. It looks like it needs more handling in lws to understand what it is and set info flags. For example here, with ipv6 enabled, it chokes on the fd handed to it, even dup()'d trying to set it for ipv6.

I have prepared a minimal example but instead of binding it to systemd there, it seems it has to be done in lws more completely.

from libwebsockets.

alex3d avatar alex3d commented on June 10, 2024

It seems systemd can hand it anything, unix socket, fifo or whatever.

Yeah, systemd can hand something completely unusable for lws (e.g. UDP/unix datagram socket). Probably this should be handled by application itself, but not lws. At the end of the day systemd unit files are out of control of lws.
IMHO only ipv4/ipv6 (and maybe unix-stream) adoptation in lws would be more than sufficient.

from libwebsockets.

lws-team avatar lws-team commented on June 10, 2024

I pushed a couple of patches on main that work here.

It auto starts the service OK but once it's running, it doesn't stop until you kill it atm.

from libwebsockets.

lws-team avatar lws-team commented on June 10, 2024

(btw lws can handle UDP fine; the async DNS uses it).

from libwebsockets.

alex3d avatar alex3d commented on June 10, 2024

(btw lws can handle UDP fine; the async DNS uses it).

This is interesting! (I have thought about HTTP/3 after I wrote "UDP completely unusable").
Well, with "completely unusable" I meant that application can't just throw fd's to lws. It is up to app to decide what is systemd unit files setup and what to do with fd's passed by systemd. For example, what to do if systemd passed multiple fd - should app make two lws vhosts or should it use extra fd for something completely different.

It auto starts the service OK but once it's running, it doesn't stop until you kill it atm.

It is OK for my usecase. From my experience with other socket activated services I can say not all of them support auto-stop.
For example, Docker doesn't stop automatically after it started by socket activation.
Redhat's Podman and Cockpit services auto stops after some idle time. After 1 minute without new requests IIRC.

Thanks for the patches! I'll test them later.

from libwebsockets.

alex3d avatar alex3d commented on June 10, 2024

@lws-team, current master branch duplicates adopted listening FD (fd=7). Is it really needed?
With your previous patch there was no FD duplication.

$ ss -lptn sport 7681
State                   Recv-Q                  Send-Q                                   Local Address:Port                                     Peer Address:Port                  Process
LISTEN                  0                       4096                                                 *:7681                                                *:*                      
users:(("lws-minimal-htt",pid=64905,fd=7),("lws-minimal-htt",pid=64905,fd=3),("systemd",pid=45678,fd=38))

UPD: Found that dup: 3207da0#r137002566

from libwebsockets.

lws-team avatar lws-team commented on June 10, 2024

With IPV6 enabled, lws deals with ipv4 + ipv6 by binding separate listen sockets to AF_INET and AF_INET6. It can create the sockets itself scratch normally but with this adoption plan, only one socket is handed to it from outside. So dup is used to solve this.

What problem does that actually create?

from libwebsockets.

alex3d avatar alex3d commented on June 10, 2024

No actual problem, thanks for explanation.

One small issue - minimal-http-server-systemd-socketact example doesn't work when activated with unix socket.
It seems port=0 should be added into example or into unix-systemd.c

if (sd_is_socket_unix(info->vh_listen_sockfd, 0, 0, NULL, 0))
info->options |= LWS_SERVER_OPTION_UNIX_SOCK;

(For unix sockets FD's also duplicated, but well, no actual problem if it is needed)

$ sudo ss -lpn src unix:/run/test.sock
Netid               State                Recv-Q               Send-Q                              Local Address:Port                                  Peer Address:Port               Process
u_str               LISTEN               0                    4096                               /run/test.sock 4833896                                          * 0                   
users:(("lws-minimal-htt",pid=1783802,fd=7),("lws-minimal-htt",pid=1783802,fd=3),("systemd",pid=1,fd=47))

from libwebsockets.

lws-team avatar lws-team commented on June 10, 2024

I added a patch for the unix domain port thing on main.

from libwebsockets.

alex3d avatar alex3d commented on June 10, 2024

Thanks, I think issue can be closed now

from libwebsockets.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.