Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Listen on multiple sockets #66

Open
jgraichen opened this issue Dec 2, 2022 · 2 comments
Open

Listen on multiple sockets #66

jgraichen opened this issue Dec 2, 2022 · 2 comments

Comments

@jgraichen
Copy link

I really do like the easy of working with axum and axum-server. It is straightforward to set up TLS and reload it, which is awesome when used with certificates that need to renewed often.

I would be genuinely interested in binding a server to multiple sockets of different types. For example, to accept an arbitrary list of TCP and unix domain sockets via systemd socket activation:

	let tls_config = RustlsConfig::from_pem_file(
		"examples/self-signed-certs/cert.pem",
		"examples/self-signed-certs/key.pem",
	)
	.await?;

	let server = axum_server::new();

	let mut lfd = ListenFd::from_env();
	if lfd.len() > 0 {
		for idx in 0..lfd.len() {
			if let Ok(Some(lst)) = lfd.take_tcp_listener(idx) {
				server = server.from_tcp_rustls(lst, tls_config);
			} else if let Ok(Some(lst)) = lfd.take_unix_listener(idx) {
				server = server.from_uds(lst);
			} else {
				warn!("Unsupported socket type at index {:?}", idx)
			}
		}
	} else {
		server = server.bind("[::]:3000".parse()?)
	}

	let app = Router::new().route("/", get(|| async { "Hello World" }));
	server.serve(app.into_make_service()).await?;

Having the same app listening on multiple sockets greatly improves usability and integration with many systems, such as systemd. Unix domain sockets are often used to provide a service to other local services, such as reverse proxies or load balancers. A second TCP listener is often spawned e.g. for debugging or monitoring purposes.

Does this feature sound reasonable for axum-server?

@programatik29
Copy link
Owner

This feature makes sense but can't be done without sacrificing integration with axum. Currently, for axum to extract SocketAddr, AddrStream from hyper must be used (see docs.rs page).

I have been delaying answering because I think this would be a good addition to new upcoming server in hyper-util (which will ideally make this crate obsolete). axum will certainly work with that new server since it will be the "official" one.

@Diggsey
Copy link

Diggsey commented Apr 22, 2024

That's not the case - in fact prior to hyper 1.x it was possible to do exactly this via acceptors.

For example, here's some code from my own application:

// Allow one of several different connection types to be used.
pub enum AnyConnection {
    // Direct TCP connection
    AddrStream(AddrStream),
    // TLS connection
    TlsStream(TlsStream),
    // Ngrok connection
    NgrokConn(ngrok::Conn),
}

// Allow getting the remote address from the underlying connection
impl Connected<&AnyConnection> for SocketAddr {
    fn connect_info(target: &AnyConnection) -> Self {
        match target {
            AnyConnection::AddrStream(inner) => inner.remote_addr(),
            AnyConnection::TlsStream(inner) => inner.io().expect("Stream errored").remote_addr(),
            AnyConnection::NgrokConn(inner) => inner.remote_addr(),
        }
    }
}

Which made it super easy to accept connections from any number of places. Unfortunately the new Accept trait from this crate is much more restrictive than the old Accept trait used to be, and it seems impossible to get the same behaviour.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants