This repository has been archived by the owner on Mar 29, 2024. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
161 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package docks | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/safing/spn/terminal" | ||
) | ||
|
||
func TestWhoAmIOp(t *testing.T) { | ||
t.Parallel() | ||
|
||
// Create test terminal pair. | ||
a, _, err := terminal.NewSimpleTestTerminalPair(0, 0, nil) | ||
if err != nil { | ||
t.Fatalf("failed to create test terminal pair: %s", err) | ||
} | ||
|
||
// Run op. | ||
resp, tErr := WhoAmI(a) | ||
if tErr.IsError() { | ||
t.Fatal(tErr) | ||
} | ||
t.Logf("whoami: %+v", resp) | ||
} |