forked from benburkert/net.tune
/
dial.go
84 lines (69 loc) · 2.09 KB
/
dial.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package tune
import (
. "net"
"os"
"syscall"
)
//Tuner sets options on the file descriptor argument.
type Tuner func(int) error
// TuneAndListen announces on the local network address laddr.
// The network net must be a stream-oriented network: "tcp", "tcp4",
// "tcp6", "unix" or "unixpacket".
// See Dial for the syntax of laddr.
// The configuration config indicates additional socket options set on the
// listener socket.
func TuneAndListen(net, laddr string, tuners ...Tuner) (Listener, error) {
switch net {
case "tcp", "tcp4", "tcp6":
tcpAddr, err := ResolveTCPAddr(net, laddr)
if err != nil {
return nil, err
}
return TuneAndListenTCP(net, tcpAddr, tuners...)
default:
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
}
}
// TuneAndListenTCP announces on the TCP address laddr and returns a TCP
// listener. The configuration config indicates additional socket options
// set on the listener socket.
func TuneAndListenTCP(net string, laddr *TCPAddr, tuners ...Tuner) (Listener, error) {
var err error
family, ipv6only := favoriteTCPAddrFamily(net, laddr, "listen")
var socketAddr syscall.Sockaddr
if socketAddr, err = ipToSockaddr(family, laddr.IP, laddr.Port, laddr.Zone); err != nil {
return nil, err
}
var s int
if s, err = sysSocket(family, syscall.SOCK_STREAM, 0); err != nil {
return nil, err
}
if err = setDefaultSockopts(s, family, syscall.SOCK_STREAM, ipv6only); err != nil {
closesocket(s)
return nil, err
}
if err = setDefaultListenerSockopts(s); err != nil {
closesocket(s)
return nil, err
}
for _, tuner := range tuners {
if err := tuner(s); err != nil {
return nil, err
}
}
if err = syscall.Bind(s, socketAddr); err != nil {
closesocket(s)
return nil, err
}
if err = syscall.Listen(s, maxListenerBacklog()); err != nil {
closesocket(s)
return nil, err
}
file := os.NewFile(uintptr(s), "listener-"+laddr.String())
defer file.Close()
var socketListener Listener
if socketListener, err = FileListener(file); err != nil {
return nil, err
}
return socketListener, nil
}