Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions docs/sandbox-link-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ A stream ends in one of two ways, and the relay keeps them apart end to end. An

The Sandbox I/O service runs `sandboxlink.Serve` with a `ServeConfig`:

- `URL`, `Credential` and `Resource` come from the [bootstrap input](sandbox-bootstrap.md). `PeerID` identifies the service. `ServerInstanceID` is a new ID whenever the service starts without its operation and handle registries.
- `URL`, `Credential` and `Resource` come from the [bootstrap input](sandbox-bootstrap.md). The credential identifies the service, so the Hello carries no peer ID. `ServerInstanceID` is a new ID whenever the service starts without its operation and handle registries.
- `Services` holds one handler per offered service and version. A handler receives the `Bind`, which carries the authorized binding including a File stream's exports, and the stream. It owns the stream and returns when it is done with it. Its context ends when the attachment closes or `Serve` returns.
- `Serve` reconnects with jittered exponential backoff, sending the same `ServerInstanceID`, whenever the link drops. It returns when its context ends or when the relay refuses the Hello with any failure other than `ServiceUnavailable` or `LimitExceeded`, for example `AuthenticationFailed` after the credential is withdrawn or `StaleGeneration` after a newer sandbox took over the resource. Before returning it cancels every handler's context and waits for the handlers.
- `OnAttachmentLost` fires when an attachment's last open stream ends while the attachment is still open, such as when the link drops. `OnAttachmentRestored` fires when a stream binds a lost attachment again. `OnAttachmentClosed` fires with the reason when the relay reports `AttachmentClosed`. Losing a socket is not closing an attachment: the service keeps an attachment's state until it is closed.
Expand Down Expand Up @@ -114,7 +114,6 @@ Hello
Version u16 // 1
Role enum // RoleServe = 1, RoleAttach = 2
if RoleServe:
PeerID ID
Credential bytes // 1..4096 bytes
Resource ResourceRef
ServerInstanceID ID
Expand Down Expand Up @@ -204,7 +203,7 @@ Later control requests continue the Hello's request IDs. The relay ends an attac

`HelloAccepted.MaxStreams` bounds the link's concurrent service streams. `MaxFrameBytes` bounds the payload of every frame on the link's service streams.

