@cryptotaxi247 / kubo / commits / 911a3c90b

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 +![travisbadge](https://travis-ci.org/jbenet/go-reuseport.svg)
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 +)