net: add ListenConfig, Dialer.Control to permit socket opts before listen/dial

Existing implementation does not provide a way to set options such as
SO_REUSEPORT, that has to be set prior the socket being bound.

New exposed API:
pkg net, method (*ListenConfig) Listen(context.Context, string, string) (Listener, error)
pkg net, method (*ListenConfig) ListenPacket(context.Context, string, string) (PacketConn, error)
pkg net, type ListenConfig struct
pkg net, type ListenConfig struct, Control func(string, string, syscall.RawConn) error
pkg net, type Dialer struct, Control func(string, string, syscall.RawConn) error

Fixes #9661

Change-Id: If4d275711f823df72d3ac5cc3858651a6a57cccb
Reviewed-on: https://go-review.googlesource.com/72810
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Audrius Butkevicius 2018-05-28 02:47:21 +01:00 committed by Ian Lance Taylor
parent cc6e568c81
commit 3c4d3bdd3b
12 changed files with 350 additions and 74 deletions

View file

@ -6,7 +6,10 @@
package net
import "syscall"
import (
"errors"
"syscall"
)
func readRawConn(c syscall.RawConn, b []byte) (int, error) {
var operr error
@ -89,3 +92,36 @@ func controlRawConn(c syscall.RawConn, addr Addr) error {
}
return nil
}
func controlOnConnSetup(network string, address string, c syscall.RawConn) error {
var operr error
var fn func(uintptr)
switch network {
case "tcp", "udp", "ip":
return errors.New("ambiguous network: " + network)
case "unix", "unixpacket", "unixgram":
fn = func(s uintptr) {
_, operr = syscall.GetsockoptInt(int(s), syscall.SOL_SOCKET, syscall.SO_ERROR)
}
default:
switch network[len(network)-1] {
case '4':
fn = func(s uintptr) {
operr = syscall.SetsockoptInt(int(s), syscall.IPPROTO_IP, syscall.IP_TTL, 1)
}
case '6':
fn = func(s uintptr) {
operr = syscall.SetsockoptInt(int(s), syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, 1)
}
default:
return errors.New("unknown network: " + network)
}
}
if err := c.Control(fn); err != nil {
return err
}
if operr != nil {
return operr
}
return nil
}