0.2.8
This commit is contained in:
@@ -93,16 +93,19 @@ func New(dest *identity.Identity, appData []byte, pathResponse bool) (*Announce,
|
||||
func (a *Announce) Propagate(interfaces []common.NetworkInterface) error {
|
||||
packet := a.CreatePacket()
|
||||
|
||||
log.Printf("Propagating announce:")
|
||||
// Enhanced logging
|
||||
log.Printf("Creating announce packet:")
|
||||
log.Printf(" Destination Hash: %x", a.destinationHash)
|
||||
log.Printf(" Public Key: %x", a.identity.GetPublicKey())
|
||||
log.Printf(" Identity Public Key: %x", a.identity.GetPublicKey())
|
||||
log.Printf(" App Data: %s", string(a.appData))
|
||||
log.Printf(" Packet Size: %d bytes", len(packet))
|
||||
log.Printf(" Full Packet: %x", packet)
|
||||
log.Printf(" Signature: %x", a.signature)
|
||||
log.Printf(" Total Packet Size: %d bytes", len(packet))
|
||||
log.Printf(" Raw Packet: %x", packet)
|
||||
|
||||
// Propagate to interfaces
|
||||
for _, iface := range interfaces {
|
||||
log.Printf("Propagating on interface %s (%s):", iface.GetName(), iface.GetType())
|
||||
log.Printf("Propagating on interface %s:", iface.GetName())
|
||||
log.Printf(" Interface Type: %s", iface.GetType())
|
||||
log.Printf(" MTU: %d bytes", iface.GetMTU())
|
||||
|
||||
if err := iface.Send(packet, ""); err != nil {
|
||||
@@ -136,18 +139,28 @@ func (a *Announce) HandleAnnounce(data []byte) error {
|
||||
a.mutex.Lock()
|
||||
defer a.mutex.Unlock()
|
||||
|
||||
// Enhanced validation logging
|
||||
log.Printf("Received announce data (%d bytes):", len(data))
|
||||
log.Printf(" Raw Data: %x", data)
|
||||
|
||||
// Validate announce data
|
||||
if len(data) < 16+32+1 { // Min size: hash + pubkey + hops
|
||||
log.Printf(" Error: Invalid announce data length (got %d, need at least %d)",
|
||||
len(data), 16+32+1)
|
||||
return errors.New("invalid announce data")
|
||||
}
|
||||
|
||||
// Extract fields
|
||||
// Extract and log fields
|
||||
destHash := data[:16]
|
||||
publicKey := data[16:48]
|
||||
hopCount := data[48]
|
||||
|
||||
// Validate hop count
|
||||
log.Printf(" Destination Hash: %x", destHash)
|
||||
log.Printf(" Public Key: %x", publicKey)
|
||||
log.Printf(" Hop Count: %d", hopCount)
|
||||
|
||||
if hopCount > MAX_HOPS {
|
||||
log.Printf(" Error: Exceeded maximum hop count (%d > %d)", hopCount, MAX_HOPS)
|
||||
return errors.New("announce exceeded maximum hop count")
|
||||
}
|
||||
|
||||
@@ -155,27 +168,36 @@ func (a *Announce) HandleAnnounce(data []byte) error {
|
||||
appData := data[49 : len(data)-64]
|
||||
signature := data[len(data)-64:]
|
||||
|
||||
log.Printf(" App Data (%d bytes): %s", len(appData), string(appData))
|
||||
log.Printf(" Signature: %x", signature)
|
||||
|
||||
// Create announced identity from public key
|
||||
announcedIdentity := identity.FromPublicKey(publicKey)
|
||||
if announcedIdentity == nil {
|
||||
log.Printf(" Error: Invalid identity public key")
|
||||
return errors.New("invalid identity public key")
|
||||
}
|
||||
|
||||
// Verify signature
|
||||
signData := append(destHash, appData...)
|
||||
if !announcedIdentity.Verify(signData, signature) {
|
||||
log.Printf(" Error: Invalid announce signature")
|
||||
return errors.New("invalid announce signature")
|
||||
}
|
||||
|
||||
log.Printf(" Signature verification successful")
|
||||
|
||||
// Process announce with registered handlers
|
||||
for _, handler := range a.handlers {
|
||||
if handler.ReceivePathResponses() || !a.pathResponse {
|
||||
if err := handler.ReceivedAnnounce(destHash, announcedIdentity, appData); err != nil {
|
||||
log.Printf(" Handler error: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf(" Successfully processed announce")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -9,17 +9,18 @@ type ConfigProvider interface {
|
||||
|
||||
// InterfaceConfig represents interface configuration
|
||||
type InterfaceConfig struct {
|
||||
Type string `toml:"type"`
|
||||
Name string `toml:"name"`
|
||||
Enabled bool `toml:"enabled"`
|
||||
TargetHost string `toml:"target_host,omitempty"`
|
||||
TargetPort int `toml:"target_port,omitempty"`
|
||||
Interface string `toml:"interface,omitempty"`
|
||||
Address string `toml:"address,omitempty"`
|
||||
Port int `toml:"port,omitempty"`
|
||||
KISSFraming bool `toml:"kiss_framing,omitempty"`
|
||||
I2PTunneled bool `toml:"i2p_tunneled,omitempty"`
|
||||
PreferIPv6 bool `toml:"prefer_ipv6,omitempty"`
|
||||
Name string `toml:"name"`
|
||||
Type string `toml:"type"`
|
||||
Enabled bool `toml:"enabled"`
|
||||
Address string `toml:"address"`
|
||||
Port int `toml:"port"`
|
||||
TargetHost string `toml:"target_host"`
|
||||
TargetPort int `toml:"target_port"`
|
||||
TargetAddress string `toml:"target_address"`
|
||||
Interface string `toml:"interface"`
|
||||
KISSFraming bool `toml:"kiss_framing"`
|
||||
I2PTunneled bool `toml:"i2p_tunneled"`
|
||||
PreferIPv6 bool `toml:"prefer_ipv6"`
|
||||
}
|
||||
|
||||
// ReticulumConfig represents the main configuration structure
|
||||
|
||||
@@ -15,6 +15,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"encoding/hex"
|
||||
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
@@ -448,19 +450,19 @@ func (i *Identity) DecryptWithHMAC(data []byte, key []byte) ([]byte, error) {
|
||||
|
||||
func (i *Identity) ToFile(path string) error {
|
||||
data := map[string]interface{}{
|
||||
"private_key": i.privateKey,
|
||||
"public_key": i.publicKey,
|
||||
"signing_key": i.signingKey,
|
||||
"private_key": i.privateKey,
|
||||
"public_key": i.publicKey,
|
||||
"signing_key": i.signingKey,
|
||||
"verification_key": i.verificationKey,
|
||||
"app_data": i.appData,
|
||||
"app_data": i.appData,
|
||||
}
|
||||
|
||||
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
|
||||
return json.NewEncoder(file).Encode(data)
|
||||
}
|
||||
|
||||
@@ -470,22 +472,30 @@ func RecallIdentity(path string) (*Identity, error) {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
|
||||
var data map[string]interface{}
|
||||
if err := json.NewDecoder(file).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
// Reconstruct identity from saved data
|
||||
id := &Identity{
|
||||
privateKey: data["private_key"].([]byte),
|
||||
publicKey: data["public_key"].([]byte),
|
||||
signingKey: data["signing_key"].(ed25519.PrivateKey),
|
||||
privateKey: data["private_key"].([]byte),
|
||||
publicKey: data["public_key"].([]byte),
|
||||
signingKey: data["signing_key"].(ed25519.PrivateKey),
|
||||
verificationKey: data["verification_key"].(ed25519.PublicKey),
|
||||
appData: data["app_data"].([]byte),
|
||||
ratchets: make(map[string][]byte),
|
||||
ratchetExpiry: make(map[string]int64),
|
||||
appData: data["app_data"].([]byte),
|
||||
ratchets: make(map[string][]byte),
|
||||
ratchetExpiry: make(map[string]int64),
|
||||
}
|
||||
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func HashFromString(hash string) ([]byte, error) {
|
||||
if len(hash) != 32 {
|
||||
return nil, fmt.Errorf("invalid hash length: expected 32, got %d", len(hash))
|
||||
}
|
||||
|
||||
return hex.DecodeString(hash)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,10 @@ type Interface interface {
|
||||
GetMode() common.InterfaceMode
|
||||
IsOnline() bool
|
||||
IsDetached() bool
|
||||
IsEnabled() bool
|
||||
Detach()
|
||||
Enable()
|
||||
Disable()
|
||||
Send(data []byte, addr string) error
|
||||
SetPacketCallback(common.PacketCallback)
|
||||
GetPacketCallback() common.PacketCallback
|
||||
@@ -33,12 +36,25 @@ type BaseInterface struct {
|
||||
mode common.InterfaceMode
|
||||
ifType common.InterfaceType
|
||||
online bool
|
||||
enabled bool
|
||||
detached bool
|
||||
mtu int
|
||||
mutex sync.RWMutex
|
||||
packetCallback common.PacketCallback
|
||||
}
|
||||
|
||||
func NewBaseInterface(name string, ifType common.InterfaceType, enabled bool) BaseInterface {
|
||||
return BaseInterface{
|
||||
name: name,
|
||||
mode: common.IF_MODE_FULL,
|
||||
ifType: ifType,
|
||||
online: false,
|
||||
enabled: enabled,
|
||||
detached: false,
|
||||
mtu: common.DEFAULT_MTU,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *BaseInterface) SetPacketCallback(callback common.PacketCallback) {
|
||||
i.Mutex.Lock()
|
||||
defer i.Mutex.Unlock()
|
||||
@@ -136,5 +152,21 @@ func (i *BaseInterface) GetConn() net.Conn {
|
||||
}
|
||||
|
||||
func (i *BaseInterface) IsEnabled() bool {
|
||||
return i.Online && !i.Detached
|
||||
i.mutex.RLock()
|
||||
defer i.mutex.RUnlock()
|
||||
return i.enabled && i.online && !i.detached
|
||||
}
|
||||
|
||||
func (i *BaseInterface) Enable() {
|
||||
i.mutex.Lock()
|
||||
defer i.mutex.Unlock()
|
||||
i.enabled = true
|
||||
i.online = true
|
||||
}
|
||||
|
||||
func (i *BaseInterface) Disable() {
|
||||
i.mutex.Lock()
|
||||
defer i.mutex.Unlock()
|
||||
i.enabled = false
|
||||
i.online = false
|
||||
}
|
||||
|
||||
@@ -44,85 +44,56 @@ type TCPClientInterface struct {
|
||||
packetCallback common.PacketCallback
|
||||
mutex sync.RWMutex
|
||||
detached bool
|
||||
enabled bool
|
||||
}
|
||||
|
||||
func NewTCPClient(name string, targetAddr string, targetPort int, kissFraming bool, i2pTunneled bool) (*TCPClientInterface, error) {
|
||||
func NewTCPClient(name string, targetHost string, targetPort int, kissFraming bool, i2pTunneled bool, enabled bool) (*TCPClientInterface, error) {
|
||||
tc := &TCPClientInterface{
|
||||
BaseInterface: BaseInterface{
|
||||
name: name,
|
||||
mode: common.IF_MODE_FULL,
|
||||
ifType: common.IF_TYPE_TCP,
|
||||
online: false,
|
||||
mtu: 1064,
|
||||
detached: false,
|
||||
},
|
||||
targetAddr: targetAddr,
|
||||
targetPort: targetPort,
|
||||
kissFraming: kissFraming,
|
||||
i2pTunneled: i2pTunneled,
|
||||
initiator: true,
|
||||
BaseInterface: NewBaseInterface(name, common.IF_TYPE_TCP, enabled),
|
||||
targetAddr: targetHost,
|
||||
targetPort: targetPort,
|
||||
kissFraming: kissFraming,
|
||||
i2pTunneled: i2pTunneled,
|
||||
initiator: true,
|
||||
enabled: enabled,
|
||||
}
|
||||
|
||||
if err := tc.connect(true); err != nil {
|
||||
go tc.reconnect()
|
||||
} else {
|
||||
go tc.readLoop()
|
||||
if enabled {
|
||||
addr := fmt.Sprintf("%s:%d", targetHost, targetPort)
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tc.conn = conn
|
||||
tc.online = true
|
||||
}
|
||||
|
||||
return tc, nil
|
||||
}
|
||||
|
||||
func (tc *TCPClientInterface) connect(initial bool) error {
|
||||
func (tc *TCPClientInterface) Start() error {
|
||||
tc.mutex.Lock()
|
||||
defer tc.mutex.Unlock()
|
||||
|
||||
if !tc.enabled {
|
||||
return fmt.Errorf("interface not enabled")
|
||||
}
|
||||
|
||||
if tc.conn != nil {
|
||||
tc.online = true
|
||||
return nil
|
||||
}
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", tc.targetAddr, tc.targetPort)
|
||||
conn, err := net.DialTimeout("tcp", addr, time.Second*INITIAL_TIMEOUT)
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
if initial {
|
||||
return fmt.Errorf("initial connection failed: %v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
tc.conn = conn
|
||||
tc.Online = true
|
||||
tc.writing = false
|
||||
tc.neverConnected = false
|
||||
|
||||
// Set TCP options
|
||||
if tcpConn, ok := conn.(*net.TCPConn); ok {
|
||||
tcpConn.SetNoDelay(true)
|
||||
tcpConn.SetKeepAlive(true)
|
||||
tcpConn.SetKeepAlivePeriod(time.Second * TCP_PROBE_INTERVAL)
|
||||
}
|
||||
|
||||
tc.online = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tc *TCPClientInterface) reconnect() {
|
||||
if tc.initiator && !tc.reconnecting {
|
||||
tc.reconnecting = true
|
||||
attempts := 0
|
||||
|
||||
for !tc.Online {
|
||||
time.Sleep(time.Second * RECONNECT_WAIT)
|
||||
attempts++
|
||||
|
||||
if tc.maxReconnectTries > 0 && attempts > tc.maxReconnectTries {
|
||||
tc.teardown()
|
||||
break
|
||||
}
|
||||
|
||||
if err := tc.connect(false); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
go tc.readLoop()
|
||||
break
|
||||
}
|
||||
|
||||
tc.reconnecting = false
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *TCPClientInterface) readLoop() {
|
||||
buffer := make([]byte, tc.MTU)
|
||||
inFrame := false
|
||||
@@ -281,7 +252,9 @@ func (tc *TCPClientInterface) SetPacketCallback(cb common.PacketCallback) {
|
||||
}
|
||||
|
||||
func (tc *TCPClientInterface) IsEnabled() bool {
|
||||
return tc.Online
|
||||
tc.mutex.RLock()
|
||||
defer tc.mutex.RUnlock()
|
||||
return tc.enabled && tc.online && !tc.detached
|
||||
}
|
||||
|
||||
func (tc *TCPClientInterface) GetName() string {
|
||||
@@ -306,17 +279,68 @@ func (tc *TCPClientInterface) IsOnline() bool {
|
||||
return tc.online
|
||||
}
|
||||
|
||||
func (tc *TCPClientInterface) reconnect() {
|
||||
tc.mutex.Lock()
|
||||
if tc.reconnecting {
|
||||
tc.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
tc.reconnecting = true
|
||||
tc.mutex.Unlock()
|
||||
|
||||
retries := 0
|
||||
for retries < tc.maxReconnectTries {
|
||||
tc.teardown()
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", tc.targetAddr, tc.targetPort)
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err == nil {
|
||||
tc.mutex.Lock()
|
||||
tc.conn = conn
|
||||
tc.online = true
|
||||
tc.neverConnected = false
|
||||
tc.reconnecting = false
|
||||
tc.mutex.Unlock()
|
||||
|
||||
// Restart read loop
|
||||
go tc.readLoop()
|
||||
return
|
||||
}
|
||||
|
||||
retries++
|
||||
// Wait before retrying
|
||||
select {
|
||||
case <-time.After(RECONNECT_WAIT * time.Second):
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Failed to reconnect after max retries
|
||||
tc.mutex.Lock()
|
||||
tc.reconnecting = false
|
||||
tc.mutex.Unlock()
|
||||
tc.teardown()
|
||||
}
|
||||
|
||||
func (tc *TCPClientInterface) Enable() {
|
||||
tc.mutex.Lock()
|
||||
defer tc.mutex.Unlock()
|
||||
tc.online = true
|
||||
}
|
||||
|
||||
func (tc *TCPClientInterface) Disable() {
|
||||
tc.mutex.Lock()
|
||||
defer tc.mutex.Unlock()
|
||||
tc.online = false
|
||||
}
|
||||
|
||||
type TCPServerInterface struct {
|
||||
BaseInterface
|
||||
listener net.Listener
|
||||
connections map[string]net.Conn
|
||||
mutex sync.RWMutex
|
||||
bindAddr string
|
||||
bindPort int
|
||||
preferIPv6 bool
|
||||
spawned bool
|
||||
port int
|
||||
host string
|
||||
kissFraming bool
|
||||
i2pTunneled bool
|
||||
packetCallback common.PacketCallback
|
||||
@@ -387,3 +411,15 @@ func (ts *TCPServerInterface) IsOnline() bool {
|
||||
defer ts.mutex.RUnlock()
|
||||
return ts.online
|
||||
}
|
||||
|
||||
func (ts *TCPServerInterface) Enable() {
|
||||
ts.mutex.Lock()
|
||||
defer ts.mutex.Unlock()
|
||||
ts.online = true
|
||||
}
|
||||
|
||||
func (ts *TCPServerInterface) Disable() {
|
||||
ts.mutex.Lock()
|
||||
defer ts.mutex.Unlock()
|
||||
ts.online = false
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package interfaces
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
@@ -19,9 +20,10 @@ type UDPInterface struct {
|
||||
rxBytes uint64
|
||||
mtu int
|
||||
bitrate int
|
||||
enabled bool
|
||||
}
|
||||
|
||||
func NewUDPInterface(name string, addr string, target string) (*UDPInterface, error) {
|
||||
func NewUDPInterface(name string, addr string, target string, enabled bool) (*UDPInterface, error) {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -36,17 +38,12 @@ func NewUDPInterface(name string, addr string, target string) (*UDPInterface, er
|
||||
}
|
||||
|
||||
ui := &UDPInterface{
|
||||
BaseInterface: BaseInterface{
|
||||
name: name,
|
||||
mode: common.IF_MODE_FULL,
|
||||
ifType: common.IF_TYPE_UDP,
|
||||
online: false,
|
||||
mtu: common.DEFAULT_MTU,
|
||||
detached: false,
|
||||
},
|
||||
addr: udpAddr,
|
||||
targetAddr: targetAddr,
|
||||
readBuffer: make([]byte, common.DEFAULT_MTU),
|
||||
BaseInterface: NewBaseInterface(name, common.IF_TYPE_UDP, enabled),
|
||||
addr: udpAddr,
|
||||
targetAddr: targetAddr,
|
||||
readBuffer: make([]byte, common.DEFAULT_MTU),
|
||||
mtu: common.DEFAULT_MTU,
|
||||
enabled: enabled,
|
||||
}
|
||||
|
||||
return ui, nil
|
||||
@@ -86,29 +83,16 @@ func (ui *UDPInterface) Detach() {
|
||||
}
|
||||
|
||||
func (ui *UDPInterface) Send(data []byte, addr string) error {
|
||||
if !ui.IsOnline() {
|
||||
return fmt.Errorf("interface offline")
|
||||
if !ui.IsEnabled() {
|
||||
return fmt.Errorf("interface not enabled")
|
||||
}
|
||||
|
||||
targetAddr := ui.targetAddr
|
||||
if addr != "" {
|
||||
var err error
|
||||
targetAddr, err = net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid target address: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if targetAddr == nil {
|
||||
if ui.targetAddr == nil {
|
||||
return fmt.Errorf("no target address configured")
|
||||
}
|
||||
|
||||
_, err := ui.conn.WriteToUDP(data, targetAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("UDP write failed: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := ui.conn.WriteTo(data, ui.targetAddr)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ui *UDPInterface) SetPacketCallback(callback common.PacketCallback) {
|
||||
@@ -173,3 +157,58 @@ func (ui *UDPInterface) GetMTU() int {
|
||||
func (ui *UDPInterface) GetBitrate() int {
|
||||
return ui.bitrate
|
||||
}
|
||||
|
||||
func (ui *UDPInterface) Enable() {
|
||||
ui.mutex.Lock()
|
||||
defer ui.mutex.Unlock()
|
||||
ui.online = true
|
||||
}
|
||||
|
||||
func (ui *UDPInterface) Disable() {
|
||||
ui.mutex.Lock()
|
||||
defer ui.mutex.Unlock()
|
||||
ui.online = false
|
||||
}
|
||||
|
||||
func (ui *UDPInterface) Start() error {
|
||||
conn, err := net.ListenUDP("udp", ui.addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ui.conn = conn
|
||||
ui.online = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ui *UDPInterface) readLoop() {
|
||||
buffer := make([]byte, ui.mtu)
|
||||
for {
|
||||
if ui.IsDetached() {
|
||||
return
|
||||
}
|
||||
|
||||
n, addr, err := ui.conn.ReadFromUDP(buffer)
|
||||
if err != nil {
|
||||
if !ui.IsDetached() {
|
||||
log.Printf("UDP read error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ui.mutex.Lock()
|
||||
ui.rxBytes += uint64(n)
|
||||
ui.mutex.Unlock()
|
||||
|
||||
log.Printf("Received %d bytes from %s", n, addr.String())
|
||||
|
||||
if callback := ui.GetPacketCallback(); callback != nil {
|
||||
callback(buffer[:n], ui)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *UDPInterface) IsEnabled() bool {
|
||||
ui.mutex.RLock()
|
||||
defer ui.mutex.RUnlock()
|
||||
return ui.enabled && ui.online && !ui.detached
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ type Transport struct {
|
||||
mutex sync.RWMutex
|
||||
handlerLock sync.RWMutex
|
||||
pathLock sync.RWMutex
|
||||
links map[string]*Link
|
||||
}
|
||||
|
||||
func NewTransport(config *common.ReticulumConfig) (*Transport, error) {
|
||||
@@ -61,6 +62,7 @@ func NewTransport(config *common.ReticulumConfig) (*Transport, error) {
|
||||
config: config,
|
||||
interfaces: make(map[string]common.NetworkInterface),
|
||||
paths: make(map[string]*common.Path),
|
||||
links: make(map[string]*Link),
|
||||
}
|
||||
|
||||
transportMutex.Lock()
|
||||
@@ -126,6 +128,8 @@ type Link struct {
|
||||
packetCb func([]byte)
|
||||
resourceCb func(interface{}) bool
|
||||
resourceStrategy int
|
||||
connectedCb func()
|
||||
disconnectedCb func()
|
||||
}
|
||||
|
||||
type Destination struct {
|
||||
@@ -183,6 +187,9 @@ func (l *Link) SetResourceCallback(cb func(interface{}) bool) {
|
||||
}
|
||||
|
||||
func (l *Link) Teardown() {
|
||||
if l.disconnectedCb != nil {
|
||||
l.disconnectedCb()
|
||||
}
|
||||
if l.closedCb != nil {
|
||||
l.closedCb()
|
||||
}
|
||||
@@ -206,7 +213,9 @@ func (l *Link) Send(data []byte) error {
|
||||
}
|
||||
|
||||
type AnnounceHandler interface {
|
||||
ReceivedAnnounce(destinationHash []byte, identity interface{}, appData []byte)
|
||||
AspectFilter() []string
|
||||
ReceivedAnnounce(destinationHash []byte, announcedIdentity interface{}, appData []byte) error
|
||||
ReceivePathResponses() bool
|
||||
}
|
||||
|
||||
func (t *Transport) RegisterAnnounceHandler(handler AnnounceHandler) {
|
||||
@@ -630,3 +639,33 @@ func (t *Transport) SendPacket(p *packet.Packet) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) GetLink(destHash []byte) (*Link, error) {
|
||||
t.mutex.RLock()
|
||||
defer t.mutex.RUnlock()
|
||||
|
||||
link, exists := t.links[string(destHash)]
|
||||
if !exists {
|
||||
// Create new link if it doesn't exist
|
||||
link = NewLink(
|
||||
destHash,
|
||||
nil, // established callback
|
||||
nil, // closed callback
|
||||
)
|
||||
t.links[string(destHash)] = link
|
||||
}
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
func (l *Link) OnConnected(cb func()) {
|
||||
l.connectedCb = cb
|
||||
// If already established, trigger callback immediately
|
||||
if !l.establishedAt.IsZero() && cb != nil {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Link) OnDisconnected(cb func()) {
|
||||
l.disconnectedCb = cb
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user