Skip to content

Commit 061b68a

Browse files
committed
prototype scion-socket
this is required by bindings to languages whose networking libraries main abstraction are berkley sockets, not connections as in Go
1 parent 3afc9a9 commit 061b68a

File tree

8 files changed

+590
-46
lines changed

8 files changed

+590
-46
lines changed

.vscode/launch.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Launch Package",
9+
"type": "go",
10+
"request": "launch",
11+
"mode": "auto",
12+
"program": "${workspaceFolder}/_examples/helloworld_socket/helloworld_socket.go",
13+
"args": ["-remote" ,"19-ffaa:1:1067,127.0.0.1:2222"]
14+
15+
}
16+
]
17+
}
22.1 MB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright 2018 ETH Zurich
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"context"
19+
"errors"
20+
"flag"
21+
"fmt"
22+
"net/netip"
23+
"os"
24+
"time"
25+
26+
"github.com/netsec-ethz/scion-apps/pkg/pan"
27+
)
28+
29+
func main() {
30+
var err error
31+
// get local and remote addresses from program arguments:
32+
var listen pan.IPPortValue
33+
flag.Var(&listen, "listen", "[Server] local IP:port to listen on")
34+
remoteAddr := flag.String("remote", "", "[Client] Remote (i.e. the server's) SCION Address (e.g. 17-ffaa:1:1,[127.0.0.1]:12345)")
35+
count := flag.Uint("count", 1, "[Client] Number of messages to send")
36+
flag.Parse()
37+
38+
if (listen.Get().Port() > 0) == (len(*remoteAddr) > 0) {
39+
check(fmt.Errorf("either specify -listen for server or -remote for client"))
40+
}
41+
42+
if listen.Get().Port() > 0 {
43+
err = runServer(listen.Get())
44+
check(err)
45+
} else {
46+
err = runClient(*remoteAddr, int(*count))
47+
check(err)
48+
}
49+
}
50+
51+
func runServer(listen netip.AddrPort) error {
52+
sock, err := pan.NewScionSocket(context.Background(), listen)
53+
54+
if err != nil {
55+
return err
56+
}
57+
defer sock.Close()
58+
fmt.Println(sock.LocalAddr())
59+
60+
buffer := make([]byte, 16*1024)
61+
for {
62+
n, from, err := sock.ReadFrom(buffer)
63+
if err != nil {
64+
return err
65+
}
66+
data := buffer[:n]
67+
fmt.Printf("Received %s: %s\n", from, data)
68+
msg := fmt.Sprintf("take it back! %s", time.Now().Format("15:04:05.0"))
69+
n, err = sock.WriteTo([]byte(msg), from)
70+
if err != nil {
71+
return err
72+
}
73+
fmt.Printf("Wrote %d bytes.\n", n)
74+
}
75+
}
76+
77+
func runClient(address string, count int) error {
78+
addr, err := pan.ResolveUDPAddr(context.TODO(), address)
79+
if err != nil {
80+
return err
81+
}
82+
83+
sock, err := pan.NewScionSocket(context.Background(), netip.AddrPort{})
84+
if err != nil {
85+
return err
86+
}
87+
defer sock.Close()
88+
89+
for i := 0; i < count; i++ {
90+
nBytes, err := sock.WriteTo([]byte(fmt.Sprintf("hello world %s", time.Now().Format("15:04:05.0"))), addr)
91+
if err != nil {
92+
return err
93+
}
94+
fmt.Printf("Wrote %d bytes.\n", nBytes)
95+
96+
buffer := make([]byte, 16*1024)
97+
/* if err = conn.SetReadDeadline(time.Now().Add(1 * time.Second)); err != nil {
98+
return err
99+
} */
100+
n, _, err := sock.ReadFrom(buffer)
101+
if errors.Is(err, os.ErrDeadlineExceeded) {
102+
continue
103+
} else if err != nil {
104+
return err
105+
}
106+
data := buffer[:n]
107+
fmt.Printf("Received reply: %s\n", data)
108+
}
109+
return nil
110+
}
111+
112+
// Check just ensures the error is nil, or complains and quits
113+
func check(e error) {
114+
if e != nil {
115+
fmt.Fprintln(os.Stderr, "Fatal error:", e)
116+
os.Exit(1)
117+
}
118+
}

pkg/pan/combi_selector.go

