|  |  |  | @@ -16,14 +16,11 @@ type peerState interface { | 
		
	
		
			
				|  |  |  |  | 	OnSynAck(netip.AddrPort, synAckPacket) peerState | 
		
	
		
			
				|  |  |  |  | 	OnAck(netip.AddrPort, ackPacket) peerState | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// When the peer is updated, we reset. Handled by base state. | 
		
	
		
			
				|  |  |  |  | 	OnPeerUpdate(*m.Peer) peerState | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// To determe up / dataCipher. Handled by base state. | 
		
	
		
			
				|  |  |  |  | 	OnPing(netip.AddrPort, pingPacket) peerState | 
		
	
		
			
				|  |  |  |  | 	OnPong(netip.AddrPort, pongPacket) peerState | 
		
	
		
			
				|  |  |  |  | 	OnPingTimer() peerState | 
		
	
		
			
				|  |  |  |  | 	OnTimeoutTimer() peerState | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// When the peer is updated, we reset. Handled by base state. | 
		
	
		
			
				|  |  |  |  | 	OnPeerUpdate(*m.Peer) peerState | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ---------------------------------------------------------------------------- | 
		
	
	
		
			
				
					
					|  |  |  | @@ -82,37 +79,39 @@ func (s *stateBase) selectStateFromPeer(peer *m.Peer) peerState { | 
		
	
		
			
				|  |  |  |  | 	if peer == nil { | 
		
	
		
			
				|  |  |  |  | 		return newStateNoPeer(s) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s.staged.controlCipher = newControlCipher(s.privKey, peer.EncPubKey) | 
		
	
		
			
				|  |  |  |  | 	s.staged.dataCipher = newDataCipher() | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s.resetPingTimer() | 
		
	
		
			
				|  |  |  |  | 	s.resetTimeoutTimer() | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	ip, isValid := netip.AddrFromSlice(peer.PublicIP) | 
		
	
		
			
				|  |  |  |  | 	if isValid { | 
		
	
		
			
				|  |  |  |  | 		s.remotePub = true | 
		
	
		
			
				|  |  |  |  | 		s.staged.remoteAddr = netip.AddrPortFrom(ip, peer.Port) | 
		
	
		
			
				|  |  |  |  | 		s.staged.relay = peer.Mediator | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if s.localPub && s.localIP < s.remoteIP { | 
		
	
		
			
				|  |  |  |  | 			return newStateServer(s) | 
		
	
		
			
				|  |  |  |  | 	if s.remotePub == s.localPub { | 
		
	
		
			
				|  |  |  |  | 		if s.localIP < s.remoteIP { | 
		
	
		
			
				|  |  |  |  | 			return newStateServer2(s) | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		return newStateClient(s) | 
		
	
		
			
				|  |  |  |  | 		return newStateDialLocal(s) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if s.localPub { | 
		
	
		
			
				|  |  |  |  | 		return newStateServer(s) | 
		
	
		
			
				|  |  |  |  | 	if s.remotePub { | 
		
	
		
			
				|  |  |  |  | 		return newStateDialLocal(s) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return newStateSelectRelay(s) | 
		
	
		
			
				|  |  |  |  | 	return newStateServer2(s) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) OnSyn(rAddr netip.AddrPort, p synPacket) peerState       { return nil } | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) OnSynAck(rAddr netip.AddrPort, p synAckPacket) peerState { return nil } | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) OnAck(rAddr netip.AddrPort, p ackPacket) peerState       { return nil } | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) OnPing(rAddr netip.AddrPort, p pingPacket) peerState     { return nil } | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) OnPong(rAddr netip.AddrPort, p pongPacket) peerState     { return nil } | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) OnPingTimer() peerState                                  { return nil } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) OnTimeoutTimer() peerState { | 
		
	
		
			
				|  |  |  |  | 	return s.selectStateFromPeer(s.peer) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) OnPingTimer() peerState    { return nil } | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) OnTimeoutTimer() peerState { return nil } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // Helpers. | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -144,14 +143,6 @@ func (s *stateBase) selectRelay() byte { | 
		
	
		
			
				|  |  |  |  | 	return possible[rand.Intn(len(possible))] | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) sendPing(sharedKey [32]byte) { | 
		
	
		
			
				|  |  |  |  | 	s.sendControlPacket(newPingPacket(sharedKey)) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) sendPong(ping pingPacket) { | 
		
	
		
			
				|  |  |  |  | 	s.sendControlPacket(newPongPacket(ping.SentAt)) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateBase) sendControlPacket(pkt interface{ Marshal([]byte) []byte }) { | 
		
	
		
			
				|  |  |  |  | 	buf := pkt.Marshal(s.buf) | 
		
	
		
			
				|  |  |  |  | 	h := header{ | 
		
	
	
		
			
				
					
					|  |  |  | @@ -183,6 +174,117 @@ func newStateNoPeer(b *stateBase) *stateNoPeer { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ---------------------------------------------------------------------------- | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | type stateServer2 struct { | 
		
	
		
			
				|  |  |  |  | 	*stateBase | 
		
	
		
			
				|  |  |  |  | 	syn              synPacket | 
		
	
		
			
				|  |  |  |  | 	publishedTraceID uint64 | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // TODO: Server should send SynAck packets on a loop. | 
		
	
		
			
				|  |  |  |  | func newStateServer2(b *stateBase) peerState { | 
		
	
		
			
				|  |  |  |  | 	s := &stateServer2{stateBase: b} | 
		
	
		
			
				|  |  |  |  | 	s.resetTimeoutTimer() | 
		
	
		
			
				|  |  |  |  | 	return s | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateServer2) Name() string { return "server" } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateServer2) OnSyn(remoteAddr netip.AddrPort, p synPacket) peerState { | 
		
	
		
			
				|  |  |  |  | 	s.syn = p | 
		
	
		
			
				|  |  |  |  | 	s.sendControlPacket(newSynAckPacket(p.TraceID)) | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateServer2) OnAck(remoteAddr netip.AddrPort, p ackPacket) peerState { | 
		
	
		
			
				|  |  |  |  | 	if p.TraceID != s.syn.TraceID { | 
		
	
		
			
				|  |  |  |  | 		return nil | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s.resetTimeoutTimer() | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if p.TraceID == s.publishedTraceID { | 
		
	
		
			
				|  |  |  |  | 		return nil | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// Pubish staged | 
		
	
		
			
				|  |  |  |  | 	s.staged.remoteAddr = remoteAddr | 
		
	
		
			
				|  |  |  |  | 	s.staged.dataCipher = newDataCipherFromKey(s.syn.SharedKey) | 
		
	
		
			
				|  |  |  |  | 	s.staged.relayIP = s.syn.RelayIP | 
		
	
		
			
				|  |  |  |  | 	s.staged.up = true | 
		
	
		
			
				|  |  |  |  | 	s.publish() | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s.publishedTraceID = p.TraceID | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateServer) OnTimeoutTimer() peerState { | 
		
	
		
			
				|  |  |  |  | 	// TODO: We're down. | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ---------------------------------------------------------------------------- | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | type stateDialLocal struct { | 
		
	
		
			
				|  |  |  |  | 	*stateBase | 
		
	
		
			
				|  |  |  |  | 	syn synPacket | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func newStateDialLocal(b *stateBase) peerState { | 
		
	
		
			
				|  |  |  |  | 	// s := stateDialLocal{stateBase: b} | 
		
	
		
			
				|  |  |  |  | 	// TODO: check for peer local address. | 
		
	
		
			
				|  |  |  |  | 	return newStateDialDirect(b) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateDialLocal) Name() string { return "dial-local" } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ---------------------------------------------------------------------------- | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | type stateDialDirect struct { | 
		
	
		
			
				|  |  |  |  | 	*stateBase | 
		
	
		
			
				|  |  |  |  | 	syn synPacket | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func newStateDialDirect(b *stateBase) peerState { | 
		
	
		
			
				|  |  |  |  | 	// If we don't have an address, dial via relay. | 
		
	
		
			
				|  |  |  |  | 	if b.staged.remoteAddr == zeroAddrPort { | 
		
	
		
			
				|  |  |  |  | 		return newStateNoPeer(b) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s := &stateDialDirect{stateBase: b} | 
		
	
		
			
				|  |  |  |  | 	s.syn = synPacket{ | 
		
	
		
			
				|  |  |  |  | 		TraceID:    newTraceID(), | 
		
	
		
			
				|  |  |  |  | 		SharedKey:  s.staged.dataCipher.Key(), | 
		
	
		
			
				|  |  |  |  | 		ServerAddr: b.staged.remoteAddr, | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s.sendControlPacket(s.syn) | 
		
	
		
			
				|  |  |  |  | 	s.resetTimeoutTimer() | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return s | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateDialDirect) Name() string { return "dial-direct" } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateDialDirect) OnSynAck(remoteAddr netip.AddrPort, p synAckPacket) peerState { | 
		
	
		
			
				|  |  |  |  | 	if p.TraceID != s.syn.TraceID { | 
		
	
		
			
				|  |  |  |  | 		// Hmm... | 
		
	
		
			
				|  |  |  |  | 		return nil | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s.sendControlPacket(ackPacket{TraceID: s.syn.TraceID}) | 
		
	
		
			
				|  |  |  |  | 	s.logf("GOT SYN-ACK! TODO!") | 
		
	
		
			
				|  |  |  |  | 	// client should continue to respond to synAck packets from server. | 
		
	
		
			
				|  |  |  |  | 	// return newStateClientConnected(s.stateBase, s.syn.TraceID) ... | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateDialDirect) OnTimeoutTimer() peerState { | 
		
	
		
			
				|  |  |  |  | 	s.logf("Timeout when dialing") | 
		
	
		
			
				|  |  |  |  | 	return newStateDialLocal(s.stateBase) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ---------------------------------------------------------------------------- | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | type stateClient struct { | 
		
	
		
			
				|  |  |  |  | 	sharedKey [32]byte | 
		
	
		
			
				|  |  |  |  | 	*stateBase | 
		
	
	
		
			
				
					
					|  |  |  | @@ -195,7 +297,7 @@ func newStateClient(b *stateBase) peerState { | 
		
	
		
			
				|  |  |  |  | 	s.staged.dataCipher = newDataCipher() | 
		
	
		
			
				|  |  |  |  | 	s.sharedKey = s.staged.dataCipher.Key() | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s.sendPing(s.sharedKey) | 
		
	
		
			
				|  |  |  |  | 	s.sendControlPacket(newPingPacket()) | 
		
	
		
			
				|  |  |  |  | 	s.resetPingTimer() | 
		
	
		
			
				|  |  |  |  | 	s.resetTimeoutTimer() | 
		
	
		
			
				|  |  |  |  | 	return s | 
		
	
	
		
			
				
					
					|  |  |  | @@ -203,27 +305,6 @@ func newStateClient(b *stateBase) peerState { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateClient) Name() string { return "client" } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateClient) OnPong(addr netip.AddrPort, p pongPacket) peerState { | 
		
	
		
			
				|  |  |  |  | 	if !s.staged.up { | 
		
	
		
			
				|  |  |  |  | 		s.staged.up = true | 
		
	
		
			
				|  |  |  |  | 		s.publish() | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	s.resetTimeoutTimer() | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateClient) OnPingTimer() peerState { | 
		
	
		
			
				|  |  |  |  | 	s.sendPing(s.sharedKey) | 
		
	
		
			
				|  |  |  |  | 	s.resetPingTimer() | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateClient) OnTimeoutTimer() peerState { | 
		
	
		
			
				|  |  |  |  | 	s.staged.up = false | 
		
	
		
			
				|  |  |  |  | 	s.publish() | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ---------------------------------------------------------------------------- | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | type stateServer struct { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -240,25 +321,6 @@ func newStateServer(b *stateBase) peerState { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateServer) Name() string { return "server" } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateServer) OnPing(addr netip.AddrPort, p pingPacket) peerState { | 
		
	
		
			
				|  |  |  |  | 	if addr != s.staged.remoteAddr { | 
		
	
		
			
				|  |  |  |  | 		s.logf("Got new peer address: %v", addr) | 
		
	
		
			
				|  |  |  |  | 		s.staged.remoteAddr = addr | 
		
	
		
			
				|  |  |  |  | 		s.staged.up = true | 
		
	
		
			
				|  |  |  |  | 		s.publish() | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if s.staged.dataCipher == nil || p.SharedKey != s.staged.dataCipher.Key() { | 
		
	
		
			
				|  |  |  |  | 		s.logf("Got new shared key.") | 
		
	
		
			
				|  |  |  |  | 		s.staged.dataCipher = newDataCipherFromKey(p.SharedKey) | 
		
	
		
			
				|  |  |  |  | 		s.staged.up = true | 
		
	
		
			
				|  |  |  |  | 		s.publish() | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s.sendPong(p) | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ---------------------------------------------------------------------------- | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | type stateSelectRelay struct { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -315,7 +377,7 @@ func newStateClientRelayed(b *stateBase) peerState { | 
		
	
		
			
				|  |  |  |  | 	s.sharedKey = s.staged.dataCipher.Key() | 
		
	
		
			
				|  |  |  |  | 	s.publish() | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s.sendPing(s.sharedKey) | 
		
	
		
			
				|  |  |  |  | 	s.sendControlPacket(newPingPacket()) | 
		
	
		
			
				|  |  |  |  | 	s.resetPingTimer() | 
		
	
		
			
				|  |  |  |  | 	s.resetTimeoutTimer() | 
		
	
		
			
				|  |  |  |  | 	return s | 
		
	
	
		
			
				
					
					|  |  |  | @@ -323,26 +385,6 @@ func newStateClientRelayed(b *stateBase) peerState { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateClientRelayed) Name() string { return "client-relayed" } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateClientRelayed) OnPong(addr netip.AddrPort, p pongPacket) peerState { | 
		
	
		
			
				|  |  |  |  | 	if !s.staged.up { | 
		
	
		
			
				|  |  |  |  | 		s.staged.up = true | 
		
	
		
			
				|  |  |  |  | 		s.publish() | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s.resetTimeoutTimer() | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateClientRelayed) OnPingTimer() peerState { | 
		
	
		
			
				|  |  |  |  | 	s.sendPing(s.sharedKey) | 
		
	
		
			
				|  |  |  |  | 	s.resetPingTimer() | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateClientRelayed) OnTimeoutTimer() peerState { | 
		
	
		
			
				|  |  |  |  | 	return newStateSelectRelay(s.stateBase) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ---------------------------------------------------------------------------- | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | type stateServerRelayed struct { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -358,19 +400,6 @@ func newStateServerRelayed(b *stateBase) peerState { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateServerRelayed) Name() string { return "server-relayed" } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateServerRelayed) OnPing(addr netip.AddrPort, p pingPacket) peerState { | 
		
	
		
			
				|  |  |  |  | 	if s.staged.dataCipher == nil || p.SharedKey != s.staged.dataCipher.Key() { | 
		
	
		
			
				|  |  |  |  | 		s.logf("Got new shared key.") | 
		
	
		
			
				|  |  |  |  | 		s.staged.up = true | 
		
	
		
			
				|  |  |  |  | 		s.staged.dataCipher = newDataCipherFromKey(p.SharedKey) | 
		
	
		
			
				|  |  |  |  | 		s.publish() | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	s.sendPong(p) | 
		
	
		
			
				|  |  |  |  | 	s.resetTimeoutTimer() | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (s *stateServerRelayed) OnTimeoutTimer() peerState { | 
		
	
		
			
				|  |  |  |  | 	return newStateSelectRelay(s.stateBase) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					| 
							
							
							
						 |  |  |   |