Skip to content
This repository has been archived by the owner on May 26, 2022. It is now read-only.

Commit

Permalink
use a single handle for each reuse
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-seemann committed Aug 5, 2019
1 parent e13a88e commit 074b517
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 13 deletions.
28 changes: 21 additions & 7 deletions reuse.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,37 @@ func (c *reuseConn) GetCount() int { return int(atomic.LoadInt32(&c.refCount))
type reuse struct {
mutex sync.Mutex

handle *netlink.Handle // Only set on Linux. nil on other systems.

unicast map[string] /* IP.String() */ map[int] /* port */ *reuseConn
// global contains connections that are listening on 0.0.0.0 / ::
global map[int]*reuseConn
}

func newReuse() *reuse {
func newReuse() (*reuse, error) {
// On non-Linux systems, this will return ErrNotImplemented.
handle, err := netlink.NewHandle()
if err == netlink.ErrNotImplemented {
handle = nil
} else if err != nil {
return nil, err
}
return &reuse{
unicast: make(map[string]map[int]*reuseConn),
global: make(map[int]*reuseConn),
}
handle: handle,
}, nil
}

// Get the source IP that the kernel would use for dialing.
// This only works on Linux.
// On other systems, this returns an empty slice of IP addresses.
func (r *reuse) getSourceIPs(network string, raddr *net.UDPAddr) ([]net.IP, error) {
// Determine the source address that the kernel would use for this IP address.
// Note: This only works on Linux.
// On other OSes, this will return a netlink.ErrNotImplemetned.
routes, err := (&netlink.Handle{}).RouteGet(raddr.IP)
if r.handle == nil {
return nil, nil
}

routes, err := r.handle.RouteGet(raddr.IP)
if err != nil {
return nil, err
}
Expand All @@ -63,7 +77,7 @@ func (r *reuse) Dial(network string, raddr *net.UDPAddr) (*reuseConn, error) {

func (r *reuse) dial(network string, raddr *net.UDPAddr) (*reuseConn, error) {
ips, err := r.getSourceIPs(network, raddr)
if err != nil && err != netlink.ErrNotImplemented {
if err != nil {
return nil, err
}

Expand Down
4 changes: 3 additions & 1 deletion reuse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ var _ = Describe("Reuse", func() {
var reuse *reuse

BeforeEach(func() {
reuse = newReuse()
var err error
reuse, err = newReuse()
Expect(err).ToNot(HaveOccurred())
})

It("creates a new global connection when listening on 0.0.0.0", func() {
Expand Down
22 changes: 17 additions & 5 deletions transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,19 @@ type connManager struct {
reuseUDP6 *reuse
}

func newConnManager() *connManager {
return &connManager{
reuseUDP4: newReuse(),
reuseUDP6: newReuse(),
func newConnManager() (*connManager, error) {
reuseUDP4, err := newReuse()
if err != nil {
return nil, err
}
reuseUDP6, err := newReuse()
if err != nil {
return nil, err
}
return &connManager{
reuseUDP4: reuseUDP4,
reuseUDP6: reuseUDP6,
}, nil
}

func (c *connManager) getReuse(network string) (*reuse, error) {
Expand Down Expand Up @@ -87,12 +95,16 @@ func NewTransport(key ic.PrivKey) (tpt.Transport, error) {
if err != nil {
return nil, err
}
connManager, err := newConnManager()
if err != nil {
return nil, err
}

return &transport{
privKey: key,
localPeer: localPeer,
identity: identity,
connManager: newConnManager(),
connManager: connManager,
}, nil
}

Expand Down

0 comments on commit 074b517

Please sign in to comment.