@@ -196,13 +196,13 @@ func readSelfID() string {
196196
197197// readTurnSecret resolves the TURN shared secret in priority order:
198198//
199- // 1. TURN_SHARED_SECRET env (set when using an external coturn whose
200- // static-auth-secret was configured out-of-band — e.g. the Vultr
201- // coordinator path). When this is present it MUST win, because
202- // the local TEE-derived value won't match what coturn is checking
203- // against.
204- // 2. /run/secrets/turn (TEE-derived path; matches the embedded
205- // coordinator's coturn which reads the same file).
199+ // 1. TURN_SHARED_SECRET env (set when using an external coturn whose
200+ // static-auth-secret was configured out-of-band — e.g. the Vultr
201+ // coordinator path). When this is present it MUST win, because
202+ // the local TEE-derived value won't match what coturn is checking
203+ // against.
204+ // 2. /run/secrets/turn (TEE-derived path; matches the embedded
205+ // coordinator's coturn which reads the same file).
206206//
207207// Order matters: env beats file so that "use external coturn" can be
208208// configured purely at the cluster.tf layer.
@@ -515,10 +515,11 @@ func sleepCtx(ctx context.Context, d time.Duration) bool {
515515}
516516
517517// Stream header layout: 3 bytes per stream open.
518- // byte 0 = tag (streamUDP or streamTCP)
519- // bytes 1-2 = receiver-side port (big-endian uint16) — the port number
520- // the receiver itself binds locally; receiver looks it up in its own
521- // Ports list to find the index/protocol slot
518+ //
519+ // byte 0 = tag (streamUDP or streamTCP)
520+ // bytes 1-2 = receiver-side port (big-endian uint16) — the port number
521+ // the receiver itself binds locally; receiver looks it up in its own
522+ // Ports list to find the index/protocol slot
522523const (
523524 streamUDP byte = 0x55 // long-lived per-port UDP datagram pipe
524525 streamTCP byte = 0x33 // per-conn TCP byte-stream forwarder
@@ -633,7 +634,7 @@ func (m *Mesh) dialAndPump(parentCtx context.Context, peer Peer, sess *peerSessi
633634 // mesh-sidecar/entrypoint.sh before mesh-conn starts; failing
634635 // here means the alias didn't get set up.
635636 peerVip := peer .vipAddr ()
636- udpSocks := map [int ]* net.UDPConn {} // port -> listener (only UDP-bearing ports)
637+ udpSocks := map [int ]* net.UDPConn {} // port -> listener (only UDP-bearing ports)
637638 tcpListeners := make ([]* net.TCPListener , 0 , len (cfg .Allowlist ))
638639 for _ , ip := range cfg .Allowlist {
639640 tl , err := net .ListenTCP ("tcp" , & net.TCPAddr {IP : peerVip , Port : ip .Port })
@@ -1212,7 +1213,9 @@ func (m *Mesh) dialICE(remoteID string, sess *peerSession, attemptCtx context.Co
12121213 if c == nil {
12131214 return
12141215 }
1215- publish (cfg , remoteID , "candidate" , c .Marshal ())
1216+ if err := publish (cfg , remoteID , "candidate" , c .Marshal ()); err != nil {
1217+ log .Printf ("[%s] publish candidate: %v" , remoteID , err )
1218+ }
12161219 }); err != nil {
12171220 return nil , err
12181221 }
@@ -1233,7 +1236,9 @@ func (m *Mesh) dialICE(remoteID string, sess *peerSession, attemptCtx context.Co
12331236 if err != nil {
12341237 return nil , err
12351238 }
1236- publish (cfg , remoteID , "auth" , localUfrag + ":" + localPwd )
1239+ if err = publish (cfg , remoteID , "auth" , localUfrag + ":" + localPwd ); err != nil {
1240+ return nil , fmt .Errorf ("publish auth to %s: %w" , remoteID , err )
1241+ }
12371242
12381243 if err = agent .GatherCandidates (); err != nil {
12391244 return nil , err
@@ -1255,18 +1260,25 @@ func (m *Mesh) dialICE(remoteID string, sess *peerSession, attemptCtx context.Co
12551260
12561261 // Wait for remote auth. pollLoop drain-then-pushes the freshest
12571262 // peer auth into sess.authCh independent of state, so by the time
1258- // we wake we always have the latest value. attemptCtx covers the
1259- // case where pollLoop already aborted us mid-wait (peer rolled
1260- // creds again between agent install and now).
1263+ // we wake we always have the latest value. Absence of remote auth
1264+ // means the peer has not started or has not reached signalling yet;
1265+ // there is no stale ICE attempt to tear down until both sides have
1266+ // exchanged credentials. attemptCtx still covers process shutdown
1267+ // and the rare case where pollLoop explicitly aborts this attempt.
12611268 var remote [2 ]string
1262- select {
1263- case remote = <- sess .authCh :
1264- case <- time .After (60 * time .Second ):
1265- err = fmt .Errorf ("timeout waiting for remote auth from %s" , remoteID )
1266- return nil , err
1267- case <- attemptCtx .Done ():
1268- err = fmt .Errorf ("attempt aborted before auth from %s" , remoteID )
1269- return nil , err
1269+ waitLog := time .NewTicker (60 * time .Second )
1270+ defer waitLog .Stop ()
1271+ waitRemoteAuth:
1272+ for {
1273+ select {
1274+ case remote = <- sess .authCh :
1275+ break waitRemoteAuth
1276+ case <- attemptCtx .Done ():
1277+ err = fmt .Errorf ("attempt aborted before auth from %s" , remoteID )
1278+ return nil , err
1279+ case <- waitLog .C :
1280+ log .Printf ("[%s] waiting for remote auth" , remoteID )
1281+ }
12701282 }
12711283
12721284 // Record what we're about to dial against, so pollLoop can detect
@@ -1334,16 +1346,19 @@ type Message struct {
13341346 Data string `json:"data"`
13351347}
13361348
1337- func publish (cfg * Config , to , typ , data string ) {
1349+ func publish (cfg * Config , to , typ , data string ) error {
13381350 body , _ := json .Marshal (Message {From : cfg .SelfID , Type : typ , Data : data })
13391351 resp , err := http .Post (cfg .SignalingURL + "/publish?to=" + url .QueryEscape (to ),
13401352 "application/json" , strings .NewReader (string (body )))
13411353 if err != nil {
1342- log .Printf ("publish err: %v" , err )
1343- return
1354+ return err
1355+ }
1356+ defer resp .Body .Close ()
1357+ respBody , _ := io .ReadAll (io .LimitReader (resp .Body , 4096 ))
1358+ if resp .StatusCode < 200 || resp .StatusCode >= 300 {
1359+ return fmt .Errorf ("%s: %s" , resp .Status , strings .TrimSpace (string (respBody )))
13441360 }
1345- io .Copy (io .Discard , resp .Body )
1346- resp .Body .Close ()
1361+ return nil
13471362}
13481363
13491364func (m * Mesh ) pollLoop (ctx context.Context ) {
0 commit comments