safing-portmaster/spn/docks/terminal_expansion.go
Daniel Hååvi 80664d1a27
Restructure modules ()
* Move portbase into monorepo

* Add new simple module mgr

* [WIP] Switch to new simple module mgr

* Add StateMgr and more worker variants

* [WIP] Switch more modules

* [WIP] Switch more modules

* [WIP] swtich more modules

* [WIP] switch all SPN modules

* [WIP] switch all service modules

* [WIP] Convert all workers to the new module system

* [WIP] add new task system to module manager

* [WIP] Add second take for scheduling workers

* [WIP] Add FIXME for bugs in new scheduler

* [WIP] Add minor improvements to scheduler

* [WIP] Add new worker scheduler

* [WIP] Fix more bug related to new module system

* [WIP] Fix start handing of the new module system

* [WIP] Improve startup process

* [WIP] Fix minor issues

* [WIP] Fix missing subsystem in settings

* [WIP] Initialize managers in constructor

* [WIP] Move module event initialization to constrictors

* [WIP] Fix setting for enabling and disabling the SPN module

* [WIP] Move API registeration into module construction

* [WIP] Update states mgr for all modules

* [WIP] Add CmdLine operation support

* Add state helper methods to module group and instance

* Add notification and module status handling to status package

* Fix starting issues

* Remove pilot widget and update security lock to new status data

* Remove debug logs

* Improve http server shutdown

* Add workaround for cleanly shutting down firewall+netquery

* Improve logging

* Add syncing states with notifications for new module system

* Improve starting, stopping, shutdown; resolve FIXMEs/TODOs

* [WIP] Fix most unit tests

* Review new module system and fix minor issues

* Push shutdown and restart events again via API

* Set sleep mode via interface

* Update example/template module

* [WIP] Fix spn/cabin unit test

* Remove deprecated UI elements

* Make log output more similar for the logging transition phase

* Switch spn hub and observer cmds to new module system

* Fix log sources

* Make worker mgr less error prone

* Fix tests and minor issues

* Fix observation hub

* Improve shutdown and restart handling

* Split up big connection.go source file

* Move varint and dsd packages to structures repo

* Improve expansion test

* Fix linter warnings

* Fix interception module on windows

* Fix linter errors

---------

Co-authored-by: Vladimir Stoilov <vladimir@safing.io>
2024-08-09 18:15:48 +03:00

150 lines
4.3 KiB
Go

package docks
import (
"fmt"
"sync"
"time"
"github.com/tevino/abool"
"github.com/safing/portmaster/spn/hub"
"github.com/safing/portmaster/spn/terminal"
"github.com/safing/structures/container"
)
// ExpansionTerminal is used for expanding to another Hub.
type ExpansionTerminal struct {
*terminal.TerminalBase
relayOp *ExpansionTerminalRelayOp
changeNotifyFuncReady *abool.AtomicBool
changeNotifyFunc func()
reachableChecked time.Time
reachableLock sync.Mutex
}
// ExpansionTerminalRelayOp is the operation that connects to the relay.
type ExpansionTerminalRelayOp struct {
terminal.OperationBase
expansionTerminal *ExpansionTerminal
}
// Type returns the type ID.
func (op *ExpansionTerminalRelayOp) Type() string {
return ExpandOpType
}
// ExpandTo initiates an expansion.
func ExpandTo(from terminal.Terminal, routeTo string, encryptFor *hub.Hub) (*ExpansionTerminal, *terminal.Error) {
// First, create the local endpoint terminal to generate the init data.
// Create options and bare expansion terminal.
opts := terminal.DefaultExpansionTerminalOpts()
opts.Encrypt = encryptFor != nil
expansion := &ExpansionTerminal{
changeNotifyFuncReady: abool.New(),
}
expansion.relayOp = &ExpansionTerminalRelayOp{
expansionTerminal: expansion,
}
// Create base terminal for expansion.
base, initData, tErr := terminal.NewLocalBaseTerminal(
module.mgr.Ctx(),
0, // Ignore; The ID of the operation is used for communication.
from.FmtID(),
encryptFor,
opts,
expansion.relayOp,
)
if tErr != nil {
return nil, tErr.Wrap("failed to create expansion terminal base")
}
expansion.TerminalBase = base
base.SetTerminalExtension(expansion)
base.SetTimeout(defaultTerminalIdleTimeout)
// Second, start the actual relay operation.
// Create setup message for relay operation.
opInitData := container.New()
opInitData.AppendAsBlock([]byte(routeTo))
opInitData.AppendContainer(initData)
// Start relay operation on connected Hub.
tErr = from.StartOperation(expansion.relayOp, opInitData, 5*time.Second)
if tErr != nil {
return nil, tErr.Wrap("failed to start expansion operation")
}
// Start Workers.
base.StartWorkers(module.mgr, "expansion terminal")
return expansion, nil
}
// SetChangeNotifyFunc sets a callback function that is called when the terminal state changes.
func (t *ExpansionTerminal) SetChangeNotifyFunc(f func()) {
if t.changeNotifyFuncReady.IsSet() {
return
}
t.changeNotifyFunc = f
t.changeNotifyFuncReady.Set()
}
// NeedsReachableCheck returns whether the terminal should be checked if it is
// reachable via the existing network internal relayed connection.
func (t *ExpansionTerminal) NeedsReachableCheck(maxCheckAge time.Duration) bool {
t.reachableLock.Lock()
defer t.reachableLock.Unlock()
return time.Since(t.reachableChecked) > maxCheckAge
}
// MarkReachable marks the terminal as reachable via the existing network
// internal relayed connection.
func (t *ExpansionTerminal) MarkReachable() {
t.reachableLock.Lock()
defer t.reachableLock.Unlock()
t.reachableChecked = time.Now()
}
// HandleDestruction gives the terminal the ability to clean up.
// The terminal has already fully shut down at this point.
// Should never be called directly. Call Abandon() instead.
func (t *ExpansionTerminal) HandleDestruction(err *terminal.Error) {
// Trigger update of connected Pin.
if t.changeNotifyFuncReady.IsSet() {
t.changeNotifyFunc()
}
// Stop the relay operation.
// The error message is arlready sent by the terminal.
t.relayOp.Stop(t.relayOp, nil)
}
// CustomIDFormat formats the terminal ID.
func (t *ExpansionTerminal) CustomIDFormat() string {
return fmt.Sprintf("%s~%d", t.relayOp.Terminal().FmtID(), t.relayOp.ID())
}
// Deliver delivers a message to the operation.
func (op *ExpansionTerminalRelayOp) Deliver(msg *terminal.Msg) *terminal.Error {
// Proxy directly to expansion terminal.
return op.expansionTerminal.Deliver(msg)
}
// 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 *ExpansionTerminalRelayOp) HandleStop(err *terminal.Error) (errorToSend *terminal.Error) {
// Stop the expansion terminal.
// The error message will be sent by the operation.
op.expansionTerminal.Abandon(nil)
return err
}