added go-reuseport + go-sockaddr
Juan Batiz-Benet committed
Jan 19, 2015 at 02:53 UTC
911a3c90bc1a98f1cb6541688c70fed22036eb5b
18 files changed
+1449
Godeps/Godeps.json
+8
@@ -158,6 +158,14 @@
158
"ImportPath": "github.com/jbenet/go-random",
159
"Rev": "c50d0ce235bacde481d3e885b5dfd562c75c981a"
160
},
161
+ {
162
+ "ImportPath": "github.com/jbenet/go-reuseport",
163
+ "Rev": "f08ef6913526113c76e12e059ffe1b93319a7a18"
164
+ },
165
+ {
166
+ "ImportPath": "github.com/jbenet/go-sockaddr/net",
167
+ "Rev": "47da30afb462a74cfc7f3df73d4e5cb1bc42b7c7"
168
+ },
169
{
170
"ImportPath": "github.com/jbenet/go-temp-err-catcher",
171
"Rev": "c531232018e678b2a702cfb86b5c3f68d1c8beb8"
Godeps/_workspace/src/github.com/jbenet/go-reuseport/.travis.yml
new
+11
@@ -0,0 +1,11 @@
1
+language: go
2
+
3
+go:
4
+ - 1.2
5
+ - 1.3
6
+ - 1.4
7
+ - release
8
+ - tip
9
+
10
+script:
11
+ - go test -v ./...
Godeps/_workspace/src/github.com/jbenet/go-reuseport/LICENSE
new
+13
@@ -0,0 +1,13 @@
1
+Copyright (c) 2013 Conformal Systems LLC.
2
+
3
+Permission to use, copy, modify, and distribute this software for any
4
+purpose with or without fee is hereby granted, provided that the above
5
+copyright notice and this permission notice appear in all copies.
6
+
7
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
\ No newline at end of file
Godeps/_workspace/src/github.com/jbenet/go-reuseport/README.md
new
+42
@@ -0,0 +1,42 @@
1
+# go-reuseport
2
+
3
+
4
+
5
+This package enables listening and dialing from _the same_ TCP or UDP port.
6
+This means that the following sockopts are set:
7
+
8
+```
9
+SO_REUSEADDR
10
+SO_REUSEPORT
11
+```
12
+
13
+- godoc: https://godoc.org/github.com/jbenet/go-reuseport
14
+
15
+This is a simple package to get around the problem of reusing addresses.
16
+The go `net` package (to my knowledge) does not allow setting socket options.
17
+This is particularly problematic when attempting to do TCP NAT holepunching,
18
+which requires a process to both Listen and Dial on the same TCP port.
19
+This package makes this possible for me. It is a pretty narrow use case, but
20
+perhaps this package can grow to be more general over time.
21
+
22
+## Examples
23
+
24
+
25
+```Go
26
+// listen on the same port. oh yeah.
27
+l1, _ := reuse.Listen("tcp", "127.0.0.1:1234")
28
+l2, _ := reuse.Listen("tcp", "127.0.0.1:1234")
29
+```
30
+
31
+```Go
32
+// dial from the same port. oh yeah.
33
+l1, _ := reuse.Listen("tcp", "127.0.0.1:1234")
34
+l2, _ := reuse.Listen("tcp", "127.0.0.1:1235")
35
+c, _ := reuse.Dial("tcp", "127.0.0.1:1234", "127.0.0.1:1235")
36
+```
37
+
38
+**Note: cant dial self because tcp/ip stacks use 4-tuples to identify connections, and doing so would clash.**
39
+
40
+## Tested
41
+
42
+Tested on `darwin` and `linux`.
Godeps/_workspace/src/github.com/jbenet/go-reuseport/addr.go
new
+20
@@ -0,0 +1,20 @@
1
+package reuseport
2
+
3
+import (
4
+ "net"
5
+)
6
+
7
+func ResolveAddr(network, address string) (net.Addr, error) {
8
+ switch network {
9
+ default:
10
+ return nil, net.UnknownNetworkError(network)
11
+ case "ip", "ip4", "ip6":
12
+ return net.ResolveIPAddr(network, address)
13
+ case "tcp", "tcp4", "tcp6":
14
+ return net.ResolveTCPAddr(network, address)
15
+ case "udp", "udp4", "udp6":
16
+ return net.ResolveUDPAddr(network, address)
17
+ case "unix", "unixgram", "unixpacket":
18
+ return net.ResolveUnixAddr(network, address)
19
+ }
20
+}
Godeps/_workspace/src/github.com/jbenet/go-reuseport/const_bsd.go
new
+10
@@ -0,0 +1,10 @@
1
+// +build darwin freebsd dragonfly netbsd openbsd
2
+
3
+package reuseport
4
+
5
+import (
6
+ "syscall"
7
+)
8
+
9
+var soReusePort = syscall.SO_REUSEPORT
10
+var soReuseAddr = syscall.SO_REUSEADDR
Godeps/_workspace/src/github.com/jbenet/go-reuseport/const_linux.go
new
+10
@@ -0,0 +1,10 @@
1
+// +build linux
2
+
3
+package reuseport
4
+
5
+import (
6
+ "syscall"
7
+)
8
+
9
+var soReusePort = 15 // this is not defined in unix go pkg.
10
+var soReuseAddr = syscall.SO_REUSEADDR
Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_unix.go
new
+339
@@ -0,0 +1,339 @@
1
+// +build darwin freebsd dragonfly netbsd openbsd linux
2
+
3
+package reuseport
4
+
5
+import (
6
+ "net"
7
+ "os"
8
+ "strconv"
9
+ "syscall"
10
+ "time"
11
+
12
+ sockaddrnet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net"
13
+)
14
+
15
+const (
16
+ tcp4 = 52 // "4"
17
+ tcp6 = 54 // "6"
18
+ filePrefix = "port."
19
+)
20
+
21
+// Wrapper around the socket system call that marks the returned file
22
+// descriptor as nonblocking and close-on-exec.
23
+func socket(family, socktype, protocol int) (fd int, err error) {
24
+ syscall.ForkLock.RLock()
25
+ fd, err = syscall.Socket(family, socktype, protocol)
26
+ if err == nil {
27
+ syscall.CloseOnExec(fd)
28
+ }
29
+ syscall.ForkLock.RUnlock()
30
+
31
+ if err != nil {
32
+ return -1, err
33
+ }
34
+
35
+ // set non-blocking until after connect, because we cant poll using runtime :(
36
+ // if err = syscall.SetNonblock(fd, true); err != nil {
37
+ // syscall.Close(fd)
38
+ // return -1, err
39
+ // }
40
+
41
+ if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, soReuseAddr, 1); err != nil {
42
+ // fmt.Println("reuse addr failed")
43
+ syscall.Close(fd)
44
+ return -1, err
45
+ }
46
+
47
+ if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, soReusePort, 1); err != nil {
48
+ // fmt.Println("reuse port failed")
49
+ syscall.Close(fd)
50
+ return -1, err
51
+ }
52
+
53
+ // set setLinger to 5 as reusing exact same (srcip:srcport, dstip:dstport)
54
+ // will otherwise fail on connect.
55
+ if err = setLinger(fd, 5); err != nil {
56
+ // fmt.Println("linger failed")
57
+ syscall.Close(fd)
58
+ return -1, err
59
+ }
60
+
61
+ return fd, nil
62
+}
63
+
64
+func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) {
65
+ var (
66
+ fd int
67
+ lfamily int
68
+ rfamily int
69
+ socktype int
70
+ lprotocol int
71
+ rprotocol int
72
+ file *os.File
73
+ remoteSockaddr syscall.Sockaddr
74
+ localSockaddr syscall.Sockaddr
75
+ )
76
+
77
+ netAddr, err := ResolveAddr(netw, addr)
78
+ if err != nil {
79
+ // fmt.Println("resolve addr failed")
80
+ return nil, err
81
+ }
82
+
83
+ switch netAddr.(type) {
84
+ case *net.TCPAddr, *net.UDPAddr:
85
+ default:
86
+ return nil, ErrUnsupportedProtocol
87
+ }
88
+
89
+ localSockaddr = sockaddrnet.NetAddrToSockaddr(dialer.LocalAddr)
90
+ remoteSockaddr = sockaddrnet.NetAddrToSockaddr(netAddr)
91
+
92
+ rfamily = sockaddrnet.NetAddrAF(netAddr)
93
+ rprotocol = sockaddrnet.NetAddrIPPROTO(netAddr)
94
+ socktype = sockaddrnet.NetAddrSOCK(netAddr)
95
+
96
+ if dialer.LocalAddr != nil {
97
+ switch dialer.LocalAddr.(type) {
98
+ case *net.TCPAddr, *net.UDPAddr:
99
+ default:
100
+ return nil, ErrUnsupportedProtocol
101
+ }
102
+
103
+ // check family and protocols match.
104
+ lfamily = sockaddrnet.NetAddrAF(dialer.LocalAddr)
105
+ lprotocol = sockaddrnet.NetAddrIPPROTO(dialer.LocalAddr)
106
+ if lfamily != rfamily && lprotocol != rfamily {
107
+ return nil, &net.AddrError{Err: "unexpected address type", Addr: netAddr.String()}
108
+ }
109
+ }
110
+
111
+ if fd, err = socket(rfamily, socktype, rprotocol); err != nil {
112
+ return nil, err
113
+ }
114
+
115
+ if err = syscall.Bind(fd, localSockaddr); err != nil {
116
+ // fmt.Println("bind failed")
117
+ syscall.Close(fd)
118
+ return nil, err
119
+ }
120
+ if err = connect(fd, remoteSockaddr); err != nil {
121
+ syscall.Close(fd)
122
+ // fmt.Println("connect failed", localSockaddr, err)
123
+ return nil, err
124
+ }
125
+
126
+ if rprotocol == syscall.IPPROTO_TCP {
127
+ // by default golang/net sets TCP no delay to true.
128
+ if err = setNoDelay(fd, true); err != nil {
129
+ // fmt.Println("set no delay failed")
130
+ syscall.Close(fd)
131
+ return nil, err
132
+ }
133
+ }
134
+
135
+ if err = syscall.SetNonblock(fd, true); err != nil {
136
+ syscall.Close(fd)
137
+ return nil, err
138
+ }
139
+
140
+ switch socktype {
141
+ case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
142
+
143
+ // File Name get be nil
144
+ file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid()))
145
+ if c, err = net.FileConn(file); err != nil {
146
+ // fmt.Println("fileconn failed")
147
+ syscall.Close(fd)
148
+ return nil, err
149
+ }
150
+
151
+ case syscall.SOCK_DGRAM:
152
+
153
+ // File Name get be nil
154
+ file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid()))
155
+ if c, err = net.FileConn(file); err != nil {
156
+ // fmt.Println("fileconn failed")
157
+ syscall.Close(fd)
158
+ return nil, err
159
+ }
160
+ }
161
+
162
+ if err = file.Close(); err != nil {
163
+ // fmt.Println("file close failed")
164
+ syscall.Close(fd)
165
+ return nil, err
166
+ }
167
+
168
+ return c, err
169
+}
170
+
171
+func listen(netw, addr string) (fd int, err error) {
172
+ var (
173
+ family int
174
+ socktype int
175
+ protocol int
176
+ sockaddr syscall.Sockaddr
177
+ )
178
+
179
+ netAddr, err := ResolveAddr(netw, addr)
180
+ if err != nil {
181
+ // fmt.Println("resolve addr failed")
182
+ return -1, err
183
+ }
184
+
185
+ switch netAddr.(type) {
186
+ case *net.TCPAddr, *net.UDPAddr:
187
+ default:
188
+ return -1, ErrUnsupportedProtocol
189
+ }
190
+
191
+ family = sockaddrnet.NetAddrAF(netAddr)
192
+ protocol = sockaddrnet.NetAddrIPPROTO(netAddr)
193
+ sockaddr = sockaddrnet.NetAddrToSockaddr(netAddr)
194
+ socktype = sockaddrnet.NetAddrSOCK(netAddr)
195
+
196
+ if fd, err = socket(family, socktype, protocol); err != nil {
197
+ return -1, err
198
+ }
199
+
200
+ if err = syscall.Bind(fd, sockaddr); err != nil {
201
+ // fmt.Println("bind failed")
202
+ syscall.Close(fd)
203
+ return -1, err
204
+ }
205
+
206
+ if protocol == syscall.IPPROTO_TCP {
207
+ // by default golang/net sets TCP no delay to true.
208
+ if err = setNoDelay(fd, true); err != nil {
209
+ // fmt.Println("set no delay failed")
210
+ syscall.Close(fd)
211
+ return -1, err
212
+ }
213
+ }
214
+
215
+ if err = syscall.SetNonblock(fd, true); err != nil {
216
+ syscall.Close(fd)
217
+ return -1, err
218
+ }
219
+
220
+ return fd, nil
221
+}
222
+
223
+func listenStream(netw, addr string) (l net.Listener, err error) {
224
+ var (
225
+ file *os.File
226
+ )
227
+
228
+ fd, err := listen(netw, addr)
229
+ if err != nil {
230
+ return nil, err
231
+ }
232
+
233
+ // Set backlog size to the maximum
234
+ if err = syscall.Listen(fd, syscall.SOMAXCONN); err != nil {
235
+ // fmt.Println("listen failed")
236
+ syscall.Close(fd)
237
+ return nil, err
238
+ }
239
+
240
+ file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid()))
241
+ if l, err = net.FileListener(file); err != nil {
242
+ // fmt.Println("filelistener failed")
243
+ syscall.Close(fd)
244
+ return nil, err
245
+ }
246
+
247
+ if err = file.Close(); err != nil {
248
+ // fmt.Println("file close failed")
249
+ syscall.Close(fd)
250
+ return nil, err
251
+ }
252
+
253
+ return l, err
254
+}
255
+
256
+func listenPacket(netw, addr string) (p net.PacketConn, err error) {
257
+ var (
258
+ file *os.File
259
+ )
260
+
261
+ fd, err := listen(netw, addr)
262
+ if err != nil {
263
+ return nil, err
264
+ }
265
+
266
+ file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid()))
267
+ if p, err = net.FilePacketConn(file); err != nil {
268
+ // fmt.Println("filelistener failed")
269
+ syscall.Close(fd)
270
+ return nil, err
271
+ }
272
+
273
+ if err = file.Close(); err != nil {
274
+ // fmt.Println("file close failed")
275
+ syscall.Close(fd)
276
+ return nil, err
277
+ }
278
+
279
+ return p, err
280
+}
281
+
282
+func listenUDP(netw, addr string) (c net.Conn, err error) {
283
+ var (
284
+ file *os.File
285
+ )
286
+
287
+ fd, err := listen(netw, addr)
288
+ if err != nil {
289
+ return nil, err
290
+ }
291
+
292
+ file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid()))
293
+ if c, err = net.FileConn(file); err != nil {
294
+ // fmt.Println("filelistener failed")
295
+ syscall.Close(fd)
296
+ return nil, err
297
+ }
298
+
299
+ if err = file.Close(); err != nil {
300
+ // fmt.Println("file close failed")
301
+ syscall.Close(fd)
302
+ return nil, err
303
+ }
304
+
305
+ return c, err
306
+}
307
+
308
+func connect(fd int, ra syscall.Sockaddr) error {
309
+ switch err := syscall.Connect(fd, ra); err {
310
+ case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
311
+ case nil, syscall.EISCONN:
312
+ return nil
313
+ default:
314
+ return err
315
+ }
316
+
317
+ var err error
318
+ for {
319
+ // if err := fd.pd.WaitWrite(); err != nil {
320
+ // return err
321
+ // }
322
+ // i'd use the above fd.pd.WaitWrite to poll io correctly, just like net sockets...
323
+ // but of course, it uses fucking runtime_* functions that _cannot_ be used by
324
+ // non-go-stdlib source... seriously guys, what kind of bullshit is that!?
325
+ <-time.After(20 * time.Microsecond)
326
+ var nerr int
327
+ nerr, err = syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_ERROR)
328
+ if err != nil {
329
+ return err
330
+ }
331
+ switch err = syscall.Errno(nerr); err {
332
+ case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
333
+ case syscall.Errno(0), syscall.EISCONN:
334
+ return nil
335
+ default:
336
+ return err
337
+ }
338
+ }
339
+}
Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_windows.go
new
+15
@@ -0,0 +1,15 @@
1
+package reuseport
2
+
3
+import (
4
+ "net"
5
+)
6
+
7
+// TODO. for now, just pass it over to net.Listen/net.Dial
8
+
9
+func listen(network, address string) (net.Listener, error) {
10
+ return net.Listen(network, address)
11
+}
12
+
13
+func dial(dialer net.Dialer, network, address string) (net.Conn, error) {
14
+ return dialer.Dial(network, address)
15
+}
Godeps/_workspace/src/github.com/jbenet/go-reuseport/interface.go
new
+91
@@ -0,0 +1,91 @@
1
+// Package reuseport provides Listen and Dial functions that set socket options
2
+// in order to be able to reuse ports. You should only use this package if you
3
+// know what SO_REUSEADDR and SO_REUSEPORT are.
4
+//
5
+// For example:
6
+//
7
+// // listen on the same port. oh yeah.
8
+// l1, _ := reuse.Listen("tcp", "127.0.0.1:1234")
9
+// l2, _ := reuse.Listen("tcp", "127.0.0.1:1234")
10
+//
11
+// // dial from the same port. oh yeah.
12
+// l1, _ := reuse.Listen("tcp", "127.0.0.1:1234")
13
+// l2, _ := reuse.Listen("tcp", "127.0.0.1:1235")
14
+// c, _ := reuse.Dial("tcp", "127.0.0.1:1234", "127.0.0.1:1235")
15
+//
16
+// Note: cant dial self because tcp/ip stacks use 4-tuples to identify connections,
17
+// and doing so would clash.
18
+package reuseport
19
+
20
+import (
21
+ "errors"
22
+ "net"
23
+ "time"
24
+)
25
+
26
+// ErrUnsuportedProtocol signals that the protocol is not currently
27
+// supported by this package. This package currently only supports TCP.
28
+var ErrUnsupportedProtocol = errors.New("protocol not yet supported")
29
+
30
+// ErrReuseFailed is returned if a reuse attempt was unsuccessful.
31
+var ErrReuseFailed = errors.New("reuse failed")
32
+
33
+// Listen listens at the given network and address. see net.Listen
34
+// Returns a net.Listener created from a file discriptor for a socket
35
+// with SO_REUSEPORT and SO_REUSEADDR option set.
36
+func Listen(network, address string) (net.Listener, error) {
37
+ return listenStream(network, address)
38
+}
39
+
40
+// ListenPacket listens at the given network and address. see net.ListenPacket
41
+// Returns a net.Listener created from a file discriptor for a socket
42
+// with SO_REUSEPORT and SO_REUSEADDR option set.
43
+func ListenPacket(network, address string) (net.PacketConn, error) {
44
+ return listenPacket(network, address)
45
+}
46
+
47
+// Dial dials the given network and address. see net.Dialer.Dial
48
+// Returns a net.Conn created from a file discriptor for a socket
49
+// with SO_REUSEPORT and SO_REUSEADDR option set.
50
+func Dial(network, laddr, raddr string) (net.Conn, error) {
51
+
52
+ var d Dialer
53
+ if laddr != "" {
54
+ netladdr, err := ResolveAddr(network, laddr)
55
+ if err != nil {
56
+ return nil, err
57
+ }
58
+ d.D.LocalAddr = netladdr
59
+ }
60
+
61
+ return d.Dial(network, raddr)
62
+}
63
+
64
+// Dialer is used to specify the Dial options, much like net.Dialer.
65
+// We simply wrap a net.Dialer.
66
+type Dialer struct {
67
+ D net.Dialer
68
+}
69
+
70
+// Dial dials the given network and address. see net.Dialer.Dial
71
+// Returns a net.Conn created from a file discriptor for a socket
72
+// with SO_REUSEPORT and SO_REUSEADDR option set.
73
+func (d *Dialer) Dial(network, address string) (net.Conn, error) {
74
+ // there's a rare case where dial returns successfully but for some reason the
75
+ // RemoteAddr is not yet set. We wait here a while until it is, and if too long
76
+ // passes, we fail.
77
+ c, err := dial(d.D, network, address)
78
+ if err != nil {
79
+ return nil, err
80
+ }
81
+
82
+ for start := time.Now(); c.RemoteAddr() == nil; {
83
+ if time.Now().Sub(start) > time.Second {
84
+ c.Close()
85
+ return nil, ErrReuseFailed
86
+ }
87
+
88
+ <-time.After(20 * time.Microsecond)
89
+ }
90
+ return c, nil
91
+}
Godeps/_workspace/src/github.com/jbenet/go-reuseport/opts_posix.go
new
+35
@@ -0,0 +1,35 @@
1
+// Copyright 2009 The Go Authors. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
6
+
7
+package reuseport
8
+
9
+import (
10
+ "os"
11
+ "syscall"
12
+)
13
+
14
+func boolint(b bool) int {
15
+ if b {
16
+ return 1
17
+ }
18
+ return 0
19
+}
20
+
21
+func setNoDelay(fd int, noDelay bool) error {
22
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay)))
23
+}
24
+
25
+func setLinger(fd int, sec int) error {
26
+ var l syscall.Linger
27
+ if sec >= 0 {
28
+ l.Onoff = 1
29
+ l.Linger = int32(sec)
30
+ } else {
31
+ l.Onoff = 0
32
+ l.Linger = 0
33
+ }
34
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptLinger(fd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l))
35
+}
Godeps/_workspace/src/github.com/jbenet/go-reuseport/reuse_test.go
new
+374
@@ -0,0 +1,374 @@
1
+package reuseport
2
+
3
+import (
4
+ "bytes"
5
+ "io"
6
+ "net"
7
+ "os"
8
+ "strings"
9
+ "testing"
10
+)
11
+
12
+func echo(c net.Conn) {
13
+ io.Copy(c, c)
14
+ c.Close()
15
+}
16
+
17
+func packetEcho(c net.PacketConn) {
18
+ buf := make([]byte, 65536)
19
+ for {
20
+ n, addr, err := c.ReadFrom(buf)
21
+ if err != nil {
22
+ return
23
+ }
24
+ if _, err := c.WriteTo(buf[:n], addr); err != nil {
25
+ return
26
+ }
27
+ }
28
+}
29
+
30
+func acceptAndEcho(l net.Listener) {
31
+ for {
32
+ c, err := l.Accept()
33
+ if err != nil {
34
+ return
35
+ }
36
+ go echo(c)
37
+ }
38
+}
39
+
40
+func CI() bool {
41
+ return os.Getenv("TRAVIS") == "true"
42
+}
43
+
44
+func TestStreamListenSamePort(t *testing.T) {
45
+
46
+ // any ports
47
+ any := [][]string{
48
+ []string{"tcp", "0.0.0.0:0"},
49
+ []string{"tcp4", "0.0.0.0:0"},
50
+ []string{"tcp6", "[::]:0"},
51
+
52
+ []string{"tcp", "127.0.0.1:0"},
53
+ []string{"tcp", "[::1]:0"},
54
+ []string{"tcp4", "127.0.0.1:0"},
55
+ []string{"tcp6", "[::1]:0"},
56
+ }
57
+
58
+ // specific ports. off in CI
59
+ specific := [][]string{
60
+ []string{"tcp", "127.0.0.1:5556"},
61
+ []string{"tcp", "[::1]:5557"},
62
+ []string{"tcp4", "127.0.0.1:5558"},
63
+ []string{"tcp6", "[::1]:5559"},
64
+ }
65
+
66
+ testCases := any
67
+ if !CI() {
68
+ testCases = append(testCases, specific...)
69
+ }
70
+
71
+ for _, tcase := range testCases {
72
+ network := tcase[0]
73
+ addr := tcase[1]
74
+ t.Log("testing", network, addr)
75
+
76
+ l1, err := Listen(network, addr)
77
+ if err != nil {
78
+ t.Fatal(err)
79
+ continue
80
+ }
81
+ defer l1.Close()
82
+ t.Log("listening", l1.Addr())
83
+
84
+ l2, err := Listen(l1.Addr().Network(), l1.Addr().String())
85
+ if err != nil {
86
+ t.Fatal(err)
87
+ continue
88
+ }
89
+ defer l2.Close()
90
+ t.Log("listening", l2.Addr())
91
+
92
+ l3, err := Listen(l2.Addr().Network(), l2.Addr().String())
93
+ if err != nil {
94
+ t.Fatal(err)
95
+ continue
96
+ }
97
+ defer l3.Close()
98
+ t.Log("listening", l3.Addr())
99
+
100
+ if l1.Addr().String() != l2.Addr().String() {
101
+ t.Fatal("addrs should match", l1.Addr(), l2.Addr())
102
+ }
103
+
104
+ if l1.Addr().String() != l3.Addr().String() {
105
+ t.Fatal("addrs should match", l1.Addr(), l3.Addr())
106
+ }
107
+ }
108
+}
109
+
110
+func TestPacketListenSamePort(t *testing.T) {
111
+
112
+ // any ports
113
+ any := [][]string{
114
+ []string{"udp", "0.0.0.0:0"},
115
+ []string{"udp4", "0.0.0.0:0"},
116
+ []string{"udp6", "[::]:0"},
117
+
118
+ []string{"udp", "127.0.0.1:0"},
119
+ []string{"udp", "[::1]:0"},
120
+ []string{"udp4", "127.0.0.1:0"},
121
+ []string{"udp6", "[::1]:0"},
122
+ }
123
+
124
+ // specific ports. off in CI
125
+ specific := [][]string{
126
+ []string{"udp", "127.0.0.1:5560"},
127
+ []string{"udp", "[::1]:5561"},
128
+ []string{"udp4", "127.0.0.1:5562"},
129
+ []string{"udp6", "[::1]:5563"},
130
+ }
131
+
132
+ testCases := any
133
+ if !CI() {
134
+ testCases = append(testCases, specific...)
135
+ }
136
+
137
+ for _, tcase := range testCases {
138
+ network := tcase[0]
139
+ addr := tcase[1]
140
+ t.Log("testing", network, addr)
141
+
142
+ l1, err := ListenPacket(network, addr)
143
+ if err != nil {
144
+ t.Fatal(err)
145
+ continue
146
+ }
147
+ defer l1.Close()
148
+ t.Log("listening", l1.LocalAddr())
149
+
150
+ l2, err := ListenPacket(l1.LocalAddr().Network(), l1.LocalAddr().String())
151
+ if err != nil {
152
+ t.Fatal(err)
153
+ continue
154
+ }
155
+ defer l2.Close()
156
+ t.Log("listening", l2.LocalAddr())
157
+
158
+ l3, err := ListenPacket(l2.LocalAddr().Network(), l2.LocalAddr().String())
159
+ if err != nil {
160
+ t.Fatal(err)
161
+ continue
162
+ }
163
+ defer l3.Close()
164
+ t.Log("listening", l3.LocalAddr())
165
+
166
+ if l1.LocalAddr().String() != l2.LocalAddr().String() {
167
+ t.Fatal("addrs should match", l1.LocalAddr(), l2.LocalAddr())
168
+ }
169
+
170
+ if l1.LocalAddr().String() != l3.LocalAddr().String() {
171
+ t.Fatal("addrs should match", l1.LocalAddr(), l3.LocalAddr())
172
+ }
173
+ }
174
+}
175
+
176
+func TestStreamListenDialSamePort(t *testing.T) {
177
+
178
+ any := [][]string{
179
+ []string{"tcp", "0.0.0.0:0", "0.0.0.0:0"},
180
+ []string{"tcp4", "0.0.0.0:0", "0.0.0.0:0"},
181
+ []string{"tcp6", "[::]:0", "[::]:0"},
182
+
183
+ []string{"tcp", "127.0.0.1:0", "127.0.0.1:0"},
184
+ []string{"tcp4", "127.0.0.1:0", "127.0.0.1:0"},
185
+ []string{"tcp6", "[::1]:0", "[::1]:0"},
186
+ }
187
+
188
+ specific := [][]string{
189
+ []string{"tcp", "127.0.0.1:0", "127.0.0.1:5571"},
190
+ []string{"tcp4", "127.0.0.1:0", "127.0.0.1:5573"},
191
+ []string{"tcp6", "[::1]:0", "[::1]:5574"},
192
+ []string{"tcp", "127.0.0.1:5570", "127.0.0.1:0"},
193
+ []string{"tcp4", "127.0.0.1:5572", "127.0.0.1:0"},
194
+ []string{"tcp6", "[::1]:5573", "[::1]:0"},
195
+ }
196
+
197
+ testCases := any
198
+ if !CI() {
199
+ testCases = append(testCases, specific...)
200
+ }
201
+
202
+ for _, tcase := range testCases {
203
+ t.Log("testing", tcase)
204
+ network := tcase[0]
205
+ addr1 := tcase[1]
206
+ addr2 := tcase[2]
207
+
208
+ l1, err := Listen(network, addr1)
209
+ if err != nil {
210
+ t.Fatal(err)
211
+ continue
212
+ }
213
+ defer l1.Close()
214
+ t.Log("listening", l1.Addr())
215
+
216
+ l2, err := Listen(network, addr2)
217
+ if err != nil {
218
+ t.Fatal(err)
219
+ continue
220
+ }
221
+ defer l2.Close()
222
+ t.Log("listening", l2.Addr())
223
+
224
+ go acceptAndEcho(l1)
225
+ go acceptAndEcho(l2)
226
+
227
+ c1, err := Dial(network, l1.Addr().String(), l2.Addr().String())
228
+ if err != nil {
229
+ t.Fatal(err)
230
+ continue
231
+ }
232
+ defer c1.Close()
233
+ t.Log("dialed", c1, c1.LocalAddr(), c1.RemoteAddr())
234
+
235
+ if getPort(l1.Addr()) != getPort(c1.LocalAddr()) {
236
+ t.Fatal("addrs should match", l1.Addr(), c1.LocalAddr())
237
+ }
238
+
239
+ if getPort(l2.Addr()) != getPort(c1.RemoteAddr()) {
240
+ t.Fatal("addrs should match", l2.Addr(), c1.RemoteAddr())
241
+ }
242
+
243
+ hello1 := []byte("hello world")
244
+ hello2 := make([]byte, len(hello1))
245
+ if _, err := c1.Write(hello1); err != nil {
246
+ t.Fatal(err)
247
+ continue
248
+ }
249
+
250
+ if _, err := c1.Read(hello2); err != nil {
251
+ t.Fatal(err)
252
+ continue
253
+ }
254
+
255
+ if !bytes.Equal(hello1, hello2) {
256
+ t.Fatal("echo failed", string(hello1), "!=", string(hello2))
257
+ }
258
+ t.Log("echoed", string(hello2))
259
+ c1.Close()
260
+ }
261
+}
262
+
263
+func TestPacketListenDialSamePort(t *testing.T) {
264
+
265
+ any := [][]string{
266
+ []string{"udp", "0.0.0.0:0", "0.0.0.0:0"},
267
+ []string{"udp4", "0.0.0.0:0", "0.0.0.0:0"},
268
+ []string{"udp6", "[::]:0", "[::]:0"},
269
+
270
+ []string{"udp", "127.0.0.1:0", "127.0.0.1:0"},
271
+ []string{"udp4", "127.0.0.1:0", "127.0.0.1:0"},
272
+ []string{"udp6", "[::1]:0", "[::1]:0"},
273
+ }
274
+
275
+ specific := [][]string{
276
+ []string{"udp", "127.0.0.1:5670", "127.0.0.1:5671"},
277
+ []string{"udp4", "127.0.0.1:5672", "127.0.0.1:5673"},
278
+ []string{"udp6", "[::1]:5673", "[::1]:5674"},
279
+ }
280
+
281
+ testCases := any
282
+ if !CI() {
283
+ testCases = append(testCases, specific...)
284
+ }
285
+
286
+ for _, tcase := range testCases {
287
+ t.Log("testing", tcase)
288
+ network := tcase[0]
289
+ addr1 := tcase[1]
290
+ addr2 := tcase[2]
291
+
292
+ l1, err := ListenPacket(network, addr1)
293
+ if err != nil {
294
+ t.Fatal(err)
295
+ continue
296
+ }
297
+ defer l1.Close()
298
+ t.Log("listening", l1.LocalAddr())
299
+
300
+ l2, err := ListenPacket(network, addr2)
301
+ if err != nil {
302
+ t.Fatal(err)
303
+ continue
304
+ }
305
+ defer l2.Close()
306
+ t.Log("listening", l2.LocalAddr())
307
+
308
+ go packetEcho(l1)
309
+ go packetEcho(l2)
310
+
311
+ c1, err := Dial(network, l1.LocalAddr().String(), l2.LocalAddr().String())
312
+ if err != nil {
313
+ t.Fatal(err)
314
+ continue
315
+ }
316
+ defer c1.Close()
317
+ t.Log("dialed", c1.LocalAddr(), c1.RemoteAddr())
318
+
319
+ if getPort(l1.LocalAddr()) != getPort(c1.LocalAddr()) {
320
+ t.Fatal("addrs should match", l1.LocalAddr(), c1.LocalAddr())
321
+ }
322
+
323
+ if getPort(l2.LocalAddr()) != getPort(c1.RemoteAddr()) {
324
+ t.Fatal("addrs should match", l2.LocalAddr(), c1.RemoteAddr())
325
+ }
326
+
327
+ hello1 := []byte("hello world")
328
+ hello2 := make([]byte, len(hello1))
329
+ if _, err := c1.Write(hello1); err != nil {
330
+ t.Fatal(err)
331
+ continue
332
+ }
333
+
334
+ if _, err := c1.Read(hello2); err != nil {
335
+ t.Fatal(err)
336
+ continue
337
+ }
338
+
339
+ if !bytes.Equal(hello1, hello2) {
340
+ t.Fatal("echo failed", string(hello1), "!=", string(hello2))
341
+ }
342
+ t.Log("echoed", string(hello2))
343
+ }
344
+}
345
+
346
+func TestUnixNotSupported(t *testing.T) {
347
+
348
+ testCases := [][]string{
349
+ []string{"unix", "/tmp/foo"},
350
+ }
351
+
352
+ for _, tcase := range testCases {
353
+ network := tcase[0]
354
+ addr := tcase[1]
355
+ t.Log("testing", network, addr)
356
+
357
+ _, err := Listen(network, addr)
358
+ if err == nil {
359
+ t.Fatal("unix supported")
360
+ continue
361
+ }
362
+ }
363
+}
364
+
365
+func getPort(a net.Addr) string {
366
+ if a == nil {
367
+ return ""
368
+ }
369
+ s := strings.Split(a.String(), ":")
370
+ if len(s) > 1 {
371
+ return s[1]
372
+ }
373
+ return ""
374
+}
Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/.gitignore
new
+1
@@ -0,0 +1 @@
1
+test
Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/main.go
new
+71
@@ -0,0 +1,71 @@
1
+package main
2
+
3
+import (
4
+ "fmt"
5
+ "io"
6
+ "net"
7
+ "os"
8
+
9
+ reuse "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport"
10
+ resolve "github.com/jbenet/go-net-resolve-addr"
11
+)
12
+
13
+func main() {
14
+
15
+ l1, err := reuse.Listen("tcp", "0.0.0.0:11111")
16
+ maybeDie(err)
17
+ fmt.Printf("listening on %s\n", l1.Addr())
18
+
19
+ l2, err := reuse.Listen("tcp", "0.0.0.0:22222")
20
+ maybeDie(err)
21
+ fmt.Printf("listening on %s\n", l2.Addr())
22
+
23
+ a1, err := resolve.ResolveAddr("dial", "tcp", "127.0.0.1:11111")
24
+ maybeDie(err)
25
+
26
+ a3, err := resolve.ResolveAddr("dial", "tcp", "127.0.0.1:33333")
27
+ maybeDie(err)
28
+
29
+ d1 := reuse.Dialer{net.Dialer{LocalAddr: a1}}
30
+ d2 := reuse.Dialer{net.Dialer{LocalAddr: a3}}
31
+
32
+ go func() {
33
+ l2to1foo, err := l2.Accept()
34
+ maybeDie(err)
35
+ fmt.Printf("%s accepted conn from %s\n", addrStr(l2.Addr()), addrStr(l2to1foo.RemoteAddr()))
36
+
37
+ fmt.Println("safe")
38
+
39
+ l1to2bar, err := l1.Accept()
40
+ maybeDie(err)
41
+ fmt.Printf("%s accepted conn from %s\n", addrStr(l1.Addr()), addrStr(l1to2bar.RemoteAddr()))
42
+
43
+ io.Copy(l1to2bar, l2to1foo)
44
+ }()
45
+
46
+ d1to2foo, err := d1.Dial("tcp4", "127.0.0.1:22222")
47
+ maybeDie(err)
48
+ fmt.Printf("dialing from %s to %s\n", d1.D.LocalAddr, "127.0.0.1:22222")
49
+
50
+ d2to1bar, err := d2.Dial("tcp4", "127.0.0.1:11111")
51
+ maybeDie(err)
52
+ fmt.Printf("dialing from %s to %s\n", d2.D.LocalAddr, "127.0.0.1:11111")
53
+
54
+ go io.Copy(d1to2foo, os.Stdin)
55
+ io.Copy(os.Stdout, d2to1bar)
56
+}
57
+
58
+func die(err error) {
59
+ fmt.Fprintf(os.Stderr, "%s\n", err)
60
+ os.Exit(-1)
61
+}
62
+
63
+func maybeDie(err error) {
64
+ if err != nil {
65
+ die(err)
66
+ }
67
+}
68
+
69
+func addrStr(a net.Addr) string {
70
+ return fmt.Sprintf("%s/%s", a.Network(), a)
71
+}
Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net.go
new
+341
@@ -0,0 +1,341 @@
1
+// package sockaddrnet provides conversions between net.Addr and syscall.Sockaddr
2
+package sockaddrnet
3
+
4
+import (
5
+ "net"
6
+ "syscall"
7
+)
8
+
9
+// NetAddrAF returns the syscall AF_* type for a given net.Addr
10
+// returns AF_UNSPEC if unknown
11
+func NetAddrAF(addr net.Addr) int {
12
+ switch addr := addr.(type) {
13
+ default:
14
+ return AF_UNSPEC
15
+
16
+ case *net.IPAddr:
17
+ return IPAF(addr.IP)
18
+
19
+ case *net.TCPAddr:
20
+ return IPAF(addr.IP)
21
+
22
+ case *net.UDPAddr:
23
+ return IPAF(addr.IP)
24
+
25
+ case *net.UnixAddr:
26
+ return AF_UNIX
27
+ }
28
+}
29
+
30
+// IPAF returns the syscall AF_* type for a given IP address
31
+// returns AF_UNSPEC if unknown
32
+func IPAF(ip net.IP) int {
33
+ switch {
34
+ default:
35
+ return AF_UNSPEC
36
+
37
+ case ip.To4() != nil:
38
+ return AF_INET
39
+
40
+ case ip.To16() != nil:
41
+ return AF_INET6
42
+ }
43
+}
44
+
45
+// NetAddrIPPROTO returns the syscall IPPROTO_* type for a given net.Addr
46
+// returns -1 if protocol unknown
47
+func NetAddrIPPROTO(addr net.Addr) int {
48
+ switch addr := addr.(type) {
49
+ default:
50
+ return -1
51
+
52
+ case *net.IPAddr:
53
+ switch {
54
+ default:
55
+ return IPPROTO_IP
56
+
57
+ case addr.IP.To4() != nil:
58
+ return IPPROTO_IPV4
59
+
60
+ case addr.IP.To16() != nil:
61
+ return IPPROTO_IPV6
62
+ }
63
+
64
+ case *net.TCPAddr:
65
+ return IPPROTO_TCP
66
+
67
+ case *net.UDPAddr:
68
+ return IPPROTO_UDP
69
+ }
70
+}
71
+
72
+// NetAddrSOCK returns the syscall SOCK_* type for a given net.Addr
73
+// returns 0 if type unknown
74
+func NetAddrSOCK(addr net.Addr) int {
75
+ switch addr := addr.(type) {
76
+ default:
77
+ return 0
78
+ case *net.IPAddr:
79
+ return SOCK_DGRAM
80
+ case *net.TCPAddr:
81
+ return SOCK_STREAM
82
+ case *net.UDPAddr:
83
+ return SOCK_DGRAM
84
+ case *net.UnixAddr:
85
+ switch addr.Net {
86
+ default:
87
+ return 0
88
+ case "unix":
89
+ return SOCK_STREAM
90
+ case "unixgram":
91
+ return SOCK_DGRAM
92
+ case "unixpacket":
93
+ return SOCK_SEQPACKET
94
+ }
95
+ }
96
+}
97
+
98
+// NetAddrToSockaddr converts a net.Addr to a syscall.Sockaddr.
99
+// Returns nil if the input is invalid or conversion is not possible.
100
+func NetAddrToSockaddr(addr net.Addr) syscall.Sockaddr {
101
+ switch addr := addr.(type) {
102
+ default:
103
+ return nil
104
+ case *net.IPAddr:
105
+ return IPAddrToSockaddr(addr)
106
+ case *net.TCPAddr:
107
+ return TCPAddrToSockaddr(addr)
108
+ case *net.UDPAddr:
109
+ return UDPAddrToSockaddr(addr)
110
+ case *net.UnixAddr:
111
+ sa, _ := UnixAddrToSockaddr(addr)
112
+ return sa
113
+ }
114
+}
115
+
116
+// IPAndZoneToSockaddr converts a net.IP (with optional IPv6 Zone) to a syscall.Sockaddr
117
+// Returns nil if conversion fails.
118
+func IPAndZoneToSockaddr(ip net.IP, zone string) syscall.Sockaddr {
119
+ switch {
120
+ case len(ip) < net.IPv4len: // default to IPv4
121
+ buf := [4]byte{0, 0, 0, 0}
122
+ return &syscall.SockaddrInet4{Addr: buf}
123
+
124
+ case ip.To4() != nil:
125
+ var buf [4]byte
126
+ copy(buf[:], ip[12:16]) // last 4 bytes
127
+ return &syscall.SockaddrInet4{Addr: buf}
128
+
129
+ case ip.To16() != nil:
130
+ var buf [16]byte
131
+ copy(buf[:], ip)
132
+ return &syscall.SockaddrInet6{Addr: buf, ZoneId: uint32(IP6ZoneToInt(zone))}
133
+ }
134
+ panic("should be unreachable")
135
+}
136
+
137
+// IPAddrToSockaddr converts a net.IPAddr to a syscall.Sockaddr.
138
+// Returns nil if conversion fails.
139
+func IPAddrToSockaddr(addr *net.IPAddr) syscall.Sockaddr {
140
+ return IPAndZoneToSockaddr(addr.IP, addr.Zone)
141
+}
142
+
143
+// TCPAddrToSockaddr converts a net.TCPAddr to a syscall.Sockaddr.
144
+// Returns nil if conversion fails.
145
+func TCPAddrToSockaddr(addr *net.TCPAddr) syscall.Sockaddr {
146
+ sa := IPAndZoneToSockaddr(addr.IP, addr.Zone)
147
+ switch sa := sa.(type) {
148
+ default:
149
+ return nil
150
+ case *syscall.SockaddrInet4:
151
+ sa.Port = addr.Port
152
+ return sa
153
+ case *syscall.SockaddrInet6:
154
+ sa.Port = addr.Port
155
+ return sa
156
+ }
157
+}
158
+
159
+// UDPAddrToSockaddr converts a net.UDPAddr to a syscall.Sockaddr.
160
+// Returns nil if conversion fails.
161
+func UDPAddrToSockaddr(addr *net.UDPAddr) syscall.Sockaddr {
162
+ sa := IPAndZoneToSockaddr(addr.IP, addr.Zone)
163
+ switch sa := sa.(type) {
164
+ default:
165
+ return nil
166
+ case *syscall.SockaddrInet4:
167
+ sa.Port = addr.Port
168
+ return sa
169
+ case *syscall.SockaddrInet6:
170
+ sa.Port = addr.Port
171
+ return sa
172
+ }
173
+}
174
+
175
+// UnixAddrToSockaddr converts a net.UnixAddr to a syscall.Sockaddr, and returns
176
+// the type (syscall.SOCK_STREAM, syscall.SOCK_DGRAM, syscall.SOCK_SEQPACKET)
177
+// Returns (nil, 0) if conversion fails.
178
+func UnixAddrToSockaddr(addr *net.UnixAddr) (syscall.Sockaddr, int) {
179
+ t := 0
180
+ switch addr.Net {
181
+ default:
182
+ return nil, 0
183
+ case "unix":
184
+ t = syscall.SOCK_STREAM
185
+ case "unixgram":
186
+ t = syscall.SOCK_DGRAM
187
+ case "unixpacket":
188
+ t = syscall.SOCK_SEQPACKET
189
+ }
190
+ return &syscall.SockaddrUnix{Name: addr.Name}, t
191
+}
192
+
193
+// IPAndZoneToSockaddr converts a net.IP (with optional IPv6 Zone) to a syscall.Sockaddr
194
+// Returns nil if conversion fails.
195
+func SockaddrToIPAndZone(sa syscall.Sockaddr) (net.IP, string) {
196
+ switch sa := sa.(type) {
197
+ case *syscall.SockaddrInet4:
198
+ ip := make([]byte, 16)
199
+ copy(ip[12:16], sa.Addr[:])
200
+ return ip, ""
201
+
202
+ case *syscall.SockaddrInet6:
203
+ ip := make([]byte, 16)
204
+ copy(ip, sa.Addr[:])
205
+ return ip, IP6ZoneToString(int(sa.ZoneId))
206
+ }
207
+ return nil, ""
208
+}
209
+
210
+// SockaddrToIPAddr converts a syscall.Sockaddr to a net.IPAddr
211
+// Returns nil if conversion fails.
212
+func SockaddrToIPAddr(sa syscall.Sockaddr) *net.IPAddr {
213
+ ip, zone := SockaddrToIPAndZone(sa)
214
+ switch sa.(type) {
215
+ case *syscall.SockaddrInet4:
216
+ return &net.IPAddr{IP: ip}
217
+ case *syscall.SockaddrInet6:
218
+ return &net.IPAddr{IP: ip, Zone: zone}
219
+ }
220
+ return nil
221
+}
222
+
223
+// SockaddrToTCPAddr converts a syscall.Sockaddr to a net.TCPAddr
224
+// Returns nil if conversion fails.
225
+func SockaddrToTCPAddr(sa syscall.Sockaddr) *net.TCPAddr {
226
+ ip, zone := SockaddrToIPAndZone(sa)
227
+ switch sa := sa.(type) {
228
+ case *syscall.SockaddrInet4:
229
+ return &net.TCPAddr{IP: ip, Port: sa.Port}
230
+ case *syscall.SockaddrInet6:
231
+ return &net.TCPAddr{IP: ip, Port: sa.Port, Zone: zone}
232
+ }
233
+ return nil
234
+}
235
+
236
+// SockaddrToUDPAddr converts a syscall.Sockaddr to a net.UDPAddr
237
+// Returns nil if conversion fails.
238
+func SockaddrToUDPAddr(sa syscall.Sockaddr) *net.UDPAddr {
239
+ ip, zone := SockaddrToIPAndZone(sa)
240
+ switch sa := sa.(type) {
241
+ case *syscall.SockaddrInet4:
242
+ return &net.UDPAddr{IP: ip, Port: sa.Port}
243
+ case *syscall.SockaddrInet6:
244
+ return &net.UDPAddr{IP: ip, Port: sa.Port, Zone: zone}
245
+ }
246
+ return nil
247
+}
248
+
249
+// from: go/src/pkg/net/unixsock_posix.go
250
+
251
+// SockaddrToUnixAddr converts a syscall.Sockaddr to a net.UnixAddr
252
+// Returns nil if conversion fails.
253
+func SockaddrToUnixAddr(sa syscall.Sockaddr) *net.UnixAddr {
254
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
255
+ return &net.UnixAddr{Name: s.Name, Net: "unix"}
256
+ }
257
+ return nil
258
+}
259
+
260
+// SockaddrToUnixgramAddr converts a syscall.Sockaddr to a net.UnixAddr
261
+// Returns nil if conversion fails.
262
+func SockaddrToUnixgramAddr(sa syscall.Sockaddr) *net.UnixAddr {
263
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
264
+ return &net.UnixAddr{Name: s.Name, Net: "unixgram"}
265
+ }
266
+ return nil
267
+}
268
+
269
+// SockaddrToUnixpacketAddr converts a syscall.Sockaddr to a net.UnixAddr
270
+// Returns nil if conversion fails.
271
+func SockaddrToUnixpacketAddr(sa syscall.Sockaddr) *net.UnixAddr {
272
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
273
+ return &net.UnixAddr{Name: s.Name, Net: "unixpacket"}
274
+ }
275
+ return nil
276
+}
277
+
278
+// from: go/src/pkg/net/ipsock.go
279
+
280
+// IP6ZoneToString converts an IP6 Zone syscall int to a net string
281
+// returns "" if zone is 0
282
+func IP6ZoneToString(zone int) string {
283
+ if zone == 0 {
284
+ return ""
285
+ }
286
+ if ifi, err := net.InterfaceByIndex(zone); err == nil {
287
+ return ifi.Name
288
+ }
289
+ return itod(uint(zone))
290
+}
291
+
292
+// IP6ZoneToInt converts an IP6 Zone net string to a syscall int
293
+// returns 0 if zone is ""
294
+func IP6ZoneToInt(zone string) int {
295
+ if zone == "" {
296
+ return 0
297
+ }
298
+ if ifi, err := net.InterfaceByName(zone); err == nil {
299
+ return ifi.Index
300
+ }
301
+ n, _, _ := dtoi(zone, 0)
302
+ return n
303
+}
304
+
305
+// from: go/src/pkg/net/parse.go
306
+
307
+// Convert i to decimal string.
308
+func itod(i uint) string {
309
+ if i == 0 {
310
+ return "0"
311
+ }
312
+
313
+ // Assemble decimal in reverse order.
314
+ var b [32]byte
315
+ bp := len(b)
316
+ for ; i > 0; i /= 10 {
317
+ bp--
318
+ b[bp] = byte(i%10) + '0'
319
+ }
320
+
321
+ return string(b[bp:])
322
+}
323
+
324
+// Bigger than we need, not too big to worry about overflow
325
+const big = 0xFFFFFF
326
+
327
+// Decimal to integer starting at &s[i0].
328
+// Returns number, new offset, success.
329
+func dtoi(s string, i0 int) (n int, i int, ok bool) {
330
+ n = 0
331
+ for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
332
+ n = n*10 + int(s[i]-'0')
333
+ if n >= big {
334
+ return 0, i, false
335
+ }
336
+ }
337
+ if i == i0 {
338
+ return 0, i, false
339
+ }
340
+ return n, i, true
341
+}
Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_bsd.go
new
+24
@@ -0,0 +1,24 @@
1
+// +build darwin dragonfly freebsd netbsd openbsd
2
+
3
+package sockaddrnet
4
+
5
+import (
6
+ "syscall"
7
+)
8
+
9
+const (
10
+ AF_INET = syscall.AF_INET
11
+ AF_INET6 = syscall.AF_INET6
12
+ AF_UNIX = syscall.AF_UNIX
13
+ AF_UNSPEC = syscall.AF_UNSPEC
14
+
15
+ IPPROTO_IP = syscall.IPPROTO_IP
16
+ IPPROTO_IPV4 = syscall.IPPROTO_IPV4
17
+ IPPROTO_IPV6 = syscall.IPPROTO_IPV6
18
+ IPPROTO_TCP = syscall.IPPROTO_TCP
19
+ IPPROTO_UDP = syscall.IPPROTO_UDP
20
+
21
+ SOCK_DGRAM = syscall.SOCK_DGRAM
22
+ SOCK_STREAM = syscall.SOCK_STREAM
23
+ SOCK_SEQPACKET = syscall.SOCK_SEQPACKET
24
+)
Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_linux.go
new
+22
@@ -0,0 +1,22 @@
1
+package sockaddrnet
2
+
3
+import (
4
+ "syscall"
5
+)
6
+
7
+const (
8
+ AF_INET = syscall.AF_INET
9
+ AF_INET6 = syscall.AF_INET6
10
+ AF_UNIX = syscall.AF_UNIX
11
+ AF_UNSPEC = syscall.AF_UNSPEC
12
+
13
+ IPPROTO_IP = syscall.IPPROTO_IP
14
+ IPPROTO_IPV4 = syscall.IPPROTO_IPIP
15
+ IPPROTO_IPV6 = syscall.IPPROTO_IPV6
16
+ IPPROTO_TCP = syscall.IPPROTO_TCP
17
+ IPPROTO_UDP = syscall.IPPROTO_UDP
18
+
19
+ SOCK_DGRAM = syscall.SOCK_DGRAM
20
+ SOCK_STREAM = syscall.SOCK_STREAM
21
+ SOCK_SEQPACKET = syscall.SOCK_SEQPACKET
22
+)
Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_windows.go
new
+22
@@ -0,0 +1,22 @@
1
+package sockaddrnet
2
+
3
+import (
4
+ "syscall"
5
+)
6
+
7
+const (
8
+ AF_INET = syscall.AF_INET
9
+ AF_INET6 = syscall.AF_INET6
10
+ AF_UNIX = syscall.AF_UNIX
11
+ AF_UNSPEC = syscall.AF_UNSPEC
12
+
13
+ IPPROTO_IP = syscall.IPPROTO_IP
14
+ IPPROTO_IPV4 = syscall.IPPROTO_IPV4
15
+ IPPROTO_IPV6 = syscall.IPPROTO_IPV6
16
+ IPPROTO_TCP = syscall.IPPROTO_TCP
17
+ IPPROTO_UDP = syscall.IPPROTO_UDP
18
+
19
+ SOCK_DGRAM = syscall.SOCK_DGRAM
20
+ SOCK_STREAM = syscall.SOCK_STREAM
21
+ SOCK_SEQPACKET = syscall.SOCK_SEQPACKET
22
+)