-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Description
Overview
At this time, there is no mechanism for socket types outside of the standard library to access the runtime network poller. This proposal, if accepted, would enable a resolution to issue #10565. This would enable packages outside of the standard library to take advantage of the runtime network poller, instead of implementing their own network polling mechanism.
Proposed Change
I propose adding a new API to package net
which enables registration of arbitrary sockets for use with the runtime network poller. The design of this API is based upon a comment from @rsc found here: #11492 (comment).
It seems to me that the net package should just keep using (and providing) only FileConn but perhaps we can put a registration mechanism in package syscall to let clients register converters between sockaddrs and net.Addr for non-standard sockaddr types.
This is what I was able to come up with after a little bit of experimentation. Parameter list is to be determined, but this is what I was able to get working with my prototype on a Linux system. Efforts will be made to make this mechanism as generic and cross-platform friendly as possible, but it may not be implemented immediately on non-UNIX platforms. From what I can tell, syscall.Sockaddr
does appear to be available on all platforms.
package net
// Registration mechanism, perhaps called in init() or main() when a
// socket is first initalized.
func RegisterSocket(
family int,
sockaddr syscall.Sockaddr,
addr Addr,
convertSockaddr func(syscall.Sockaddr) Addr,
convertNetAddr func(Addr) syscall.Sockaddr,
)
// Generic net.Conn and net.PacketConn implementation which embeds the
// internal net.conn type. Checks for registered socket hooks to determine
// validity of sent and received net.Addr implementations.
type SocketConn struct {
conn
}
Example
Using a modified version of package net
, I was able to gain access to the runtime network poller and
simplify my raw sockets package code to something like the following:
// Called in init() in package raw
net.RegisterSocket(
syscall.AF_PACKET,
&syscall.SockaddrLinklayer{},
&Addr{},
// internal conversion functions for syscall.SockaddrLinklayer <-> raw.Addr
convertSockaddr,
convertNetAddr,
)
sock, _ := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, proto)
_ = syscall.Bind(sock, &syscall.SockaddrLinklayer{
Protocol: pbe,
Ifindex: ifi.Index,
})
f := os.NewFile(uintptr(sock), "linklayer")
// c is type net.SocketConn, backed by raw socket (uses raw.Addr for addressing)
c := net.FilePacketConn(f)
Summary
The runtime network poller is an excellent mechanism, and enabling access to it will allow the future development of packages for raw ethernet sockets, netlink sockets, and other platform-specific socket types.
If this proposal is accepted, I'd happily seek guidance from @mikioh regarding creating the best possible API for this feature. In addition, this would enable me to contribute code from my raw ethernet socket package as a resolution to #8432.
Questions and comments appreciated, and thanks for your time.