<p dir="auto"><strong>Overview</strong></p>
<p dir="auto">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 <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="70575026" data-permission-text="Title is private" data-url="https://github.com/golang/go/issues/10565" data-hovercard-type="issue" data-hovercard-url="/golang/go/issues/10565/hovercard" href="https://github.com/golang/go/issues/10565">#10565</a>.  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.</p>
<p dir="auto"><strong>Proposed Change</strong></p>
<p dir="auto">I propose adding a new API to package <code class="notranslate">net</code> which enables registration of arbitrary sockets for use with the runtime network poller.  The design of this API is based upon a comment from <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/rsc/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/rsc">@rsc</a> found here: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="92230176" data-permission-text="Title is private" data-url="https://github.com/golang/go/issues/11492" data-hovercard-type="issue" data-hovercard-url="/golang/go/issues/11492/hovercard?comment_id=117855313&amp;comment_type=issue_comment" href="https://github.com/golang/go/issues/11492#issuecomment-117855313">#11492 (comment)</a>.</p>
<blockquote>
<p dir="auto">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.</p>
</blockquote>
<p dir="auto">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, <code class="notranslate">syscall.Sockaddr</code> does appear to be available on all platforms.</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="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
}"><pre class="notranslate"><span class="pl-k">package</span> net

<span class="pl-c">// Registration mechanism, perhaps called in init() or main() when a</span>
<span class="pl-c">// socket is first initalized.</span>
<span class="pl-k">func</span> <span class="pl-en">RegisterSocket</span>(
    <span class="pl-s1">family</span> <span class="pl-smi">int</span>,
    <span class="pl-s1">sockaddr</span> syscall.<span class="pl-smi">Sockaddr</span>,
    <span class="pl-s1">addr</span> <span class="pl-smi">Addr</span>,
    <span class="pl-s1">convertSockaddr</span> <span class="pl-k">func</span>(syscall.<span class="pl-smi">Sockaddr</span>) <span class="pl-smi">Addr</span>,
    <span class="pl-s1">convertNetAddr</span> <span class="pl-k">func</span>(<span class="pl-smi">Addr</span>) syscall.<span class="pl-smi">Sockaddr</span>,
)

<span class="pl-c">// Generic net.Conn and net.PacketConn implementation which embeds the</span>
<span class="pl-c">// internal net.conn type.  Checks for registered socket hooks to determine</span>
<span class="pl-c">// validity of sent and received net.Addr implementations.</span>
<span class="pl-k">type</span> <span class="pl-smi">SocketConn</span> <span class="pl-k">struct</span> {
    <span class="pl-smi">conn</span>
}</pre></div>
<p dir="auto"><strong>Example</strong></p>
<p dir="auto">Using a modified version of package <code class="notranslate">net</code>, I was able to gain access to the runtime network poller and<br>
simplify my <a href="https://github.com/mdlayher/raw">raw sockets package</a> code to something like the following:</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Called in init() in package raw
net.RegisterSocket(
    syscall.AF_PACKET,
    &amp;syscall.SockaddrLinklayer{},
    &amp;Addr{},
    // internal conversion functions for syscall.SockaddrLinklayer &lt;-&gt; raw.Addr
    convertSockaddr,
    convertNetAddr,
)

sock, _ := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, proto)
_ = syscall.Bind(sock, &amp;syscall.SockaddrLinklayer{
    Protocol: pbe,
    Ifindex:  ifi.Index,
})
f := os.NewFile(uintptr(sock), &quot;linklayer&quot;)
// c is type net.SocketConn, backed by raw socket (uses raw.Addr for addressing)
c := net.FilePacketConn(f)"><pre class="notranslate"><span class="pl-c">// Called in init() in package raw</span>
<span class="pl-s1">net</span>.<span class="pl-en">RegisterSocket</span>(
    <span class="pl-s1">syscall</span>.<span class="pl-c1">AF_PACKET</span>,
    <span class="pl-c1">&amp;</span>syscall.<span class="pl-smi">SockaddrLinklayer</span>{},
    <span class="pl-c1">&amp;</span><span class="pl-smi">Addr</span>{},
    <span class="pl-c">// internal conversion functions for syscall.SockaddrLinklayer &lt;-&gt; raw.Addr</span>
    <span class="pl-s1">convertSockaddr</span>,
    <span class="pl-s1">convertNetAddr</span>,
)

<span class="pl-s1">sock</span>, <span class="pl-s1">_</span> <span class="pl-c1">:=</span> <span class="pl-s1">syscall</span>.<span class="pl-en">Socket</span>(<span class="pl-s1">syscall</span>.<span class="pl-c1">AF_PACKET</span>, <span class="pl-s1">syscall</span>.<span class="pl-c1">SOCK_RAW</span>, <span class="pl-s1">proto</span>)
<span class="pl-s1">_</span> <span class="pl-c1">=</span> <span class="pl-s1">syscall</span>.<span class="pl-en">Bind</span>(<span class="pl-s1">sock</span>, <span class="pl-c1">&amp;</span>syscall.<span class="pl-smi">SockaddrLinklayer</span>{
    <span class="pl-c1">Protocol</span>: <span class="pl-s1">pbe</span>,
    <span class="pl-c1">Ifindex</span>:  <span class="pl-s1">ifi</span>.<span class="pl-c1">Index</span>,
})
<span class="pl-s1">f</span> <span class="pl-c1">:=</span> <span class="pl-s1">os</span>.<span class="pl-en">NewFile</span>(<span class="pl-en">uintptr</span>(<span class="pl-s1">sock</span>), <span class="pl-s">"linklayer"</span>)
<span class="pl-c">// c is type net.SocketConn, backed by raw socket (uses raw.Addr for addressing)</span>
<span class="pl-s1">c</span> <span class="pl-c1">:=</span> <span class="pl-s1">net</span>.<span class="pl-en">FilePacketConn</span>(<span class="pl-s1">f</span>)</pre></div>
<p dir="auto"><strong>Summary</strong></p>
<p dir="auto">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.</p>
<p dir="auto">If this proposal is accepted, I'd happily seek guidance from <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/mikioh/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/mikioh">@mikioh</a> 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 <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="51288188" data-permission-text="Title is private" data-url="https://github.com/golang/go/issues/8432" data-hovercard-type="issue" data-hovercard-url="/golang/go/issues/8432/hovercard" href="https://github.com/golang/go/issues/8432">#8432</a>.</p>
<p dir="auto">Questions and comments appreciated, and thanks for your time.</p>
<p dir="auto">/cc <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/rsc/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/rsc">@rsc</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/mikioh/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/mikioh">@mikioh</a></p>
<pre class="notranslate">Even though the 386 has a 4-byte word size, some instructions move 
data in larger chunks.  In particular float64 loads move 8 bytes and
some SSE2 operations (as yet unused) move even larger amounts.
A float64 load from an only-4-byte-aligned address is significantly
more expensive than one from a 8-byte-aligned address.  The same
is probably true of SSE2 too.

We should make sure that data symbols &gt;32 bits (e.g., float64 constants)
are aligned on 8-byte boundaries in the data segment.  (Fairly easy.)

We should also make sure that the stack pointer can be relied upon to be
8-byte aligned (harder), by making stack frame sizes = -4 mod 8 
(the caller PC will add 4 more) and starting new goroutines with a
properly aligned stack pointer.

It might be worth using 16 bytes for the stack alignment.  OS X requires
that for their own ABI, presumably because it matters for SSE2.</pre>