-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
1,585 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
language: go | ||
|
||
go: | ||
- 1.3 | ||
- 1.4 | ||
- release | ||
- tip | ||
|
||
script: | ||
- go test -race -cpu=5 -v ./... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
Copyright (c) 2013 Conformal Systems LLC. | ||
|
||
Permission to use, copy, modify, and distribute this software for any | ||
purpose with or without fee is hereby granted, provided that the above | ||
copyright notice and this permission notice appear in all copies. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# go-reuseport | ||
|
||
[![travisbadge](https://travis-ci.org/jbenet/go-reuseport.svg)](https://travis-ci.org/jbenet/go-reuseport) | ||
|
||
This package enables listening and dialing from _the same_ TCP or UDP port. | ||
This means that the following sockopts are set: | ||
|
||
``` | ||
SO_REUSEADDR | ||
SO_REUSEPORT | ||
``` | ||
|
||
- godoc: https://godoc.org/github.com/jbenet/go-reuseport | ||
|
||
This is a simple package to get around the problem of reusing addresses. | ||
The go `net` package (to my knowledge) does not allow setting socket options. | ||
This is particularly problematic when attempting to do TCP NAT holepunching, | ||
which requires a process to both Listen and Dial on the same TCP port. | ||
This package makes this possible for me. It is a pretty narrow use case, but | ||
perhaps this package can grow to be more general over time. | ||
|
||
## Examples | ||
|
||
|
||
```Go | ||
// listen on the same port. oh yeah. | ||
l1, _ := reuse.Listen("tcp", "127.0.0.1:1234") | ||
l2, _ := reuse.Listen("tcp", "127.0.0.1:1234") | ||
``` | ||
|
||
```Go | ||
// dial from the same port. oh yeah. | ||
l1, _ := reuse.Listen("tcp", "127.0.0.1:1234") | ||
l2, _ := reuse.Listen("tcp", "127.0.0.1:1235") | ||
c, _ := reuse.Dial("tcp", "127.0.0.1:1234", "127.0.0.1:1235") | ||
``` | ||
|
||
**Note: cant dial self because tcp/ip stacks use 4-tuples to identify connections, and doing so would clash.** | ||
|
||
## Tested | ||
|
||
Tested on `darwin` and `linux`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package reuseport | ||
|
||
import ( | ||
"net" | ||
) | ||
|
||
func ResolveAddr(network, address string) (net.Addr, error) { | ||
switch network { | ||
default: | ||
return nil, net.UnknownNetworkError(network) | ||
case "ip", "ip4", "ip6": | ||
return net.ResolveIPAddr(network, address) | ||
case "tcp", "tcp4", "tcp6": | ||
return net.ResolveTCPAddr(network, address) | ||
case "udp", "udp4", "udp6": | ||
return net.ResolveUDPAddr(network, address) | ||
case "unix", "unixgram", "unixpacket": | ||
return net.ResolveUnixAddr(network, address) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// +build darwin freebsd dragonfly netbsd openbsd linux | ||
|
||
package reuseport | ||
|
||
import ( | ||
"sync" | ||
"sync/atomic" | ||
"syscall" | ||
"time" | ||
) | ||
|
||
// checker is a struct to gather the availability check fields + funcs. | ||
// we use atomic ints because this is potentially a really hot function call. | ||
type checkerT struct { | ||
avail int32 // atomic int managed by set/isAvailable() | ||
check int32 // atomic int managed by has/checked() | ||
mu sync.Mutex // synchonizes the actual check | ||
} | ||
|
||
// the static location of the vars. | ||
var checker checkerT | ||
|
||
func (c *checkerT) isAvailable() bool { | ||
return atomic.LoadInt32(&c.avail) != 0 | ||
} | ||
|
||
func (c *checkerT) setIsAvailable(b bool) { | ||
if b { | ||
atomic.StoreInt32(&c.avail, 1) | ||
} else { | ||
atomic.StoreInt32(&c.avail, 0) | ||
} | ||
} | ||
|
||
func (c *checkerT) hasChecked() bool { | ||
return atomic.LoadInt32(&c.check) != 0 | ||
} | ||
|
||
func (c *checkerT) setHasChecked(b bool) { | ||
if b { | ||
atomic.StoreInt32(&c.check, 1) | ||
} else { | ||
atomic.StoreInt32(&c.check, 0) | ||
} | ||
} | ||
|
||
// Available returns whether or not SO_REUSEPORT is available in the OS. | ||
// It does so by attepting to open a tcp listener, setting the option, and | ||
// checking ENOPROTOOPT on error. After checking, the decision is cached | ||
// for the rest of the process run. | ||
func available() bool { | ||
if checker.hasChecked() { | ||
return checker.isAvailable() | ||
} | ||
|
||
// synchronize, only one should check | ||
checker.mu.Lock() | ||
defer checker.mu.Unlock() | ||
|
||
// we blocked. someone may have been gotten this. | ||
if checker.hasChecked() { | ||
return checker.isAvailable() | ||
} | ||
|
||
// there may be fluke reasons to fail to add a listener. | ||
// so we give it 5 shots. if not, give up and call it not avail. | ||
for i := 0; i < 5; i++ { | ||
// try to listen at tcp port 0. | ||
l, err := listenStream("tcp", "127.0.0.1:0") | ||
if err == nil { | ||
// no error? available. | ||
checker.setIsAvailable(true) | ||
checker.setHasChecked(true) | ||
l.Close() // Go back to the Shadow! | ||
return true | ||
} | ||
|
||
if errno, ok := err.(syscall.Errno); ok { | ||
if errno == syscall.ENOPROTOOPT { | ||
break // :( that's all folks. | ||
} | ||
} | ||
|
||
// not an errno? or not ENOPROTOOPT? retry. | ||
<-time.After(20 * time.Millisecond) // wait a bit | ||
} | ||
|
||
checker.setIsAvailable(false) | ||
checker.setHasChecked(true) | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// +build darwin freebsd dragonfly netbsd openbsd | ||
|
||
package reuseport | ||
|
||
import ( | ||
"syscall" | ||
) | ||
|
||
var soReusePort = syscall.SO_REUSEPORT | ||
var soReuseAddr = syscall.SO_REUSEADDR |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// +build linux | ||
|
||
package reuseport | ||
|
||
import ( | ||
"syscall" | ||
) | ||
|
||
var soReusePort = 15 // this is not defined in unix go pkg. | ||
var soReuseAddr = syscall.SO_REUSEADDR |
Oops, something went wrong.