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

Listening on Unix socket? #3560

Open
mholt opened this issue Sep 21, 2022 · 14 comments
Open

Listening on Unix socket? #3560

mholt opened this issue Sep 21, 2022 · 14 comments

Comments

@mholt
Copy link
Contributor

mholt commented Sep 21, 2022

Quic question (you probably get that pun a lot) - is there a way to serve HTTP/3 over Unix socket?

I know that probably doesn't make sense, but would quic-go work for unixgram network types? I noticed that listenAddr() hard-codes udp as the network type:

https://github.com/lucas-clemente/quic-go/blob/17761bf35f0e91c82ce963d4138aacf90213768a/server.go#L139-L147

Currently fixing a bug in Caddy that doesn't play well with unix sockets (oops). For now I might just disable the HTTP/3 listener for sites configured on Unix sockets, but I thought I should ask if it's possible or even makes sense to use HTTP/3 over UDS. Thanks!

@marten-seemann
Copy link
Member

I’m not really familiar with Unix sockets. ListenAddr is more intended as a convenience function, the more general version is Listen, which allows you to pass in a net.PacketConn. Does that help?

@mholt
Copy link
Contributor Author

mholt commented Sep 21, 2022

I'm not super well versed in this either, but I think udp unix sockets take the unixgram network type, which corresponds to a net.UnixListener struct, rather than a net.PacketConn.

@marten-seemann
Copy link
Member

The net.UnixListener returns a net.Conn, not a net.PacketConn. I'd assume there'd be a bit of wrapping necessary if one wanted to make this work.

What's the use case for this?

@mholt
Copy link
Contributor Author

mholt commented Sep 21, 2022

net.Conn and net.PacketConn have pretty similar interfaces, I think the only difference is in ReadFrom/WriteTo versus Read/Write.

I admit I don't have a specific use case right now, but I noticed that Caddy 2.6.0 failed to start when binding a site to a unix socket, because we try to start the HTTP/3 listener on the same address (but for datagrams) and get an error. In 2.6.1, I've simply disabled HTTP/3 for sites bound to unix sockets. But in doing this I realized, "Huh, I don't know how to serve HTTP/3 over a unix socket" so I opened the issue.

I suspect at some point we'll get requests for this and I can ask their use case then. But I just wanted to make sure I wasn't missing something already there.

@zllovesuki
Copy link
Contributor

You can grab it like this:

	net.ListenUnixgram("unixgram", &net.UnixAddr{
		Name: "/tmp/bleh.sock",
		Net: "unixgram",
	})

The returned *net.UnixConn is an net.PacketConn

@mholt
Copy link
Contributor Author

mholt commented Sep 22, 2022

Oh, awesome!! I didn't even notice that. Thanks @zllovesuki

@marten-seemann
Copy link
Member

@mholt Does that mean you can get the net.PacketConn in Caddy, or is anything needed from the quic-go side?

@mholt
Copy link
Contributor Author

mholt commented Sep 22, 2022

@marten-seemann I don't know... it looks like we'd need quic-go to do this or expose a new API.

We use ListenAddrEarly() and it calls unexported function listenAddr() which hard-codes the UDP network type. In other words, quic-go is creating the listener, not us. Is there a way for us to use ListenAddrEarly where we pass in the listener?

@zllovesuki
Copy link
Contributor

https://pkg.go.dev/github.com/lucas-clemente/quic-go#ListenEarly

@mholt
Copy link
Contributor Author

mholt commented Sep 22, 2022

Ahh... Not sure how I missed that. 😅 🤦‍♂️ -- I'll give that a shot. Thanks!

@mholt mholt closed this as completed Sep 22, 2022
@mholt
Copy link
Contributor Author

mholt commented Sep 26, 2022

@zllovesuki @marten-seemann Ah, so I've been working on this the last few days.... the problem with using ListenEarly and passing in the listener, is quic-go doesn't close the listener for us when we shut down the server.