For a serve peer, the Authority returns the peer ID and the resource, including generation, that the credential serves. Both must equal the Hello's, otherwise the answer is `PermissionDenied`. The relay then applies the [generation rule](#authority-and-staleness) and makes the link the resource's current serve peer.
For a serve peer, the Authority returns the peer's identity and the resource, including generation, that the credential serves. The resource must equal the Hello's, otherwise the answer is `PermissionDenied`. The relay then applies the [generation rule](#authority-and-staleness) and makes the link the resource's current serve peer.

The relay and the serve peer bound each handshake step, the WebSocket upgrade, the Hello, reading an `Open`, a `Bind` and its answer and each Authority call, by `sandboxlink.HandshakeTimeout` (10 seconds). The attach peer bounds an Open with its context.

Expand Down
11 changes: 5 additions & 6 deletions internal/sandboxlink/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,11 @@ type ServiceVersion struct {
Version uint16
}

// ServeHello introduces the Sandbox I/O service. ServerInstanceID changes
// whenever the service loses its operation or handle registry.
// ServeHello introduces the Sandbox I/O service. The credential identifies
// the peer, so the Hello carries no peer ID. ServerInstanceID changes whenever
// the service loses its operation or handle registry.
type ServeHello struct {
Version uint16
PeerID sandboxwire.ID
Credential []byte
Resource ResourceRef
ServerInstanceID sandboxwire.ID
Expand Down Expand Up @@ -611,7 +611,7 @@ func decodeRequest(r *reader, op Op) Message {
return nil
}
if Role(r.enum(func(v uint16) bool { return Role(v) == RoleServe || Role(v) == RoleAttach })) == RoleServe {
h := ServeHello{Version: Version, PeerID: r.id(), Credential: r.bytes(), Resource: r.resource(), ServerInstanceID: r.id()}
h := ServeHello{Version: Version, Credential: r.bytes(), Resource: r.resource(), ServerInstanceID: r.id()}
n := r.count(uint32(ServiceNetwork))
for range n {
h.Services = append(h.Services, ServiceVersion{Service: r.service(), Version: r.u16()})
Expand Down Expand Up @@ -672,7 +672,6 @@ func decodeSuccess(r *reader, op Op) Message {
func (h ServeHello) encode(e *sandboxwire.Encoder) {
e.U16(h.Version)
e.Enum(uint16(RoleServe))
e.ID(h.PeerID)
e.Bytes(h.Credential)
encodeResource(e, h.Resource)
e.ID(h.ServerInstanceID)
Expand Down Expand Up @@ -911,7 +910,7 @@ func (h ServeHello) validate() error {
if err := h.Resource.validate(); err != nil {
return err
}
return checkIDs(h.PeerID, h.ServerInstanceID)
return checkIDs(h.ServerInstanceID)
}

func (h AttachHello) validate() error {
Expand Down
2 changes: 1 addition & 1 deletion internal/sandboxlink/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type golden struct {

// goldenFrames are the frames in testdata/link_v1.hex, in order.
var goldenFrames = []golden{
{1, ServeHello{Version: 1, PeerID: testID(0x04), Credential: []byte("serve"), Resource: testResource, ServerInstanceID: testID(0x05),
{1, ServeHello{Version: 1, Credential: []byte("serve"), Resource: testResource, ServerInstanceID: testID(0x05),
Services: []ServiceVersion{{ServiceFile, 1}, {ServiceNetwork, 1}}}},
{1, AttachHello{Version: 1, RuntimeID: testID(0x06), Credential: []byte("runtime")}},
{1, HelloAccepted{LinkID: testID(0x0a), MaxStreams: 256, MaxFrameBytes: 1 << 20}},
Expand Down
2 changes: 1 addition & 1 deletion internal/sandboxlink/relay/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ func (rl *Relay) admitServe(l *link, id uint64, hello sandboxlink.ServeHello) (*
ctx, cancel := rl.authorityContext()
peer, err := rl.cfg.Authority.AuthenticateServe(ctx, hello)
cancel()
if err == nil && peer != (sandboxlink.ServePeer{PeerID: hello.PeerID, Resource: hello.Resource}) {
if err == nil && peer.Resource != hello.Resource {
err = sandboxlink.Fail(sandboxlink.PermissionDenied)
}
if err != nil {
Expand Down
5 changes: 2 additions & 3 deletions internal/sandboxlink/relay/relay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,7 @@ func (f *fixture) serve(generation uint64) *servePeer {

func (f *fixture) startServe(generation uint64) *servePeer {
credential := []byte(fmt.Sprintf("serve credential %d", generation))
peerID := sandboxwire.NewID()
f.auth.AddServe(credential, sandboxlink.ServePeer{PeerID: peerID, Resource: resource(generation)})
f.auth.AddServe(credential, sandboxlink.ServePeer{PeerID: sandboxwire.NewID(), Resource: resource(generation)})
p := &servePeer{instance: sandboxwire.NewID(), connected: make(chan sandboxlink.HelloAccepted, 16), conns: make(chan net.Conn, 16),
lost: make(chan sandboxwire.ID, 16), restored: make(chan sandboxwire.ID, 16), closed: make(chan sandboxlink.CloseReason, 128),
binds: make(chan sandboxlink.Bind, 16), echoed: make(chan error, 16), done: make(chan struct{})}
Expand All @@ -168,7 +167,7 @@ func (f *fixture) startServe(generation uint64) *servePeer {
}
return c, err
},
PeerID: peerID, Credential: credential, Resource: resource(generation), ServerInstanceID: p.instance,
Credential: credential, Resource: resource(generation), ServerInstanceID: p.instance,
Services: []sandboxlink.ServiceHandler{
{Service: sandboxlink.ServiceFile, Version: 1, Serve: echo},
{Service: sandboxlink.ServiceProcess, Version: 1, Serve: resetAfterOne},
Expand Down
3 changes: 1 addition & 2 deletions internal/sandboxlink/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ type ServeConfig struct {
URL string
TLS *tls.Config
Dial Dialer
PeerID sandboxwire.ID
Credential []byte
Resource ResourceRef
ServerInstanceID sandboxwire.ID
Expand Down Expand Up @@ -59,7 +58,7 @@ type ServeConfig struct {
// LimitExceeded; it then returns that *Error. Before returning it cancels
// every handler's context and waits for the handlers.
func Serve(parent context.Context, cfg ServeConfig) error {
hello := ServeHello{Version: Version, PeerID: cfg.PeerID, Credential: cfg.Credential, Resource: cfg.Resource, ServerInstanceID: cfg.ServerInstanceID}
hello := ServeHello{Version: Version, Credential: cfg.Credential, Resource: cfg.Resource, ServerInstanceID: cfg.ServerInstanceID}
for _, h := range cfg.Services {
if h.Serve == nil {
return errors.New("sandbox link: service handler without Serve")
Expand Down
5 changes: 2 additions & 3 deletions internal/sandboxlink/testdata/link_v1.hex
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# Link version 1 frames from goldenFrames in protocol_test.go, in order. Hex bytes; text after # is a comment.
# IDs repeat one byte: 01 tenant, 02 environment, 03 resource, 04 peer, 05 server instance, 06 Runtime, 07 attachment, 08 Session, 09 assignment, 0a link.
# IDs repeat one byte: 01 tenant, 02 environment, 03 resource, 05 server instance, 06 Runtime, 07 attachment, 08 Session, 09 assignment, 0a link.

# ServeHello
00000073 0001 0000 0000000000000001 # header: length 115, OpHello, flags, request 1
00000063 0001 0000 0000000000000001 # header: length 99, OpHello, flags, request 1
0001 # Version 1
0001 # Role RoleServe
04040404040404040404040404040404 # PeerID
00000005 7365727665 # Credential "serve"
01010101010101010101010101010101 # Resource.TenantID
02020202020202020202020202020202 # Resource.EnvironmentID
Expand Down
Loading