Repository: scionproto/scion
Pull request #3441 (2019-11-29 15:42:18)

Reliable socket dials/registrations use context.Context
Fixes https://github.com/scionproto/scion/issues/3402.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/scionproto/scion/3441)
<!-- Reviewable:end -->



Patch:
diff --git a/go/beacon_srv/main.go b/go/beacon_srv/main.go
index c13b16a9e..2d2ec7c0e 100644
--- a/go/beacon_srv/main.go
+++ b/go/beacon_srv/main.go
@@ -183,7 +183,7 @@ func realMain() int {
 		defer log.LogPanicAndExit()
 		msgr.ListenAndServe()
 	}()
-	dispatcherService := reliable.NewDispatcherService("")
+	dispatcherService := reliable.NewDispatcher("")
 	if cfg.General.ReconnectToDispatcher {
 		dispatcherService = reconnect.NewDispatcherService(dispatcherService)
 	}
@@ -210,7 +210,7 @@ func realMain() int {
 		addressRewriter: nc.AddressRewriter(
 			&onehop.OHPPacketDispatcherService{
 				PacketDispatcherService: &snet.DefaultPacketDispatcherService{
-					Dispatcher: reliable.NewDispatcherService(""),
+					Dispatcher: reliable.NewDispatcher(""),
 				},
 			},
 		),
diff --git a/go/border/rctrl/ctrl.go b/go/border/rctrl/ctrl.go
index 84ea47a85..e1c49d3fe 100644
--- a/go/border/rctrl/ctrl.go
+++ b/go/border/rctrl/ctrl.go
@@ -47,7 +47,7 @@ func Control(sRevInfoQ chan rpkt.RawSRevCallbackArgs, dispatcherReconnect bool)
 	logger = log.New("Part", "Control")
 	ctx := rctx.Get()
 	ia = ctx.Conf.IA
-	dispatcherService := reliable.NewDispatcherService("")
+	dispatcherService := reliable.NewDispatcher("")
 	if dispatcherReconnect {
 		dispatcherService = reconnect.NewDispatcherService(dispatcherService)
 	}
diff --git a/go/examples/pingpong/pingpong.go b/go/examples/pingpong/pingpong.go
index 9a85d81dd..e158aefbc 100644
--- a/go/examples/pingpong/pingpong.go
+++ b/go/examples/pingpong/pingpong.go
@@ -224,7 +224,7 @@ func (c *client) run() {
 	c.setupPath()
 	defer c.Close()
 
-	ds := reliable.NewDispatcherService(*dispatcher)
+	ds := reliable.NewDispatcher(*dispatcher)
 	sciondConn, err := sd.NewService(*sciond).Connect(context.Background())
 	if err != nil {
 		LogFatal("Unable to initialize SCION network", "err", err)
@@ -347,7 +347,7 @@ type server struct {
 // run listens on a SCION address and replies to any ping message.
 // On any error, the server exits.
 func (s server) run() {
-	ds := reliable.NewDispatcherService(*dispatcher)
+	ds := reliable.NewDispatcher(*dispatcher)
 	sciondConn, err := sd.NewService(*sciond).Connect(context.Background())
 	if err != nil {
 		LogFatal("Unable to initialize SCION network", "err", err)
diff --git a/go/integration/common.go b/go/integration/common.go
index 827bc1708..4793e6b92 100644
--- a/go/integration/common.go
+++ b/go/integration/common.go
@@ -74,7 +74,7 @@ func validateFlags() {
 }
 
 func InitNetwork() *snet.SCIONNetwork {
-	ds := reliable.NewDispatcherService("")
+	ds := reliable.NewDispatcher("")
 	sciondConn, err := sciond.NewService(sdSocket).Connect(context.Background())
 	if err != nil {
 		LogFatal("Unable to initialize SCION network", "err", err)
diff --git a/go/integration/end2end/main.go b/go/integration/end2end/main.go
index a6eca0a4e..4d595eff0 100644
--- a/go/integration/end2end/main.go
+++ b/go/integration/end2end/main.go
@@ -90,7 +90,7 @@ type server struct {
 
 func (s server) run() {
 	connFactory := &snet.DefaultPacketDispatcherService{
-		Dispatcher: reliable.NewDispatcherService(""),
+		Dispatcher: reliable.NewDispatcher(""),
 		SCMPHandler: snet.NewSCMPHandler(
 			sciond.RevHandler{Connector: integration.SDConn()},
 		),
@@ -145,7 +145,7 @@ type client struct {
 
 func (c client) run() int {
 	connFactory := &snet.DefaultPacketDispatcherService{
-		Dispatcher: reliable.NewDispatcherService(""),
+		Dispatcher: reliable.NewDispatcher(""),
 		SCMPHandler: snet.NewSCMPHandler(
 			sciond.RevHandler{Connector: integration.SDConn()},
 		),
diff --git a/go/lib/infra/infraenv/infraenv.go b/go/lib/infra/infraenv/infraenv.go
index a7b74316f..b4bf306a2 100644
--- a/go/lib/infra/infraenv/infraenv.go
+++ b/go/lib/infra/infraenv/infraenv.go
@@ -140,7 +140,7 @@ func (nc *NetworkConfig) AddressRewriter(
 	}
 	if connFactory == nil {
 		connFactory = &snet.DefaultPacketDispatcherService{
-			Dispatcher: reliable.NewDispatcherService(""),
+			Dispatcher: reliable.NewDispatcher(""),
 		}
 	}
 
@@ -186,7 +186,7 @@ func (nc *NetworkConfig) initUDPSocket(quicAddress string) (net.PacketConn, erro
 		return nil, common.NewBasicError("Unable to build SVC resolution reply", err)
 	}
 
-	dispatcherService := reliable.NewDispatcherService("")
+	dispatcherService := reliable.NewDispatcher("")
 	if nc.ReconnectToDispatcher {
 		dispatcherService = reconnect.NewDispatcherService(dispatcherService)
 	}
@@ -215,7 +215,7 @@ func (nc *NetworkConfig) initUDPSocket(quicAddress string) (net.PacketConn, erro
 }
 
 func (nc *NetworkConfig) initQUICSocket() (net.PacketConn, error) {
-	dispatcherService := reliable.NewDispatcherService("")
+	dispatcherService := reliable.NewDispatcher("")
 	if nc.ReconnectToDispatcher {
 		dispatcherService = reconnect.NewDispatcherService(dispatcherService)
 	}
diff --git a/go/lib/sciond/pathprobe/paths.go b/go/lib/sciond/pathprobe/paths.go
index b1780d7fd..10186b9a8 100644
--- a/go/lib/sciond/pathprobe/paths.go
+++ b/go/lib/sciond/pathprobe/paths.go
@@ -113,7 +113,7 @@ func (p Prober) GetStatuses(ctx context.Context,
 	scmpH := &scmpHandler{statuses: pathStatuses}
 	network := snet.NewCustomNetworkWithPR(p.Local.IA,
 		&snet.DefaultPacketDispatcherService{
-			Dispatcher:  reliable.NewDispatcherService(p.DispPath),
+			Dispatcher:  reliable.NewDispatcher(p.DispPath),
 			SCMPHandler: scmpH,
 		},
 	)
diff --git a/go/lib/sciond/sciond.go b/go/lib/sciond/sciond.go
index 2af629f41..b80b0586f 100644
--- a/go/lib/sciond/sciond.go
+++ b/go/lib/sciond/sciond.go
@@ -30,7 +30,6 @@ package sciond
 import (
 	"context"
 	"fmt"
-	"time"
 
 	"github.com/scionproto/scion/go/lib/addr"
 	"github.com/scionproto/scion/go/lib/common"
@@ -131,14 +130,6 @@ func (c *conn) checkForSciond(ctx context.Context) error {
 // used for its request-response matching capabilities (because a single RPC is happening on each
 // underlying connection), but rather for its context-aware API.
 func (c *conn) ctxAwareConnect(ctx context.Context) (*disp.Dispatcher, error) {
-	var timeout time.Duration
-	if deadline, ok := ctx.Deadline(); ok {
-		timeout = deadline.Sub(time.Now())
-		if timeout < 0 {
-			timeout = 0
-		}
-	}
-
 	type returnValue struct {
 		dispatcher *disp.Dispatcher
 		err        error
@@ -146,7 +137,7 @@ func (c *conn) ctxAwareConnect(ctx context.Context) (*disp.Dispatcher, error) {
 	barrier := make(chan returnValue, 1)
 	go func() {
 		defer log.LogPanicAndExit()
-		dispatcher, err := connectTimeout(c.path, timeout)
+		dispatcher, err := dial(ctx, c.path)
 		barrier <- returnValue{dispatcher: dispatcher, err: err}
 	}()
 
@@ -311,8 +302,8 @@ func (c *conn) Close(_ context.Context) error {
 	return nil
 }
 
-func connectTimeout(socketName string, timeout time.Duration) (*disp.Dispatcher, error) {
-	rConn, err := reliable.DialTimeout(socketName, timeout)
+func dial(ctx context.Context, socketName string) (*disp.Dispatcher, error) {
+	rConn, err := reliable.Dial(ctx, socketName)
 	if err != nil {
 		return nil, err
 	}
diff --git a/go/lib/snet/dispatcher.go b/go/lib/snet/dispatcher.go
index 3a4c45bc5..570d4c1ad 100644
--- a/go/lib/snet/dispatcher.go
+++ b/go/lib/snet/dispatcher.go
@@ -41,7 +41,7 @@ var _ PacketDispatcherService = (*DefaultPacketDispatcherService)(nil)
 // sent to the dispatcher.
 type DefaultPacketDispatcherService struct {
 	// Dispatcher is used to get packets from the local SCION Dispatcher process.
-	Dispatcher reliable.DispatcherService
+	Dispatcher reliable.Dispatcher
 	// SCMPHandler is invoked for packets that contain an SCMP L4. If the
 	// handler is nil, errors are returned back to applications every time an
 	// SCMP message is received.
@@ -52,7 +52,14 @@ func (s *DefaultPacketDispatcherService) RegisterTimeout(ia addr.IA, public *add
 	bind *net.UDPAddr, svc addr.HostSVC,
 	timeout time.Duration) (PacketConn, uint16, error) {
 
-	rconn, port, err := s.Dispatcher.RegisterTimeout(ia, public, bind, svc, timeout)
+	ctx := context.Background()
+	if timeout != 0 {
+		var cancelF context.CancelFunc
+		ctx, cancelF = context.WithTimeout(ctx, timeout)
+		defer cancelF()
+	}
+
+	rconn, port, err := s.Dispatcher.Register(ctx, ia, public, svc)
 	if err != nil {
 		return nil, 0, err
 	}
diff --git a/go/lib/snet/snet.go b/go/lib/snet/snet.go
index 4cc730052..1336e403b 100644
--- a/go/lib/snet/snet.go
+++ b/go/lib/snet/snet.go
@@ -70,7 +70,7 @@ type SCIONNetwork struct {
 
 // NewNetworkWithPR creates a new networking context with path resolver pr. A
 // nil path resolver means the Network will run without SCIOND.
-func NewNetworkWithPR(ia addr.IA, dispatcher reliable.DispatcherService,
+func NewNetworkWithPR(ia addr.IA, dispatcher reliable.Dispatcher,
 	querier PathQuerier, revHandler RevocationHandler) *SCIONNetwork {
 
 	return &SCIONNetwork{
diff --git a/go/lib/sock/reliable/BUILD.bazel b/go/lib/sock/reliable/BUILD.bazel
index 057b59149..edd53aea2 100644
--- a/go/lib/sock/reliable/BUILD.bazel
+++ b/go/lib/sock/reliable/BUILD.bazel
@@ -15,6 +15,7 @@ go_library(
     deps = [
         "//go/lib/addr:go_default_library",
         "//go/lib/common:go_default_library",
+        "//go/lib/log:go_default_library",
         "//go/lib/prom:go_default_library",
         "//go/lib/serrors:go_default_library",
         "//go/lib/sock/reliable/internal/metrics:go_default_library",
diff --git a/go/lib/sock/reliable/mock_reliable/reliable.go b/go/lib/sock/reliable/mock_reliable/reliable.go
index a8813c3c4..af36c76bd 100644
--- a/go/lib/sock/reliable/mock_reliable/reliable.go
+++ b/go/lib/sock/reliable/mock_reliable/reliable.go
@@ -1,42 +1,42 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/scionproto/scion/go/lib/sock/reliable (interfaces: DispatcherService)
+// Source: github.com/scionproto/scion/go/lib/sock/reliable (interfaces: Dispatcher)
 
 // Package mock_reliable is a generated GoMock package.
 package mock_reliable
 
 import (
+	context "context"
 	gomock "github.com/golang/mock/gomock"
 	addr "github.com/scionproto/scion/go/lib/addr"
 	net "net"
 	reflect "reflect"
-	time "time"
 )
 
-// MockDispatcherService is a mock of DispatcherService interface
-type MockDispatcherService struct {
+// MockDispatcher is a mock of Dispatcher interface
+type MockDispatcher struct {
 	ctrl     *gomock.Controller
-	recorder *MockDispatcherServiceMockRecorder
+	recorder *MockDispatcherMockRecorder
 }
 
-// MockDispatcherServiceMockRecorder is the mock recorder for MockDispatcherService
-type MockDispatcherServiceMockRecorder struct {
-	mock *MockDispatcherService
+// MockDispatcherMockRecorder is the mock recorder for MockDispatcher
+type MockDispatcherMockRecorder struct {
+	mock *MockDispatcher
 }
 
-// NewMockDispatcherService creates a new mock instance
-func NewMockDispatcherService(ctrl *gomock.Controller) *MockDispatcherService {
-	mock := &MockDispatcherService{ctrl: ctrl}
-	mock.recorder = &MockDispatcherServiceMockRecorder{mock}
+// NewMockDispatcher creates a new mock instance
+func NewMockDispatcher(ctrl *gomock.Controller) *MockDispatcher {
+	mock := &MockDispatcher{ctrl: ctrl}
+	mock.recorder = &MockDispatcherMockRecorder{mock}
 	return mock
 }
 
 // EXPECT returns an object that allows the caller to indicate expected use
-func (m *MockDispatcherService) EXPECT() *MockDispatcherServiceMockRecorder {
+func (m *MockDispatcher) EXPECT() *MockDispatcherMockRecorder {
 	return m.recorder
 }
 
 // Register mocks base method
-func (m *MockDispatcherService) Register(arg0 addr.IA, arg1 *addr.AppAddr, arg2 *net.UDPAddr, arg3 addr.HostSVC) (net.PacketConn, uint16, error) {
+func (m *MockDispatcher) Register(arg0 context.Context, arg1 addr.IA, arg2 *addr.AppAddr, arg3 addr.HostSVC) (net.PacketConn, uint16, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Register", arg0, arg1, arg2, arg3)
 	ret0, _ := ret[0].(net.PacketConn)
@@ -46,23 +46,7 @@ func (m *MockDispatcherService) Register(arg0 addr.IA, arg1 *addr.AppAddr, arg2
 }
 
 // Register indicates an expected call of Register
-func (mr *MockDispatcherServiceMockRecorder) Register(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
+func (mr *MockDispatcherMockRecorder) Register(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Register", reflect.TypeOf((*MockDispatcherService)(nil).Register), arg0, arg1, arg2, arg3)
-}
-
-// RegisterTimeout mocks base method
-func (m *MockDispatcherService) RegisterTimeout(arg0 addr.IA, arg1 *addr.AppAddr, arg2 *net.UDPAddr, arg3 addr.HostSVC, arg4 time.Duration) (net.PacketConn, uint16, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "RegisterTimeout", arg0, arg1, arg2, arg3, arg4)
-	ret0, _ := ret[0].(net.PacketConn)
-	ret1, _ := ret[1].(uint16)
-	ret2, _ := ret[2].(error)
-	return ret0, ret1, ret2
-}
-
-// RegisterTimeout indicates an expected call of RegisterTimeout
-func (mr *MockDispatcherServiceMockRecorder) RegisterTimeout(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterTimeout", reflect.TypeOf((*MockDispatcherService)(nil).RegisterTimeout), arg0, arg1, arg2, arg3, arg4)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Register", reflect.TypeOf((*MockDispatcher)(nil).Register), arg0, arg1, arg2, arg3)
 }
diff --git a/go/lib/sock/reliable/reconnect/conn.go b/go/lib/sock/reliable/reconnect/conn.go
index 485470d22..3ff25b2a9 100644
--- a/go/lib/sock/reliable/reconnect/conn.go
+++ b/go/lib/sock/reliable/reconnect/conn.go
@@ -15,6 +15,7 @@
 package reconnect
 
 import (
+	"context"
 	"net"
 	"sync"
 	"time"
@@ -160,7 +161,7 @@ func (conn *PacketConn) asyncReconnectWrapper() {
 // Reconnect is only used internally and should never be called from outside
 // the package.
 func (conn *PacketConn) Reconnect() (net.PacketConn, error) {
-	newConn, _, err := conn.reconnecter.Reconnect(0)
+	newConn, _, err := conn.reconnecter.Reconnect(context.Background())
 	if err != nil {
 		return nil, err
 	}
diff --git a/go/lib/sock/reliable/reconnect/mock_reconnect/reconnect.go b/go/lib/sock/reliable/reconnect/mock_reconnect/reconnect.go
index d73faa823..bd85c3d92 100644
--- a/go/lib/sock/reliable/reconnect/mock_reconnect/reconnect.go
+++ b/go/lib/sock/reliable/reconnect/mock_reconnect/reconnect.go
@@ -5,10 +5,10 @@
 package mock_reconnect
 
 import (
+	context "context"
 	gomock "github.com/golang/mock/gomock"
 	net "net"
 	reflect "reflect"
-	time "time"
 )
 
 // MockIOOperation is a mock of IOOperation interface
@@ -86,7 +86,7 @@ func (m *MockReconnecter) EXPECT() *MockReconnecterMockRecorder {
 }
 
 // Reconnect mocks base method
-func (m *MockReconnecter) Reconnect(arg0 time.Duration) (net.PacketConn, uint16, error) {
+func (m *MockReconnecter) Reconnect(arg0 context.Context) (net.PacketConn, uint16, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Reconnect", arg0)
 	ret0, _ := ret[0].(net.PacketConn)
diff --git a/go/lib/sock/reliable/reconnect/network.go b/go/lib/sock/reliable/reconnect/network.go
index 29a93186a..a8f37bee9 100644
--- a/go/lib/sock/reliable/reconnect/network.go
+++ b/go/lib/sock/reliable/reconnect/network.go
@@ -15,6 +15,7 @@
 package reconnect
 
 import (
+	"context"
 	"net"
 	"time"
 
@@ -34,30 +35,29 @@ import (
 // validating the new connection themselves should use the connection
 // constructors directly.
 type DispatcherService struct {
-	dispatcher reliable.DispatcherService
+	dispatcher reliable.Dispatcher
 }
 
 // NewDispatcherService adds transparent reconnection capabilities
 // to dispatcher connections.
-func NewDispatcherService(dispatcher reliable.DispatcherService) *DispatcherService {
+func NewDispatcherService(dispatcher reliable.Dispatcher) *DispatcherService {
 	return &DispatcherService{dispatcher: dispatcher}
 }
 
-func (pn *DispatcherService) Register(ia addr.IA, public *addr.AppAddr,
-	bind *net.UDPAddr, svc addr.HostSVC) (net.PacketConn, uint16, error) {
+func (pn *DispatcherService) Register(ctx context.Context, ia addr.IA, public *addr.AppAddr,
+	svc addr.HostSVC) (net.PacketConn, uint16, error) {
 
-	return pn.RegisterTimeout(ia, public, bind, svc, 0)
+	return pn.RegisterTimeout(ctx, ia, public, svc)
 }
 
-func (pn *DispatcherService) RegisterTimeout(ia addr.IA, public *addr.AppAddr,
-	bind *net.UDPAddr, svc addr.HostSVC,
-	timeout time.Duration) (net.PacketConn, uint16, error) {
+func (pn *DispatcherService) RegisterTimeout(ctx context.Context, ia addr.IA, public *addr.AppAddr,
+	svc addr.HostSVC) (net.PacketConn, uint16, error) {
 
 	// Perform initial connection to allocate port. We use a reconnecter here
 	// to set up the initial connection using the same retry logic we use when
 	// losing the connection to the dispatcher.
-	reconnecter := pn.newReconnecterFromListenArgs(ia, public, bind, svc, timeout)
-	conn, port, err := reconnecter.Reconnect(timeout)
+	reconnecter := pn.newReconnecterFromListenArgs(ctx, ia, public, svc)
+	conn, port, err := reconnecter.Reconnect(ctx)
 	if err != nil {
 		return nil, 0, err
 	}
@@ -66,18 +66,23 @@ func (pn *DispatcherService) RegisterTimeout(ia addr.IA, public *addr.AppAddr,
 		newPublic = public.Copy()
 		newPublic.L4 = port
 	}
-	reconnecter = pn.newReconnecterFromListenArgs(ia, newPublic, bind, svc, timeout)
+	reconnecter = pn.newReconnecterFromListenArgs(ctx, ia, newPublic, svc)
 	return NewPacketConn(conn, reconnecter), port, nil
 }
 
-func (pn *DispatcherService) newReconnecterFromListenArgs(ia addr.IA,
-	public *addr.AppAddr, bind *net.UDPAddr,
-	svc addr.HostSVC, timeout time.Duration) *TickingReconnecter {
+func (pn *DispatcherService) newReconnecterFromListenArgs(ctx context.Context, ia addr.IA,
+	public *addr.AppAddr, svc addr.HostSVC) *TickingReconnecter {
 
 	// f represents individual connection attempts
 	f := func(timeout time.Duration) (net.PacketConn, uint16, error) {
 		metrics.M.Retries().Inc()
-		conn, port, err := pn.dispatcher.RegisterTimeout(ia, public, bind, svc, timeout)
+		ctx := context.Background()
+		if timeout != 0 {
+			var cancelF context.CancelFunc
+			ctx, cancelF = context.WithTimeout(ctx, timeout)
+			defer cancelF()
+		}
+		conn, port, err := pn.dispatcher.Register(ctx, ia, public, svc)
 		if xerrors.Is(err, ErrReconnecterTimeoutExpired) {
 			metrics.M.Timeouts().Inc()
 		}
diff --git a/go/lib/sock/reliable/reconnect/reconnecter.go b/go/lib/sock/reliable/reconnect/reconnecter.go
index 4d414abcb..d1b4b2904 100644
--- a/go/lib/sock/reliable/reconnect/reconnecter.go
+++ b/go/lib/sock/reliable/reconnect/reconnecter.go
@@ -15,6 +15,7 @@
 package reconnect
 
 import (
+	"context"
 	"net"
 	"sync"
 	"time"
@@ -29,7 +30,7 @@ var (
 )
 
 type Reconnecter interface {
-	Reconnect(timeout time.Duration) (net.PacketConn, uint16, error)
+	Reconnect(ctx context.Context) (net.PacketConn, uint16, error)
 	Stop()
 }
 
@@ -62,13 +63,18 @@ func NewTickingReconnecter(
 // subject to timeout. Attempts that receive dispatcher connection errors are
 // followed by reattempts. Critical errors (e.g., port mismatches) return
 // immediately.
-func (r *TickingReconnecter) Reconnect(timeout time.Duration) (net.PacketConn, uint16, error) {
+func (r *TickingReconnecter) Reconnect(ctx context.Context) (net.PacketConn, uint16, error) {
 	r.mtx.Lock()
 	defer r.mtx.Unlock()
 	start := time.Now()
 	t := time.NewTicker(DefaultTickerInterval)
 	defer t.Stop()
 
+	var timeout time.Duration
+	if deadline, ok := ctx.Deadline(); ok {
+		timeout = deadline.Sub(time.Now())
+	}
+
 	timeoutExpired := afterTimeout(timeout)
 	for r.stopping.IsFalse() {
 		newTimeout, ok := getNewTimeout(timeout, start)
diff --git a/go/lib/sock/reliable/reliable.go b/go/lib/sock/reliable/reliable.go
index 188abae50..b86dbd675 100644
--- a/go/lib/sock/reliable/reliable.go
+++ b/go/lib/sock/reliable/reliable.go
@@ -62,6 +62,7 @@
 package reliable
 
 import (
+	"context"
 	"fmt"
 	"net"
 	"sync"
@@ -69,6 +70,7 @@ import (
 
 	"github.com/scionproto/scion/go/lib/addr"
 	"github.com/scionproto/scion/go/lib/common"
+	"github.com/scionproto/scion/go/lib/log"
 	"github.com/scionproto/scion/go/lib/prom"
 	"github.com/scionproto/scion/go/lib/serrors"
 	"github.com/scionproto/scion/go/lib/sock/reliable/internal/metrics"
@@ -86,18 +88,18 @@ const (
 	DefaultDispSocketFileMode = 0770
 )
 
-// DispatcherService controls how SCION applications open sockets in the SCION world.
-type DispatcherService interface {
-	Register(ia addr.IA, public *addr.AppAddr, bind *net.UDPAddr,
+// Dispatcher controls how SCION applications open sockets in the SCION world.
+type Dispatcher interface {
+	// Register connects to a SCION Dispatcher's UNIX socket. Future messages for the address in AS
+	// ia which arrive at the dispatcher can be read by calling Read on the returned connection.
+	Register(ctx context.Context, ia addr.IA, address *addr.AppAddr,
 		svc addr.HostSVC) (net.PacketConn, uint16, error)
-	RegisterTimeout(ia addr.IA, public *addr.AppAddr, bind *net.UDPAddr,
-		svc addr.HostSVC, timeout time.Duration) (net.PacketConn, uint16, error)
 }
 
-// NewDispatcherService creates a new dispatcher API endpoint on top of a UNIX
+// NewDispatcher creates a new dispatcher API endpoint on top of a UNIX
 // STREAM reliable socket. If name is empty, the default dispatcher path is
 // chosen.
-func NewDispatcherService(name string) DispatcherService {
+func NewDispatcher(name string) Dispatcher {
 	if name == "" {
 		name = DefaultDispPath
 	}
@@ -108,17 +110,10 @@ type dispatcherService struct {
 	Address string
 }
 
-func (d *dispatcherService) Register(ia addr.IA, public *addr.AppAddr, bind *net.UDPAddr,
+func (d *dispatcherService) Register(ctx context.Context, ia addr.IA, public *addr.AppAddr,
 	svc addr.HostSVC) (net.PacketConn, uint16, error) {
 
-	return Register(d.Address, ia, public, bind, svc)
-}
-
-func (d *dispatcherService) RegisterTimeout(ia addr.IA, public *addr.AppAddr,
-	bind *net.UDPAddr, svc addr.HostSVC,
-	timeout time.Duration) (net.PacketConn, uint16, error) {
-
-	return RegisterTimeout(d.Address, ia, public, bind, svc, timeout)
+	return registerMetricsWrapper(ctx, d.Address, ia, public, svc)
 }
 
 var _ net.Conn = (*Conn)(nil)
@@ -149,56 +144,31 @@ func newConn(c net.Conn) *Conn {
 }
 
 // Dial connects to the UNIX socket specified by address.
-func Dial(address string) (*Conn, error) {
-	return DialTimeout(address, 0)
-}
-
-// DialTimeout acts like Dial but takes a timeout.
 //
-// A timeout of 0 means infinite timeout.
-//
-// To check for timeout errors, call serrors.IsTimeout on the error.
-func DialTimeout(address string, timeout time.Duration) (*Conn, error) {
-	conn, err := dialTimeout(address, timeout)
+// The provided context must be non-nil. If the context expires before the connection is complete,
+// an error is returned. Once successfully connected, any expiration of the context will not affect
+// the connection.
+func Dial(ctx context.Context, address string) (*Conn, error) {
+	dialer := net.Dialer{}
+	c, err := dialer.DialContext(ctx, "unix", address)
 	metrics.M.Dials(metrics.DialLabels{Result: labelResult(err)}).Inc()
-	return conn, err
-}
-
-func dialTimeout(address string, timeout time.Duration) (*Conn, error) {
-	var err error
-	var c net.Conn
-	c, err = net.DialTimeout("unix", address, timeout)
 	if err != nil {
 		return nil, err
 	}
 	return newConn(c), nil
 }
 
-// Register connects to a SCION Dispatcher's UNIX socket.
-// Future messages for address public or bind in AS ia which arrive at the dispatcher can be
-// read by calling Read on the returned Conn structure.
-func Register(dispatcher string, ia addr.IA, public *addr.AppAddr, bind *net.UDPAddr,
-	svc addr.HostSVC) (*Conn, uint16, error) {
+func registerMetricsWrapper(ctx context.Context, dispatcher string, ia addr.IA,
+	public *addr.AppAddr, svc addr.HostSVC) (*Conn, uint16, error) {
 
-	return RegisterTimeout(dispatcher, ia, public, bind, svc, time.Duration(0))
-}
-
-// RegisterTimeout acts like Register but takes a timeout.
-//
-// A timeout of 0 means infinite timeout.
-//
-// To check for timeout errors, call serrors.IsTimeout on the error.
-func RegisterTimeout(dispatcher string, ia addr.IA, public *addr.AppAddr,
-	bind *net.UDPAddr, svc addr.HostSVC, timeout time.Duration) (*Conn, uint16, error) {
-
-	conn, port, err := registerTimeout(dispatcher, ia, public, bind, svc, timeout)
+	conn, port, err := register(ctx, dispatcher, ia, public, svc)
 	labels := metrics.RegisterLabels{Result: labelResult(err), SVC: svc.BaseString()}
 	metrics.M.Registers(labels).Inc()
 	return conn, port, err
 }
 
-func registerTimeout(dispatcher string, ia addr.IA, public *addr.AppAddr,
-	bind *net.UDPAddr, svc addr.HostSVC, timeout time.Duration) (*Conn, uint16, error) {
+func register(ctx context.Context, dispatcher string, ia addr.IA, public *addr.AppAddr,
+	svc addr.HostSVC) (*Conn, uint16, error) {
 
 	publicUDP, err := createUDPAddrFromAppAddr(public)
 	if err != nil {
@@ -207,53 +177,84 @@ func registerTimeout(dispatcher string, ia addr.IA, public *addr.AppAddr,
 	reg := &Registration{
 		IA:            ia,
 		PublicAddress: publicUDP,
-		BindAddress:   bind,
 		SVCAddress:    svc,
 	}
 
-	// Compute deadline prior to Dial, because timeout is relative to current time.
-	deadline := time.Now().Add(timeout)
-	conn, err := dialTimeout(dispatcher, timeout)
+	conn, err := Dial(ctx, dispatcher)
 	if err != nil {
 		return nil, 0, err
 	}
-	// If a timeout was specified, make reads and writes return if deadline exceeded.
-	if timeout != 0 {
-		conn.SetDeadline(deadline)
+
+	type RegistrationReturn struct {
+		port int
+		err  error
+	}
+	resultChannel := make(chan RegistrationReturn)
+	go func() {
+		defer log.LogPanicAndExit()
+
+		// If a timeout was specified, make reads and writes return if deadline exceeded.
+		if deadline, ok := ctx.Deadline(); ok {
+			conn.SetDeadline(deadline)
+		}
+
+		port, err := registrationExchange(conn, reg)
+		resultChannel <- RegistrationReturn{port: port, err: err}
+	}()
+
+	select {
+	case registrationReturn := <-resultChannel:
+		if registrationReturn.err != nil {
+			conn.Close()
+			return nil, 0, registrationReturn.err
+		}
+		if publicUDP.Port != 0 && publicUDP.Port != int(registrationReturn.port) {
+			conn.Close()
+			return nil, 0, serrors.New("port mismatch", "requested", publicUDP.Port,
+				"received", registrationReturn.port)
+		}
+		// Disable deadline to not affect future I/O
+		conn.SetDeadline(time.Time{})
+		return conn, uint16(registrationReturn.port), nil
+	case <-ctx.Done():
+		// Unblock registration worker I/O
+		conn.Close()
+		// Wait for registration worker to finish before exiting. Worker should exit quickly
+		// because all pending I/O immediately times out.
+		<-resultChannel
+		// The returned values aren't needed, we already decided to error out when the connection
+		// was closed. Note that the registration might succeed in the short window of time between
+		// the context being marked as done (canceled) and the I/O getting informed of the new
+		// deadline.
+		return nil, 0, serrors.WrapStr("timed out during dispatcher registration", ctx.Err())
 	}
+}
 
+func registrationExchange(conn *Conn, reg *Registration) (int, error) {
 	b := make([]byte, 1500)
 	n, err := reg.SerializeTo(b)
 	if err != nil {
-		conn.Close()
-		return nil, 0, err
+		return 0, err
 	}
 	_, err = conn.WriteTo(b[:n], nil)
 	if err != nil {
-		conn.Close()
-		return nil, 0, err
+		return 0, err
 	}
 
 	n, _, err = conn.ReadFrom(b)
 	if err != nil {
 		conn.Close()
-		return nil, 0, err
+		return 0, err
 	}
 
 	var c Confirmation
 	err = c.DecodeFromBytes(b[:n])
 	if err != nil {
 		conn.Close()
-		return nil, 0, err
-	}
-	if publicUDP.Port != 0 && publicUDP.Port != int(c.Port) {
-		conn.Close()
-		return nil, 0, common.NewBasicError("port mismatch", nil, "requested", publicUDP.Port,
-			"received", c.Port)
+		return 0, err
 	}
-	// Disable deadline to not affect calling code
-	conn.SetDeadline(time.Time{})
-	return conn, c.Port, nil
+	return int(c.Port), nil
+
 }
 
 // ReadFrom works similarly to Read. In addition to Read, it also returns the last hop
diff --git a/go/sig/sigcmn/common.go b/go/sig/sigcmn/common.go
index 3b2d0ffdb..c93db37bb 100644
--- a/go/sig/sigcmn/common.go
+++ b/go/sig/sigcmn/common.go
@@ -58,7 +58,7 @@ func Init(cfg sigconfig.SigConf, sdCfg env.SciondClient) error {
 	MgmtAddr = mgmt.NewAddr(Host, cfg.CtrlPort, cfg.EncapPort)
 	encapPort = cfg.EncapPort
 
-	ds := reliable.NewDispatcherService(cfg.Dispatcher)
+	ds := reliable.NewDispatcher(cfg.Dispatcher)
 	// TODO(karampok). To be kept until https://github.com/scionproto/scion/issues/3377
 	wait := func() (*snet.SCIONNetwork, pathmgr.Resolver, error) {
 		deadline := time.Now().Add(sdCfg.InitialConnectPeriod.Duration)
diff --git a/go/tools/scmp/cmn/BUILD.bazel b/go/tools/scmp/cmn/BUILD.bazel
index 61ff93cac..33b5f76ed 100644
--- a/go/tools/scmp/cmn/BUILD.bazel
+++ b/go/tools/scmp/cmn/BUILD.bazel
@@ -14,7 +14,6 @@ go_library(
         "//go/lib/scrypto:go_default_library",
         "//go/lib/serrors:go_default_library",
         "//go/lib/snet:go_default_library",
-        "//go/lib/sock/reliable:go_default_library",
         "//go/lib/spkt:go_default_library",
         "//go/lib/topology:go_default_library",
     ],
diff --git a/go/tools/scmp/cmn/common.go b/go/tools/scmp/cmn/common.go
index c66c6219f..df4c82740 100644
--- a/go/tools/scmp/cmn/common.go
+++ b/go/tools/scmp/cmn/common.go
@@ -33,7 +33,6 @@ import (
 	_ "github.com/scionproto/scion/go/lib/scrypto" // Make sure math/rand is seeded
 	"github.com/scionproto/scion/go/lib/serrors"
 	"github.com/scionproto/scion/go/lib/snet"
-	"github.com/scionproto/scion/go/lib/sock/reliable"
 	"github.com/scionproto/scion/go/lib/spkt"
 	"github.com/scionproto/scion/go/lib/topology"
 )
@@ -63,7 +62,7 @@ var (
 )
 
 var (
-	Conn      *reliable.Conn
+	Conn      net.PacketConn
 	Mtu       uint16
 	PathEntry snet.Path
 	Stats     *ScmpStats
diff --git a/go/tools/scmp/echo/echo.go b/go/tools/scmp/echo/echo.go
index 088179b42..73eb93ab9 100644
--- a/go/tools/scmp/echo/echo.go
+++ b/go/tools/scmp/echo/echo.go
@@ -99,7 +99,7 @@ func recvPkts() {
 	start := time.Now()
 	updateDeadline(start, 0)
 	for cmn.Count == 0 || expectedSeq < uint16(cmn.Count) {
-		pktLen, err := cmn.Conn.Read(b)
+		pktLen, _, err := cmn.Conn.ReadFrom(b)
 		if err != nil {
 			if common.IsTimeoutErr(err) {
 				if expectedSeq > recvSeq {
diff --git a/go/tools/scmp/main.go b/go/tools/scmp/main.go
index 15835d571..19220fc77 100644
--- a/go/tools/scmp/main.go
+++ b/go/tools/scmp/main.go
@@ -20,7 +20,6 @@ import (
 	"context"
 	"flag"
 	"fmt"
-	"net"
 	"os"
 	"strconv"
 	"time"
@@ -68,15 +67,9 @@ func main() {
 		cmn.Fatal("Failed to connect to SCIOND: %v\n", err)
 	}
 	// Connect to the dispatcher
-	var overlayBindAddr *net.UDPAddr
-	if cmn.Bind.Host != nil {
-		overlayBindAddr = &net.UDPAddr{
-			IP:   cmn.Bind.Host.L3.IP(),
-			Port: int(cmn.Bind.Host.L4),
-		}
-	}
-	cmn.Conn, _, err = reliable.Register(*dispatcher, cmn.Local.IA, cmn.Local.Host,
-		overlayBindAddr, addr.SvcNone)
+	dispatcherService := reliable.NewDispatcher(*dispatcher)
+	cmn.Conn, _, err = dispatcherService.Register(context.Background(), cmn.Local.IA,
+		cmn.Local.Host, addr.SvcNone)
 	if err != nil {
 		cmn.Fatal("Unable to register with the dispatcher addr=%s\nerr=%v", cmn.Local, err)
 	}
diff --git a/go/tools/scmp/recordpath/recordpath.go b/go/tools/scmp/recordpath/recordpath.go
index 875414755..7b0d22df1 100644
--- a/go/tools/scmp/recordpath/recordpath.go
+++ b/go/tools/scmp/recordpath/recordpath.go
@@ -69,7 +69,7 @@ func Run() {
 	cmn.Stats.Sent += 1
 	// Receive packet with timeout
 	cmn.Conn.SetReadDeadline(ts.Add(cmn.Timeout))
-	pktLen, err = cmn.Conn.Read(b)
+	pktLen, _, err = cmn.Conn.ReadFrom(b)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
 		return
diff --git a/go/tools/scmp/traceroute/traceroute.go b/go/tools/scmp/traceroute/traceroute.go
index 1292912df..76b86c87d 100644
--- a/go/tools/scmp/traceroute/traceroute.go
+++ b/go/tools/scmp/traceroute/traceroute.go
@@ -83,7 +83,7 @@ func Run() {
 		cmn.Stats.Sent += 1
 		// Receive packet with timeout
 		cmn.Conn.SetReadDeadline(ts.Add(cmn.Timeout))
-		pktLen, err = cmn.Conn.Read(b)
+		pktLen, _, err = cmn.Conn.ReadFrom(b)
 		if err != nil {
 			if common.IsTimeoutErr(err) {
 				rtt = cmn.Timeout + 1
diff --git a/tools/gomocks b/tools/gomocks
index 9bfe7c9ae..22d50978e 100755
--- a/tools/gomocks
+++ b/tools/gomocks
@@ -59,7 +59,7 @@ MOCK_TARGETS = [
         (SCION_PACKAGE_PREFIX + "/go/lib/snet", "Conn,PacketDispatcherService,Network,PacketConn," +
             "Path,PathQuerier,Router"),
         (SCION_PACKAGE_PREFIX + "/go/lib/snet/internal/ctxmonitor", "Monitor"),
-        (SCION_PACKAGE_PREFIX + "/go/lib/sock/reliable", "DispatcherService"),
+        (SCION_PACKAGE_PREFIX + "/go/lib/sock/reliable", "Dispatcher"),
         (SCION_PACKAGE_PREFIX + "/go/lib/sock/reliable/reconnect", "IOOperation,Reconnecter"),
         (SCION_PACKAGE_PREFIX + "/go/lib/svc", "RequestHandler,RoundTripper"),
         (SCION_PACKAGE_PREFIX + "/go/lib/svc/internal/ctxconn", "DeadlineCloser"),


Test patch:
diff --git a/go/godispatcher/main_test.go b/go/godispatcher/main_test.go
index 54a35af6b..12d604fd8 100644
--- a/go/godispatcher/main_test.go
+++ b/go/godispatcher/main_test.go
@@ -16,6 +16,7 @@
 package main
 
 import (
+	"context"
 	"io/ioutil"
 	"net"
 	"os"
@@ -434,13 +435,14 @@ func TestDataplaneIntegration(t *testing.T) {
 }
 
 func RunTestCase(t *testing.T, tc *TestCase, settings *TestSettings) {
-	conn, _, err := reliable.RegisterTimeout(
-		settings.ApplicationSocket,
+	dispatcherService := reliable.NewDispatcher(settings.ApplicationSocket)
+	ctx, cancelF := context.WithTimeout(context.Background(), defaultTimeout)
+	defer cancelF()
+	conn, _, err := dispatcherService.Register(
+		ctx,
 		tc.ClientAddress.IA,
 		&addr.AppAddr{L3: tc.ClientAddress.PublicAddress, L4: tc.ClientAddress.PublicPort},
-		nil,
 		tc.ClientAddress.ServiceAddress,
-		defaultTimeout,
 	)
 	xtest.FailOnErr(t, err, "unable to open socket")
 	// Always destroy the connection s.t. future tests aren't compromised by a
diff --git a/go/lib/sock/reliable/reconnect/conn_io_test.go b/go/lib/sock/reliable/reconnect/conn_io_test.go
index feaf196cd..898db1d9e 100644
--- a/go/lib/sock/reliable/reconnect/conn_io_test.go
+++ b/go/lib/sock/reliable/reconnect/conn_io_test.go
@@ -15,6 +15,7 @@
 package reconnect_test
 
 import (
+	"context"
 	"net"
 	"testing"
 	"time"
@@ -81,7 +82,7 @@ func TestPacketConnIO(t *testing.T) {
 			gomock.InOrder(
 				mockIO.EXPECT().Do(mockConn).Return(writeDispatcherError),
 				mockReconnecter.EXPECT().Reconnect(Any()).DoAndReturn(
-					func(_ time.Duration) (net.PacketConn, uint16, error) {
+					func(_ context.Context) (net.PacketConn, uint16, error) {
 						time.Sleep(tickerMultiplier(4))
 						return mockConn, uint16(0), nil
 					}),
@@ -96,7 +97,7 @@ func TestPacketConnIO(t *testing.T) {
 			gomock.InOrder(
 				mockIO.EXPECT().Do(mockConn).Return(writeDispatcherError),
 				mockReconnecter.EXPECT().Reconnect(Any()).DoAndReturn(
-					func(_ time.Duration) (net.PacketConn, uint16, error) {
+					func(_ context.Context) (net.PacketConn, uint16, error) {
 						time.Sleep(tickerMultiplier(6))
 						return mockConn, uint16(0), nil
 					}),
@@ -121,7 +122,7 @@ func TestPacketConnIO(t *testing.T) {
 			gomock.InOrder(
 				mockIO.EXPECT().Do(mockConn).Return(writeDispatcherError),
 				mockReconnecter.EXPECT().Reconnect(Any()).DoAndReturn(
-					func(_ time.Duration) (net.PacketConn, uint16, error) {
+					func(_ context.Context) (net.PacketConn, uint16, error) {
 						time.Sleep(tickerMultiplier(6))
 						return mockConn, uint16(0), nil
 					}),
@@ -271,7 +272,7 @@ func TestPacketConnClose(t *testing.T) {
 			mockReconnecter.EXPECT().Stop().AnyTimes()
 			mockReconnecter.EXPECT().
 				Reconnect(Any()).
-				DoAndReturn(func(_ time.Duration) (net.PacketConn, uint16, error) {
+				DoAndReturn(func(_ context.Context) (net.PacketConn, uint16, error) {
 					select {}
 				})
 			mockIO := mock_reconnect.NewMockIOOperation(ctrl)
diff --git a/go/lib/sock/reliable/reconnect/main_test.go b/go/lib/sock/reliable/reconnect/main_test.go
index 4b01b2240..6382fb9dc 100644
--- a/go/lib/sock/reliable/reconnect/main_test.go
+++ b/go/lib/sock/reliable/reconnect/main_test.go
@@ -15,6 +15,7 @@
 package reconnect_test
 
 import (
+	"context"
 	"fmt"
 	"net"
 	"os"
@@ -69,6 +70,12 @@ func tickerMultiplier(multiplier time.Duration) time.Duration {
 	return multiplier * reconnect.DefaultTickerInterval
 }
 
+func ctxMultiplier(multiplier time.Duration) context.Context {
+	ctx, cancelF := context.WithTimeout(context.Background(), tickerMultiplier(multiplier))
+	_ = cancelF
+	return ctx
+}
+
 func TestMain(m *testing.M) {
 	// Inject a smaller timeout s.t. tests run quickly
 	reconnect.DefaultTickerInterval = 10 * time.Millisecond
diff --git a/go/lib/sock/reliable/reconnect/network_test.go b/go/lib/sock/reliable/reconnect/network_test.go
index 003128664..c8db7b327 100644
--- a/go/lib/sock/reliable/reconnect/network_test.go
+++ b/go/lib/sock/reliable/reconnect/network_test.go
@@ -15,6 +15,7 @@
 package reconnect_test
 
 import (
+	"context"
 	"net"
 	"os"
 	"syscall"
@@ -34,22 +35,22 @@ func TestReconnect(t *testing.T) {
 	Convey("Reconnections must conserve local and bind addresses", t, func() {
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
-		mockNetwork := mock_reliable.NewMockDispatcherService(ctrl)
+		mockDispatcher := mock_reliable.NewMockDispatcher(ctrl)
 		Convey("Given a mocked underlying connection with local and bind", func() {
 			mockConn := mock_net.NewMockPacketConn(ctrl)
 			Convey("Allocated ports are reused on subsequent attempts", func() {
-				mockNetwork.EXPECT().
-					RegisterTimeout(localAddr.IA, localNoPortAddr.Host, bindAddr, svc, timeout).
+				mockDispatcher.EXPECT().
+					Register(context.Background(), localAddr.IA, localNoPortAddr.Host, svc).
 					Return(mockConn, uint16(80), nil)
 				newExpectedAddr := localNoPortAddr.Host.Copy()
 				newExpectedAddr.L4 = 80
-				mockNetwork.EXPECT().
-					RegisterTimeout(localAddr.IA, newExpectedAddr, bindAddr, svc, timeout).
+				mockDispatcher.EXPECT().
+					Register(context.Background(), localAddr.IA, newExpectedAddr, svc).
 					Return(mockConn, uint16(80), nil)
 
-				network := reconnect.NewDispatcherService(mockNetwork)
-				packetConn, _, _ := network.RegisterTimeout(localAddr.IA,
-					localNoPortAddr.Host, bindAddr, svc, timeout)
+				network := reconnect.NewDispatcherService(mockDispatcher)
+				packetConn, _, _ := network.RegisterTimeout(context.Background(), localAddr.IA,
+					localNoPortAddr.Host, svc)
 				packetConn.(*reconnect.PacketConn).Reconnect()
 			})
 		})
@@ -61,20 +62,20 @@ func TestNetworkFatalError(t *testing.T) {
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		err := serrors.New("Not dispatcher dead error, e.g., malformed register msg")
-		mockNetwork := mock_reliable.NewMockDispatcherService(ctrl)
+		mockNetwork := mock_reliable.NewMockDispatcher(ctrl)
 		network := reconnect.NewDispatcherService(mockNetwork)
 		Convey("The network returns non-dispatcher dial errors from the mock", func() {
 			mockNetwork.EXPECT().
-				RegisterTimeout(Any(), Any(), Any(), Any(), Any()).
+				Register(Any(), Any(), Any(), Any()).
 				Return(nil, uint16(0), err)
-			_, _, err := network.RegisterTimeout(addr.IA{}, nil, nil, addr.SvcNone, 0)
+			_, _, err := network.Register(context.Background(), addr.IA{}, nil, addr.SvcNone)
 			SoMsg("err", err, ShouldNotBeNil)
 		})
 		Convey("The network returns non-dispatcher listen errors from the mock", func() {
 			mockNetwork.EXPECT().
-				RegisterTimeout(Any(), Any(), Any(), Any(), Any()).
+				Register(Any(), Any(), Any(), Any()).
 				Return(nil, uint16(0), err)
-			_, _, err := network.RegisterTimeout(addr.IA{}, nil, nil, addr.SvcNone, 0)
+			_, _, err := network.Register(context.Background(), addr.IA{}, nil, addr.SvcNone)
 			SoMsg("err", err, ShouldNotBeNil)
 		})
 	})
@@ -85,56 +86,54 @@ func TestNetworkDispatcherDeadError(t *testing.T) {
 	Convey("Listen and Dial should reattempt to connect on dispatcher down errors", t, func() {
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
-		mockNetwork := mock_reliable.NewMockDispatcherService(ctrl)
+		mockNetwork := mock_reliable.NewMockDispatcher(ctrl)
 		network := reconnect.NewDispatcherService(mockNetwork)
 		Convey("Dial tries to reconnect if no timeout set", func() {
 			mockConn := mock_net.NewMockPacketConn(ctrl)
 			gomock.InOrder(
 				mockNetwork.EXPECT().
-					RegisterTimeout(Any(), Any(), Any(), Any(), Any()).
+					Register(Any(), Any(), Any(), Any()).
 					Return(nil, uint16(0), dispatcherError).
 					Times(2),
 				mockNetwork.EXPECT().
-					RegisterTimeout(Any(), Any(), Any(), Any(), Any()).
+					Register(Any(), Any(), Any(), Any()).
 					Return(mockConn, uint16(0), nil),
 			)
-			_, _, err := network.RegisterTimeout(addr.IA{}, nil, nil, addr.SvcNone, 0)
+			_, _, err := network.Register(context.Background(), addr.IA{}, nil, addr.SvcNone)
 			SoMsg("err", err, ShouldBeNil)
 		})
 		Convey("Dial only retries for limited time if timeout set", func() {
 			gomock.InOrder(
 				mockNetwork.EXPECT().
-					RegisterTimeout(Any(), Any(), Any(), Any(), Any()).
+					Register(Any(), Any(), Any(), Any()).
 					Return(nil, uint16(0), dispatcherError).
 					MinTimes(2).MaxTimes(5),
 			)
-			_, _, err := network.RegisterTimeout(addr.IA{},
-				nil, nil, addr.SvcNone, tickerMultiplier(4))
+			_, _, err := network.Register(ctxMultiplier(4), addr.IA{}, nil, addr.SvcNone)
 			SoMsg("err", err, ShouldNotBeNil)
 		})
 		Convey("Listen tries to reconnect if no timeout set", func() {
 			mockConn := mock_net.NewMockPacketConn(ctrl)
 			gomock.InOrder(
 				mockNetwork.EXPECT().
-					RegisterTimeout(Any(), Any(), Any(), Any(), Any()).
+					Register(Any(), Any(), Any(), Any()).
 					Return(nil, uint16(0), dispatcherError).
 					Times(2),
 				mockNetwork.EXPECT().
-					RegisterTimeout(Any(), Any(), Any(), Any(), Any()).
+					Register(Any(), Any(), Any(), Any()).
 					Return(mockConn, uint16(0), nil),
 			)
-			_, _, err := network.RegisterTimeout(addr.IA{}, nil, nil, addr.SvcNone, 0)
+			_, _, err := network.Register(context.Background(), addr.IA{}, nil, addr.SvcNone)
 			SoMsg("err", err, ShouldBeNil)
 		})
 		Convey("Listen only retries for limited time if timeout set", func() {
 			gomock.InOrder(
 				mockNetwork.EXPECT().
-					RegisterTimeout(Any(), Any(), Any(), Any(), Any()).
+					Register(Any(), Any(), Any(), Any()).
 					Return(nil, uint16(0), dispatcherError).
 					MinTimes(3).MaxTimes(5),
 			)
-			_, _, err := network.RegisterTimeout(addr.IA{},
-				nil, nil, addr.SvcNone, tickerMultiplier(4))
+			_, _, err := network.Register(ctxMultiplier(4), addr.IA{}, nil, addr.SvcNone)
 			SoMsg("err", err, ShouldNotBeNil)
 		})
 	})
diff --git a/go/lib/sock/reliable/reconnect/reconnecter_test.go b/go/lib/sock/reliable/reconnect/reconnecter_test.go
index d0b2c3911..b0ce69b8e 100644
--- a/go/lib/sock/reliable/reconnect/reconnecter_test.go
+++ b/go/lib/sock/reliable/reconnect/reconnecter_test.go
@@ -15,6 +15,7 @@
 package reconnect_test
 
 import (
+	"context"
 	"net"
 	"testing"
 	"time"
@@ -87,7 +88,7 @@ func reconnectWithoutTimeoutAfter(reconnecter *reconnect.TickingReconnecter,
 	sleepAtStart time.Duration) error {
 
 	time.Sleep(sleepAtStart)
-	_, _, err := reconnecter.Reconnect(0)
+	_, _, err := reconnecter.Reconnect(context.Background())
 	return err
 }