fix: 添加relay日志
This commit is contained in:
@@ -133,6 +133,9 @@ func (h *KCPHub) ServeRelay() error {
|
||||
|
||||
// ServeSession 处理一条新接入的 KCP 会话。
|
||||
func (h *KCPHub) ServeSession(session *kcp.UDPSession) error {
|
||||
sessionDesc := describeKCPSession(session)
|
||||
log.Printf("kcp hub accepted session %s", sessionDesc)
|
||||
|
||||
conn, err := transport.NewKCPConn(
|
||||
session,
|
||||
transport.WithKCPLogger(h.logger, latencylog.NodeRoleServer, "hub"),
|
||||
@@ -143,24 +146,26 @@ func (h *KCPHub) ServeSession(session *kcp.UDPSession) error {
|
||||
return fmt.Errorf("server: create kcp transport conn: %w", err)
|
||||
}
|
||||
|
||||
peerID, err := h.registerConn(conn)
|
||||
peerID, err := h.registerConn(conn, sessionDesc)
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
return err
|
||||
}
|
||||
defer h.unregister(peerID, conn)
|
||||
defer h.unregister(peerID, conn, sessionDesc)
|
||||
|
||||
return h.receivePeerLoop(peerID, conn)
|
||||
return h.receivePeerLoop(peerID, conn, sessionDesc)
|
||||
}
|
||||
|
||||
// 注册新连接时,KCPHub 期望第一条消息是一个 register 消息,包含 peer 的 ID
|
||||
func (h *KCPHub) registerConn(conn *transport.KCPConn) (string, error) {
|
||||
func (h *KCPHub) registerConn(conn *transport.KCPConn, sessionDesc string) (string, error) {
|
||||
msg, err := conn.Receive()
|
||||
if err != nil {
|
||||
log.Printf("kcp hub session %s failed before register: %v", sessionDesc, err)
|
||||
return "", fmt.Errorf("server: receive kcp register: %w", err)
|
||||
}
|
||||
|
||||
if msg.Type != protocol.MessageTypeRegister {
|
||||
log.Printf("kcp hub rejecting session %s: first message type=%s from=%s", sessionDesc, msg.Type, msg.From)
|
||||
if sendErr := sendKCPServerError(conn, msg.From, "first message must be register"); sendErr != nil {
|
||||
return "", fmt.Errorf("server: reject unregistered kcp peer: %w", sendErr)
|
||||
}
|
||||
@@ -171,6 +176,7 @@ func (h *KCPHub) registerConn(conn *transport.KCPConn) (string, error) {
|
||||
defer h.mu.Unlock()
|
||||
|
||||
if _, exists := h.peers[msg.From]; exists {
|
||||
log.Printf("kcp hub rejecting duplicate peer %q on session %s", msg.From, sessionDesc)
|
||||
if sendErr := sendKCPServerError(conn, msg.From, fmt.Sprintf("duplicate peer id: %s", msg.From)); sendErr != nil {
|
||||
return "", fmt.Errorf("server: duplicate kcp peer id %s: %w", msg.From, sendErr)
|
||||
}
|
||||
@@ -178,6 +184,7 @@ func (h *KCPHub) registerConn(conn *transport.KCPConn) (string, error) {
|
||||
}
|
||||
|
||||
h.peers[msg.From] = conn
|
||||
log.Printf("kcp hub registered peer %q on session %s (peers=%d)", msg.From, sessionDesc, len(h.peers))
|
||||
return msg.From, nil
|
||||
}
|
||||
|
||||
@@ -190,18 +197,26 @@ func (h *KCPHub) handlePeerMessage(peerID string, conn *transport.KCPConn, msg p
|
||||
if err := h.deliverToLocalPeer(msg); err == nil {
|
||||
return nil
|
||||
} else if !errors.Is(err, errKCPUnknownLocalTarget) {
|
||||
log.Printf("kcp hub local delivery failed for %s -> %s: %v", peerID, msg.To, err)
|
||||
return sendKCPServerError(conn, peerID, fmt.Sprintf("failed to forward to %s", msg.To))
|
||||
}
|
||||
|
||||
log.Printf("kcp hub local target miss for %s -> %s; attempting relay", peerID, msg.To)
|
||||
err := h.forwardToRelay(msg)
|
||||
switch {
|
||||
case err == nil:
|
||||
return nil
|
||||
case errors.Is(err, errKCPRelayUnavailable):
|
||||
log.Printf("kcp hub target %s unavailable for %s: no relay configured", msg.To, peerID)
|
||||
return sendKCPServerError(conn, peerID, fmt.Sprintf("unknown target: %s", msg.To))
|
||||
case errors.Is(err, errKCPRelayPeerUnknown):
|
||||
log.Printf("kcp hub relay peer address is unknown for %s -> %s", peerID, msg.To)
|
||||
return sendKCPServerError(conn, peerID, "failed to relay to remote peer")
|
||||
case errors.Is(err, errKCPRelayTooLarge):
|
||||
log.Printf("kcp hub relay rejected oversize message %s -> %s (%d bytes)", peerID, msg.To, len(msg.Body))
|
||||
return sendKCPServerError(conn, peerID, "message too large for relay udp")
|
||||
default:
|
||||
log.Printf("kcp hub relay forward failed for %s -> %s: %v", peerID, msg.To, err)
|
||||
return sendKCPServerError(conn, peerID, "failed to relay to remote peer")
|
||||
}
|
||||
case protocol.MessageTypeRegister, protocol.MessageTypeError:
|
||||
@@ -218,16 +233,18 @@ func (h *KCPHub) handlePeerMessage(peerID string, conn *transport.KCPConn, msg p
|
||||
}
|
||||
|
||||
// receivePeerLoop 持续读取 peer 发来的消息,并交给 handlePeerMessage 处理,直到连接出错。
|
||||
func (h *KCPHub) receivePeerLoop(peerID string, conn *transport.KCPConn) error {
|
||||
func (h *KCPHub) receivePeerLoop(peerID string, conn *transport.KCPConn, sessionDesc string) error {
|
||||
for {
|
||||
msg, err := conn.Receive()
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
log.Printf("kcp hub receive loop ending for peer %q on session %s: %v", peerID, sessionDesc, err)
|
||||
return fmt.Errorf("transport: kcp receive loop read: %w", err)
|
||||
}
|
||||
|
||||
if err := h.handlePeerMessage(peerID, conn, msg); err != nil {
|
||||
_ = conn.Close()
|
||||
log.Printf("kcp hub handler ending for peer %q on session %s: %v", peerID, sessionDesc, err)
|
||||
return fmt.Errorf("transport: kcp receive loop handler: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -249,6 +266,7 @@ func (h *KCPHub) deliverRelayedMessage(msg protocol.Message) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("kcp hub relayed target miss for %s -> %s; sending error back", msg.From, msg.To)
|
||||
return h.forwardRelayServerError(msg.From, fmt.Sprintf("unknown target: %s", msg.To))
|
||||
}
|
||||
|
||||
@@ -258,7 +276,7 @@ func (h *KCPHub) deliverToLocalPeer(msg protocol.Message) error {
|
||||
return fmt.Errorf("%w: %s", errKCPUnknownLocalTarget, msg.To)
|
||||
}
|
||||
if err := targetConn.Send(msg); err != nil {
|
||||
h.unregister(msg.To, targetConn)
|
||||
h.unregister(msg.To, targetConn, "local-forward-failure")
|
||||
_ = targetConn.Close()
|
||||
return fmt.Errorf("server: forward to local peer %s: %w", msg.To, err)
|
||||
}
|
||||
@@ -307,6 +325,7 @@ func (h *KCPHub) acceptRelayPeer(addr net.Addr) bool {
|
||||
|
||||
if h.relayPeerAddr == nil && h.relayLearnPeer {
|
||||
h.relayPeerAddr = cloneRelayAddr(addr)
|
||||
log.Printf("kcp hub learned relay peer %s", addr)
|
||||
return true
|
||||
}
|
||||
if h.relayPeerAddr == nil {
|
||||
@@ -323,13 +342,14 @@ func (h *KCPHub) lookup(peerID string) (*transport.KCPConn, bool) {
|
||||
return conn, ok
|
||||
}
|
||||
|
||||
func (h *KCPHub) unregister(peerID string, conn *transport.KCPConn) {
|
||||
func (h *KCPHub) unregister(peerID string, conn *transport.KCPConn, sessionDesc string) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
current, ok := h.peers[peerID]
|
||||
if ok && current == conn {
|
||||
delete(h.peers, peerID)
|
||||
log.Printf("kcp hub unregistered peer %q from session %s (peers=%d)", peerID, sessionDesc, len(h.peers))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,3 +398,17 @@ func sameRelayAddr(left, right net.Addr) bool {
|
||||
}
|
||||
return left.String() == right.String()
|
||||
}
|
||||
|
||||
func describeKCPSession(session *kcp.UDPSession) string {
|
||||
if session == nil {
|
||||
return "conv=<nil> remote=<nil> local=<nil>"
|
||||
}
|
||||
return fmt.Sprintf("conv=%d remote=%s local=%s", session.GetConv(), addrString(session.RemoteAddr()), addrString(session.LocalAddr()))
|
||||
}
|
||||
|
||||
func addrString(addr net.Addr) string {
|
||||
if addr == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return addr.String()
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func NewUDPRelay(listenConn net.PacketConn, upstreamAddr *net.UDPAddr) (*UDPRela
|
||||
return nil, fmt.Errorf("relay: upstream addr is required")
|
||||
}
|
||||
|
||||
upstreamConn, err := net.DialUDP("udp", nil, upstreamAddr)
|
||||
upstreamConn, err := net.DialUDP(relayUDPNetwork(upstreamAddr), nil, upstreamAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("relay: dial upstream %s: %w", upstreamAddr, err)
|
||||
}
|
||||
@@ -68,10 +68,20 @@ func (r *UDPRelay) forwardDownstreamToUpstream() error {
|
||||
return fmt.Errorf("relay: read downstream: %w", err)
|
||||
}
|
||||
|
||||
clientAddr := cloneRelayAddr(addr)
|
||||
|
||||
r.mu.Lock()
|
||||
r.clientAddr = cloneRelayAddr(addr)
|
||||
previousAddr := cloneRelayAddr(r.clientAddr)
|
||||
r.clientAddr = clientAddr
|
||||
r.mu.Unlock()
|
||||
|
||||
switch {
|
||||
case previousAddr == nil:
|
||||
log.Printf("relay: learned downstream client %s", clientAddr)
|
||||
case !sameRelayAddr(previousAddr, clientAddr):
|
||||
log.Printf("relay: downstream client changed from %s to %s", previousAddr, clientAddr)
|
||||
}
|
||||
|
||||
if _, err := r.upstream.Write(buf[:n]); err != nil {
|
||||
return fmt.Errorf("relay: write upstream: %w", err)
|
||||
}
|
||||
@@ -113,3 +123,13 @@ func (r *UDPRelay) Close() error {
|
||||
}
|
||||
return err2
|
||||
}
|
||||
|
||||
func relayUDPNetwork(addr *net.UDPAddr) string {
|
||||
if addr == nil || addr.IP == nil {
|
||||
return "udp"
|
||||
}
|
||||
if addr.IP.To4() != nil {
|
||||
return "udp4"
|
||||
}
|
||||
return "udp6"
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ func TestUDPRelayKCPForwardAndReturn(t *testing.T) {
|
||||
hub, hubAddr, hubCleanup := startKCPHubForRelay(t)
|
||||
defer hubCleanup()
|
||||
|
||||
relayAddr := startUDPRelay(t, hubAddr)
|
||||
relayAddr, relay := startUDPRelay(t, hubAddr)
|
||||
|
||||
peerBConn := dialKCPPeer(t, hubAddr)
|
||||
peerAConn := dialKCPPeer(t, relayAddr)
|
||||
@@ -41,6 +41,11 @@ func TestUDPRelayKCPForwardAndReturn(t *testing.T) {
|
||||
waitForRelay(t, func() bool {
|
||||
return hub.HasPeer("peer-a") && hub.HasPeer("peer-b")
|
||||
}, "both peers to be registered")
|
||||
waitForRelay(t, func() bool {
|
||||
relay.mu.RLock()
|
||||
defer relay.mu.RUnlock()
|
||||
return relay.clientAddr != nil
|
||||
}, "relay to learn the downstream peer")
|
||||
|
||||
if err := peerBConn.Send(protocol.Message{
|
||||
Type: protocol.MessageTypeText,
|
||||
@@ -95,7 +100,7 @@ func TestUDPRelayKCPFileMessage(t *testing.T) {
|
||||
hub, hubAddr, hubCleanup := startKCPHubForRelay(t)
|
||||
defer hubCleanup()
|
||||
|
||||
relayAddr := startUDPRelay(t, hubAddr)
|
||||
relayAddr, relay := startUDPRelay(t, hubAddr)
|
||||
|
||||
peerBConn := dialKCPPeer(t, hubAddr)
|
||||
peerAConn := dialKCPPeer(t, relayAddr)
|
||||
@@ -118,6 +123,11 @@ func TestUDPRelayKCPFileMessage(t *testing.T) {
|
||||
waitForRelay(t, func() bool {
|
||||
return hub.HasPeer("peer-a") && hub.HasPeer("peer-b")
|
||||
}, "both peers to be registered")
|
||||
waitForRelay(t, func() bool {
|
||||
relay.mu.RLock()
|
||||
defer relay.mu.RUnlock()
|
||||
return relay.clientAddr != nil
|
||||
}, "relay to learn the downstream peer")
|
||||
|
||||
if err := peerBConn.Send(protocol.Message{
|
||||
Type: protocol.MessageTypeFile,
|
||||
@@ -222,7 +232,7 @@ func dialKCPPeer(t *testing.T, serverAddr string) *transport.KCPConn {
|
||||
return conn
|
||||
}
|
||||
|
||||
func startUDPRelay(t *testing.T, upstreamAddr string) string {
|
||||
func startUDPRelay(t *testing.T, upstreamAddr string) (string, *UDPRelay) {
|
||||
t.Helper()
|
||||
|
||||
remoteAddr, err := net.ResolveUDPAddr("udp", upstreamAddr)
|
||||
@@ -255,7 +265,7 @@ func startUDPRelay(t *testing.T, upstreamAddr string) string {
|
||||
wg.Wait()
|
||||
})
|
||||
|
||||
return conn.LocalAddr().String()
|
||||
return conn.LocalAddr().String(), relay
|
||||
}
|
||||
|
||||
func waitForRelay(t *testing.T, condition func() bool, description string) {
|
||||
|
||||
Reference in New Issue
Block a user