This repository has been archived by the owner on Mar 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
/
op_whoami.go
135 lines (112 loc) · 3.27 KB
/
op_whoami.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package docks
import (
"time"
"github.com/safing/portbase/container"
"github.com/safing/portbase/formats/dsd"
"github.com/safing/spn/terminal"
)
const (
// WhoAmIType is the type ID of the latency test operation.
WhoAmIType = "whoami"
whoAmITimeout = 3 * time.Second
)
// WhoAmIOp is used to request some metadata about the other side.
type WhoAmIOp struct {
terminal.OneOffOperationBase
response *WhoAmIResponse
}
// WhoAmIResponse is a whoami response.
type WhoAmIResponse struct {
// Timestamp in nanoseconds
Timestamp int64 `cbor:"t,omitempty" json:"t,omitempty"`
// Addr is the remote address as reported by the crane terminal (IP and port).
Addr string `cbor:"a,omitempty" json:"a,omitempty"`
}
// Type returns the type ID.
func (op *WhoAmIOp) Type() string {
return WhoAmIType
}
func init() {
terminal.RegisterOpType(terminal.OperationFactory{
Type: WhoAmIType,
Start: startWhoAmI,
})
}
// WhoAmI executes a whoami operation and returns the response.
func WhoAmI(t terminal.Terminal) (*WhoAmIResponse, *terminal.Error) {
whoami, err := NewWhoAmIOp(t)
if err.IsError() {
return nil, err
}
// Wait for response.
select {
case tErr := <-whoami.Result:
if tErr.IsError() {
return nil, tErr
}
return whoami.response, nil
case <-time.After(whoAmITimeout * 2):
return nil, terminal.ErrTimeout
}
}
// NewWhoAmIOp starts a new whoami operation.
func NewWhoAmIOp(t terminal.Terminal) (*WhoAmIOp, *terminal.Error) {
// Create operation and init.
op := &WhoAmIOp{}
op.OneOffOperationBase.Init()
// Send ping.
tErr := t.StartOperation(op, nil, whoAmITimeout)
if tErr != nil {
return nil, tErr
}
return op, nil
}
// Deliver delivers a message to the operation.
func (op *WhoAmIOp) Deliver(msg *terminal.Msg) *terminal.Error {
defer msg.Finish()
// Parse response.
response := &WhoAmIResponse{}
_, err := dsd.Load(msg.Data.CompileData(), response)
if err != nil {
return terminal.ErrMalformedData.With("failed to parse ping response: %w", err)
}
op.response = response
return terminal.ErrExplicitAck
}
func startWhoAmI(t terminal.Terminal, opID uint32, data *container.Container) (terminal.Operation, *terminal.Error) {
// Get crane terminal, if available.
ct, _ := t.(*CraneTerminal)
// Create response.
r := &WhoAmIResponse{
Timestamp: time.Now().UnixNano(),
}
if ct != nil {
r.Addr = ct.RemoteAddr().String()
}
response, err := dsd.Dump(r, dsd.CBOR)
if err != nil {
return nil, terminal.ErrInternalError.With("failed to create whoami response: %w", err)
}
// Send response.
msg := terminal.NewMsg(response)
msg.FlowID = opID
msg.Unit.MakeHighPriority()
if terminal.UsePriorityDataMsgs {
msg.Type = terminal.MsgTypePriorityData
}
tErr := t.Send(msg, whoAmITimeout)
if tErr != nil {
// Finish message unit on failure.
msg.Finish()
return nil, tErr.With("failed to send ping response")
}
// Operation is just one response and finished successfully.
return nil, nil
}
// HandleStop gives the operation the ability to cleanly shut down.
// The returned error is the error to send to the other side.
// Should never be called directly. Call Stop() instead.
func (op *WhoAmIOp) HandleStop(err *terminal.Error) (errorToSend *terminal.Error) {
// Continue with usual handling of inherited base.
return op.OneOffOperationBase.HandleStop(err)
}