(Edit: And, I'm an idiot for not reading the godoc comment on ServeListener() 😅 )

And I think that makes sense, except I'm having trouble reusing listeners across reloads because I can't keep track of when Close() is called, since quic-go doesn't call Close():

https://github.com/lucas-clemente/quic-go/blob/424a66389c01d10678bfb980cfe6faa8524b42b6/server.go#L273-L284

Basically, I expect the listener to be closed when I shut down the server using it.

Maybe that's not always the case for PacketConns? I dunno. It makes reusing unix sockets a bit tricky. Do you have any suggestions or maybe can explain and help me understand why that's the case?

(One more note: I think it's a bit surprising since calling net/http.Server.Shutdown() does close the listeners even though it did not create it for me.)

I can work around this by storing the listeners I pass into the server; but, it is less convenient. Actually, this doesn't work -- see comment below.

@mholt
Copy link
Contributor Author

mholt commented Sep 27, 2022

It turns out that because the quic.EarlyListener returned from ListenEarly is a *baseServer which has the exact same Close() as the one I was calling before, it still doesn't close the listeners because it didn't create them.

This means I need to design an API like this:

func ListenQUIC(address string) (net.PacketConn, quic.EarlyListener, error)

instead of this:

func ListenQUIC(address string) (quic.EarlyListener, error)

because I need to get a handle on the underlying PacketConn to close it, since closing the quic.EarlyListener doesn't close the PacketConn.

So in other words, I now need to hold onto both the net.PacketConn and quic.EarlyListener, and close them separately.

At this point, I'm wondering if you'd be open to one of these changes:

  • (Preferred) Have *http3.Server.Close() close the listeners like net/http does.
  • Have quic.EarlyListener.Close() actually close the listener, not the server instead.

@mholt mholt reopened this Sep 27, 2022
mholt added a commit to caddyserver/caddy that referenced this issue Sep 27, 2022
Deprecate:
- caddy.Listen
- caddy.ListenTimeout
- caddy.ListenPacket

Prefer caddy.NetworkAddress.Listen() instead.

Change:
- caddy.ListenQUIC (hopefully to remove later)
- caddy.ListenerFunc signature (add context and ListenConfig)

- Don't emit Alt-Svc header advertising h3 over HTTP/3

- Use quic.ListenEarly instead of quic.ListenEarlyAddr; this gives us
more flexibility (e.g. possibility of HTTP/3 over UDS) but also
introduces a new issue:
quic-go/quic-go#3560 (comment)

- Unlink unix socket before and after use
mholt added a commit to caddyserver/caddy that referenced this issue Sep 28, 2022
* core: Refactor, improve listener logic

Deprecate:
- caddy.Listen
- caddy.ListenTimeout
- caddy.ListenPacket

Prefer caddy.NetworkAddress.Listen() instead.

Change:
- caddy.ListenQUIC (hopefully to remove later)
- caddy.ListenerFunc signature (add context and ListenConfig)

- Don't emit Alt-Svc header advertising h3 over HTTP/3

- Use quic.ListenEarly instead of quic.ListenEarlyAddr; this gives us
more flexibility (e.g. possibility of HTTP/3 over UDS) but also
introduces a new issue:
quic-go/quic-go#3560 (comment)

- Unlink unix socket before and after use

* Appease the linter

* Keep ListenAll
@mamaart
Copy link

mamaart commented Dec 4, 2023

I've been working on running a QUIC application locally over Unixgram, and I've successfully set up the listener using the net.PacketConn obtained from net.ListenPacket("unixgram", socketFile) passed into quic.Listen().

However, when attempting to use quic.Dial, I realized it requires a net.PacketConn as well. Unfortunately, I haven't been able to find clear information on how to obtain a net.PacketConn for dialing over Unixgram.

Has anyone successfully managed this or can provide some guidance on the right direction to pursue? Any help or pointers would be greatly appreciated.

Thank you in advance!

@marten-seemann
Copy link
Member

Why can’t you just use the same net.PacketConn that you obtained from ListenPacket?

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

4 participants