package peer import ( "io" "net" "net/netip" "sync" "sync/atomic" "time" ) const ( version = 1 bufferSize = 8192 // Enough for data packets and encryption buffers. if_mtu = 1200 if_queue_len = 2048 controlCipherOverhead = 16 dataCipherOverhead = 16 signOverhead = 64 pingInterval = 8 * time.Second timeoutInterval = 30 * time.Second broadcastInterval = 16 * time.Second broadcastErrorTimeoutInterval = 8 * time.Second ) var multicastAddr = net.UDPAddrFromAddrPort(netip.AddrPortFrom( netip.AddrFrom4([4]byte{224, 0, 0, 157}), 4560)) type marshaller interface { Marshal([]byte) []byte } // ---------------------------------------------------------------------------- type Globals struct { LocalConfig // Embed, immutable. // Local public address (if available). Immutable. LocalAddr netip.AddrPort // True if local public address is valid. Immutable. LocalAddrValid bool // All remote peers by VPN IP. RemotePeers [256]*atomic.Pointer[Remote] // Discovered public addresses. PubAddrs *pubAddrStore // Attempts to ensure that we have a relay available. RelayHandler *relayHandler // Send UDP - Global function to write UDP packets. SendUDP func(b []byte, addr netip.AddrPort) (n int, err error) // Global TUN interface. IFace io.ReadWriteCloser } func NewGlobals( localConfig LocalConfig, localAddr netip.AddrPort, conn *net.UDPConn, iface io.ReadWriteCloser, ) (g Globals) { g.LocalConfig = localConfig g.LocalAddr = localAddr g.LocalAddrValid = localAddr.IsValid() g.PubAddrs = newPubAddrStore(localAddr) g.RelayHandler = newRelayHandler() // Use a lock here avoids starvation, at least on my Linux machine. sendLock := sync.Mutex{} g.SendUDP = func(b []byte, addr netip.AddrPort) (int, error) { sendLock.Lock() n, err := conn.WriteToUDPAddrPort(b, addr) sendLock.Unlock() return n, err } g.IFace = iface for i := range g.RemotePeers { g.RemotePeers[i] = &atomic.Pointer[Remote]{} } for i := range g.RemotePeers { g.RemotePeers[i].Store(newRemote(g, byte(i))) } return g }