Skip to content

Commit bf15c14

Browse files
authored
Merge pull request #29 from jmgraeffe/feature/cancellable-dial-in
V1: made QUIC socket dial in functions cancellable
2 parents ead496e + 5ab2f23 commit bf15c14

File tree

7 files changed

+145
-0
lines changed

7 files changed

+145
-0
lines changed

api/smp.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package smp
22

33
import (
4+
"context"
45
"time"
56

67
"github.com/netsys-lab/scion-path-discovery/packets"
@@ -476,3 +477,11 @@ func (l *MPListener) Listen() error {
476477
func (l *MPListener) WaitForMPPeerSockConnect() (*snet.UDPAddr, error) {
477478
return l.socket.WaitForDialIn()
478479
}
480+
481+
// Waits for new incoming MPPeerSocks
482+
// Should be called in a loop
483+
// Using the returned addr, a new MPPeerSock can be instantiated
484+
// That dials back to the incoming socket
485+
func (l *MPListener) WaitForMPPeerSockConnectWithContext(ctx context.Context) (*snet.UDPAddr, error) {
486+
return l.socket.WaitForDialInWithContext(ctx)
487+
}

packets/quicconn.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,24 @@ func (qc *QUICReliableConn) AcceptStream() (quic.Stream, error) {
244244
return stream, nil
245245
}
246246

247+
func (qc *QUICReliableConn) AcceptStreamWithContext(ctx context.Context) (quic.Stream, error) {
248+
log.Debugf("Accepting on quic %s", qc.listener.Addr())
249+
session, err := qc.listener.Accept(ctx)
250+
if err != nil {
251+
return nil, err
252+
}
253+
log.Debugf("Got session on quic %s", qc.listener.Addr())
254+
255+
stream, err := session.AcceptStream(ctx)
256+
if err != nil {
257+
return nil, err
258+
}
259+
260+
// qc.internalConn = stream
261+
262+
return stream, nil
263+
}
264+
247265
func (qc *QUICReliableConn) Listen(addr snet.UDPAddr) error {
248266
qc.Ready = make(chan bool, 0)
249267
udpAddr := net.UDPAddr{

socket/quicsocket.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package socket
22

33
import (
44
"bytes"
5+
"context"
56
"crypto/rand"
67
"encoding/base32"
78
"encoding/gob"
@@ -178,6 +179,48 @@ func (s *QUICSocket) WaitForDialIn() (*snet.UDPAddr, error) {
178179
return &addr, nil
179180
}
180181

182+
func (s *QUICSocket) WaitForDialInWithContext(ctx context.Context) (*snet.UDPAddr, error) {
183+
bts := make([]byte, packets.PACKET_SIZE)
184+
log.Debugf("Wait for Dial In")
185+
stream, err := s.listenConns[0].AcceptStreamWithContext(ctx)
186+
if err != nil {
187+
return nil, err
188+
}
189+
190+
s.listenConns[0].SetStream(stream)
191+
192+
select {
193+
case s.listenConns[0].Ready <- true:
194+
default:
195+
}
196+
197+
_, err = stream.Read(bts)
198+
if err != nil {
199+
return nil, err
200+
}
201+
p := DialPacketQuic{}
202+
network := bytes.NewBuffer(bts) // Stand-in for a network connection
203+
dec := gob.NewDecoder(network)
204+
err = dec.Decode(&p)
205+
if err != nil {
206+
return nil, err
207+
}
208+
209+
s.listenConns[0].SetRemote(&p.Addr)
210+
log.Debugf("Waiting for %d more connections", p.NumPaths-1)
211+
212+
for i := 1; i < p.NumPaths; i++ {
213+
_, err := s.WaitForIncomingConn()
214+
if err != nil {
215+
return nil, err
216+
}
217+
log.Debugf("Dialed In %d of %d", i, p.NumPaths)
218+
}
219+
220+
addr := p.Addr
221+
return &addr, nil
222+
}
223+
181224
func (s *QUICSocket) Dial(remote snet.UDPAddr, path snet.Path, options DialOptions, i int) (packets.UDPConn, error) {
182225
// appnet.SetPath(&remote, path)
183226
if s.options == nil || !s.options.MultiportMode {

socket/quicsocket_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package socket
22

33
import (
4+
"context"
5+
"errors"
46
"testing"
7+
"time"
58

69
lookup "github.com/netsys-lab/scion-path-discovery/pathlookup"
710
"github.com/netsys-lab/scion-path-discovery/pathselection"
@@ -63,4 +66,22 @@ func Test_QUICSocket(t *testing.T) {
6366
sock2.CloseAll()
6467
})
6568

69+
t.Run("QUICSocket Listen And Contextualized Wait For Dial", func(t *testing.T) {
70+
sock := NewQUICSocket("1-ff00:0:110,[127.0.0.12]:41000", &SockOptions{PathSelectionResponsibility: "server"})
71+
err := sock.Listen()
72+
if err != nil {
73+
t.Error(err)
74+
return
75+
}
76+
defer sock.CloseAll()
77+
78+
ctx, cancelFunc := context.WithDeadline(context.Background(), time.Now())
79+
defer cancelFunc()
80+
_, err = sock.WaitForDialInWithContext(ctx)
81+
if err != nil && !errors.Is(err, context.DeadlineExceeded) {
82+
t.Error(err)
83+
return
84+
}
85+
})
86+
6687
}

socket/scionsocket.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package socket
22

33
import (
44
"bytes"
5+
"context"
56
"encoding/gob"
7+
"os"
8+
"time"
69

710
"github.com/netsys-lab/scion-path-discovery/packets"
811
"github.com/netsys-lab/scion-path-discovery/pathselection"
@@ -74,6 +77,34 @@ func (s *SCIONSocket) WaitForDialIn() (*snet.UDPAddr, error) {
7477
return &addr, nil
7578
}
7679

80+
func (s *SCIONSocket) WaitForDialInWithContext(ctx context.Context) (*snet.UDPAddr, error) {
81+
for {
82+
deadline, hasDeadline := ctx.Deadline()
83+
var err error
84+
if hasDeadline {
85+
err = s.connections[0].SetReadDeadline(deadline)
86+
} else {
87+
err = s.connections[0].SetDeadline(time.Now().Add(5 * time.Second))
88+
}
89+
if err != nil {
90+
return nil, err
91+
}
92+
93+
addr, err := s.WaitForDialIn()
94+
if err == nil {
95+
return addr, nil
96+
} else if !os.IsTimeout(err) {
97+
return nil, err
98+
}
99+
100+
select {
101+
case <-ctx.Done():
102+
return nil, ctx.Err()
103+
}
104+
}
105+
106+
}
107+
77108
func (s *SCIONSocket) Dial(remote snet.UDPAddr, path snet.Path, options DialOptions, i int) (packets.UDPConn, error) {
78109
// appnet.SetPath(&remote, path)
79110
// fmt.Printf("Dialing to %s via %s\n", remote.String(), remote.Path)

socket/scionsocket_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package socket
22

33
import (
4+
"context"
5+
"errors"
46
"testing"
7+
"time"
58

69
lookup "github.com/netsys-lab/scion-path-discovery/pathlookup"
710
"github.com/netsys-lab/scion-path-discovery/pathselection"
@@ -64,4 +67,22 @@ func Test_SCIONSocket(t *testing.T) {
6467
sock2.CloseAll()
6568
})
6669

70+
t.Run("SCIONSocket Listen And Contextualized Wait For Dial", func(t *testing.T) {
71+
sock := NewSCIONSocket("1-ff00:0:110,[127.0.0.12]:21000")
72+
err := sock.Listen()
73+
if err != nil {
74+
t.Error(err)
75+
return
76+
}
77+
defer sock.CloseAll()
78+
79+
ctx, cancelFunc := context.WithDeadline(context.Background(), time.Now())
80+
defer cancelFunc()
81+
_, err = sock.WaitForDialInWithContext(ctx)
82+
if err != nil && !errors.Is(err, context.DeadlineExceeded) {
83+
t.Error(err)
84+
return
85+
}
86+
})
87+
6788
}

socket/socket.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package socket
22

33
import (
4+
"context"
45
"github.com/netsys-lab/scion-path-discovery/packets"
56
"github.com/netsys-lab/scion-path-discovery/pathselection"
67
"github.com/scionproto/scion/go/lib/snet"
@@ -26,6 +27,7 @@ type DialOptions struct {
2627
type UnderlaySocket interface {
2728
Listen() error
2829
WaitForDialIn() (*snet.UDPAddr, error)
30+
WaitForDialInWithContext(ctx context.Context) (*snet.UDPAddr, error)
2931
WaitForIncomingConn() (packets.UDPConn, error)
3032
Dial(remote snet.UDPAddr, path snet.Path, options DialOptions, i int) (packets.UDPConn, error)
3133
DialAll(remote snet.UDPAddr, path []pathselection.PathQuality, options DialOptions) ([]packets.UDPConn, error)

0 commit comments

Comments
 (0)