+188
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
package pan
2+
3+
import (
4+
"context"
5+
"errors"
6+
)
7+
8+
// socket roles (selector internals)
9+
const dialer = 0
10+
const listener = 1
11+
12+
/*
13+
!
14+
\brief this class provides the service of path selection for a remote address to scion-sockets
15+
Every scion-socket has one.
16+
17+
It should not be cluttered with Refresh()/Update()/PathDown or any other technical
18+
methods that are required by the pathStatedDB or pathPool to update the selectors state.
19+
*/
20+
type CombiSelector interface {
21+
Close() error
22+
// PathDown(PathFingerprint, PathInterface) // pathDownNotifyee
23+
24+
// called when the scion-socket is bound to an address
25+
LocalAddrChanged(newlocal UDPAddr)
26+
Path(remote UDPAddr) (*Path, error)
27+
//Refresh([]*Path) Selector
28+
// Refresh(paths []*Path, remote UDPAddr)
29+
Record(remote UDPAddr, path *Path)
30+
//Update( )#
31+
// setter the respective defaults
32+
SetReplySelector(ReplySelector)
33+
SetSelector(sel func() Selector)
34+
SetPolicy(pol func() Policy)
35+
36+
// setter for AS specific path policies
37+
// SetSelectorFor(remote IA, sel Selector)
38+
// SetPolicyFor(remote IA, pol Policy)
39+
// SetPolicedSelectorFor(remote IA, sel Selector, pol Policy)
40+
41+
// initialize(local UDPAddr, remote UDPAddr, paths []*Path)
42+
// maybe make this pubilc and let the ScionCocketCall it,
43+
// in its ctor (or once the local addr is known i.e after Bind() was called )
44+
}
45+
46+
type DefaultCombiSelector struct {
47+
local UDPAddr
48+
roles map[UDPAddr]int // is this host the dialer or listener for the connection to this remote host
49+
// decided from which method is called first for a remote address X
50+
// Record(X)->listener or Path(X)->dialer
51+
52+
// maybe make map of pair (, ,) ?!
53+
// policies map[UDPAddr]Policy
54+
policy_factory func() Policy
55+
selector_factory func() Selector
56+
57+
// TODO: this state should be confined in size somehow
58+
// i.e. drop selectors with LRU scheme
59+
// Note that this is not an attack vector, as this state can only be increased
60+
// by deliberate decisions of this host to dial a remote for which it does not yet has a selector
61+
selectors map[IA]Selector
62+
subscribers map[IA]*pathRefreshSubscriber
63+
replyselector ReplySelector
64+
}
65+
66+
func (s *DefaultCombiSelector) needPathTo(remote UDPAddr) bool {
67+
return s.local.IA != remote.IA
68+
}
69+
70+
func (s *DefaultCombiSelector) Close() error {
71+
72+
for _, v := range s.subscribers {
73+
if e := v.Close(); e != nil {
74+
return e
75+
}
76+
}
77+
78+
for _, v := range s.selectors {
79+
if e := v.Close(); e != nil {
80+
return e
81+
}
82+
}
83+
if e := s.replyselector.Close(); e != nil {
84+
return e
85+
}
86+
87+
return nil
88+
}
89+
90+
func NewDefaultCombiSelector(local UDPAddr) (CombiSelector, error) {
91+
selector := &DefaultCombiSelector{
92+
local: local,
93+
roles: make(map[UDPAddr]int),
94+
// policies: make(map[UDPAddr]Policy),
95+
policy_factory: func() Policy {
96+
var s Policy = nil
97+
return s
98+
},
99+
selector_factory: func() Selector { return NewDefaultSelector() },
100+
selectors: make(map[IA]Selector),
101+
subscribers: make(map[IA]*pathRefreshSubscriber),
102+
replyselector: NewDefaultReplySelector(),
103+
}
104+
105+
selector.replyselector.Initialize(local)
106+
107+
return selector, nil
108+
}
109+
110+
func (s *DefaultCombiSelector) SetReplySelector(rep ReplySelector) {
111+
s.replyselector = rep
112+
}
113+
114+
func (s *DefaultCombiSelector) LocalAddrChanged(newlocal UDPAddr) {
115+
s.local = newlocal
116+
}
117+
118+
func (s *DefaultCombiSelector) Path(remote UDPAddr) (*Path, error) {
119+
if r, ok := s.roles[remote]; ok {
120+
// the role is already decided
121+
if r == dialer {
122+
if s.needPathTo(remote) {
123+
sel := s.selectors[remote.IA]
124+
sel.NewRemote(remote)
125+
return sel.Path(remote)
126+
} else {
127+
return nil, errors.New("if src and dst are in same AS and no scion path is required, the connection shouldnt request one")
128+
}
129+
} else {
130+
return s.replyselector.Path(remote)
131+
}
132+
} else {
133+
// no role yet -> no path to remote has been requested yet Path()
134+
// so we are acting as a server
135+
s.roles[remote] = dialer
136+
137+
// set up a refresherSubscriber etc ..
138+
if s.needPathTo(remote) {
139+
var selector Selector
140+
var policy Policy
141+
142+
if s.policy_factory != nil {
143+
policy = s.policy_factory()
144+
}
145+
if s.selector_factory != nil {
146+
selector = s.selector_factory()
147+
} else {
148+
selector = NewDefaultSelector()
149+
}
150+
var ctx context.Context = context.Background()
151+
// Todo: set timeout for path request
152+
subscriber, err := openPathRefreshSubscriber(ctx, s.local, remote, policy, selector)
153+
if err != nil {
154+
155+
return nil, err
156+
}
157+
s.selectors[remote.IA] = selector
158+
s.subscribers[remote.IA] = subscriber
159+
160+
return selector.Path(remote)
161+
} else {
162+
return nil, errors.New("if src and dst are in same AS and no scion path is required, the connection shouldnt request one")
163+
}
164+
}
165+
}
166+
167+
func (s *DefaultCombiSelector) SetPolicy(pol func() Policy) {
168+
s.policy_factory = pol
169+
}
170+
171+
func (s *DefaultCombiSelector) SetSelector(sel func() Selector) {
172+
s.selector_factory = sel
173+
}
174+
175+
func (s *DefaultCombiSelector) Record(remote UDPAddr, path *Path) {
176+
177+
if r, ok := s.roles[remote]; ok {
178+
// the role is already decided
179+
if r == listener {
180+
s.replyselector.Record(remote, path)
181+
}
182+
} else {
183+
// no role yet -> no path to remote has been requested yet Path()
184+
// so we are acting as a server
185+
s.roles[remote] = listener
186+
}
187+
188+
}

0 commit comments

Comments
 (0)