mirror of
https://github.com/Quad4-Software/Reticulum-Go
synced 2026-08-29 23:48:44 -04:00
110 lines
2.4 KiB
Go
110 lines
2.4 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright (c) 2024-2026 Quad4.io
|
|
|
|
// Package backbone provides a process-wide multiplexed I/O hub for high-throughput
|
|
// TCP interfaces (BackboneInterface, local shared instance) using epoll, kqueue,
|
|
// or optional io_uring on Linux.
|
|
package backbone
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"sync"
|
|
)
|
|
|
|
// Backend selects the kernel multiplexing implementation.
|
|
type Backend string
|
|
|
|
const (
|
|
BackendAuto Backend = "auto"
|
|
BackendEpoll Backend = "epoll"
|
|
BackendKqueue Backend = "kqueue"
|
|
BackendUring Backend = "io_uring"
|
|
BackendGo Backend = "go"
|
|
|
|
// streamReadChunk is the hub socket read size. HDLC still splits frames
|
|
// at the packet MTU. Reading more than one MTU per syscall is the
|
|
// fast path for TCP backbone streams.
|
|
streamReadChunk = 64 * 1024
|
|
)
|
|
|
|
var (
|
|
globalHub *Hub
|
|
globalMu sync.Mutex
|
|
)
|
|
|
|
func streamReadSize(mtu int) int {
|
|
if mtu > streamReadChunk {
|
|
return mtu
|
|
}
|
|
return streamReadChunk
|
|
}
|
|
|
|
// ParseBackend normalises a configuration value.
|
|
func ParseBackend(s string) Backend {
|
|
switch Backend(s) {
|
|
case BackendEpoll, BackendKqueue, BackendUring, BackendGo:
|
|
return Backend(s)
|
|
default:
|
|
return BackendAuto
|
|
}
|
|
}
|
|
|
|
// DefaultBackend picks the native multiplexer for the current platform.
|
|
func DefaultBackend() Backend {
|
|
switch runtime.GOOS {
|
|
case "linux", "android":
|
|
return BackendEpoll
|
|
case "darwin", "freebsd", "netbsd", "openbsd":
|
|
return BackendKqueue
|
|
default:
|
|
return BackendGo
|
|
}
|
|
}
|
|
|
|
// Init creates and starts the process-wide I/O hub. Safe to call multiple times.
|
|
// subsequent calls return the existing hub if already initialised.
|
|
func Init(backend Backend) (*Hub, error) {
|
|
globalMu.Lock()
|
|
defer globalMu.Unlock()
|
|
if globalHub != nil {
|
|
return globalHub, nil
|
|
}
|
|
if backend == BackendAuto || backend == "" {
|
|
backend = DefaultBackend()
|
|
}
|
|
h, err := newHub(backend)
|
|
if err != nil {
|
|
if backend == BackendUring {
|
|
h, err = newHub(BackendEpoll)
|
|
if err != nil {
|
|
h, err = newHub(BackendGo)
|
|
}
|
|
} else if backend != BackendGo {
|
|
h, err = newHub(BackendGo)
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("backbone init: %w", err)
|
|
}
|
|
}
|
|
globalHub = h
|
|
return h, nil
|
|
}
|
|
|
|
// Get returns the global hub or nil if Init was not called.
|
|
func Get() *Hub {
|
|
globalMu.Lock()
|
|
defer globalMu.Unlock()
|
|
return globalHub
|
|
}
|
|
|
|
// Shutdown stops and clears the global hub.
|
|
func Shutdown() {
|
|
globalMu.Lock()
|
|
h := globalHub
|
|
globalHub = nil
|
|
globalMu.Unlock()
|
|
if h != nil {
|
|
h.Close()
|
|
}
|
|
}
|