Files
OmniSocketGo/cmd/kcpserver/main.go
2026-03-27 19:08:31 +08:00

122 lines
4.1 KiB
Go

package main
import (
"flag"
"log"
"net"
"strings"
kcp "github.com/xtaci/kcp-go/v5"
"omnisocketgo/cmd/internal/latencylog"
"omnisocketgo/cmd/internal/server"
"omnisocketgo/cmd/internal/transport"
)
func main() {
listenAddr := flag.String("listen", ":9002", "KCP server listen address")
bindDevice := flag.String("bind-device", "", "optional Linux network device used when listening")
logPath := flag.String("latency-log", "", "optional JSONL file path for latency timestamp logs")
kcpTimestampDebugLogPath := flag.String("kcp-ts-debug-log", "", "optional JSONL file path for KCP packet kernel timestamp debug records")
kcpSessionStatsLogPath := flag.String("kcp-session-stats-log", "", "optional JSONL file path for KCP session stats records")
kcpSessionStatsInterval := flag.String("kcp-session-stats-interval", transport.DefaultKCPSessionStatsInterval.String(), "sampling interval for KCP session stats, for example 100ms")
relayListenAddr := flag.String("relay-listen", "", "optional raw UDP relay listen address")
relayPeerAddr := flag.String("relay-peer", "", "optional fixed raw UDP relay peer address")
relayLearnPeer := flag.Bool("relay-learn-peer", false, "learn the relay peer address from the first inbound relay packet")
flag.Parse()
statsInterval, err := transport.ParseKCPSessionStatsInterval(*kcpSessionStatsInterval)
if err != nil {
log.Fatalf("parse -kcp-session-stats-interval=%q: %v", *kcpSessionStatsInterval, err)
}
hubOptions := make([]server.KCPOption, 0, 2)
if *logPath != "" {
logger, err := latencylog.NewJSONLLogger(*logPath)
if err != nil {
log.Fatalf("create latency logger %s: %v", *logPath, err)
}
defer logger.Close()
hubOptions = append(hubOptions, server.WithKCPLogger(logger))
}
var packetLogger transport.KCPPacketDebugLogger
if *kcpTimestampDebugLogPath != "" {
logger, err := transport.NewJSONLKCPPacketDebugLogger(*kcpTimestampDebugLogPath)
if err != nil {
log.Fatalf("create kcp packet debug logger %s: %v", *kcpTimestampDebugLogPath, err)
}
defer logger.Close()
packetLogger = logger
}
if *kcpSessionStatsLogPath != "" {
logger, err := transport.NewJSONLKCPSessionStatsLogger(*kcpSessionStatsLogPath)
if err != nil {
log.Fatalf("create kcp session stats logger %s: %v", *kcpSessionStatsLogPath, err)
}
defer logger.Close()
hubOptions = append(hubOptions, server.WithKCPSessionStatsLogger(logger, statsInterval))
}
listener, packetConn, err := transport.ListenKCPSessions(*listenAddr, *bindDevice, packetLogger, latencylog.NodeRoleServer, "hub")
if err != nil {
log.Fatalf("listen kcp on %s: %v", *listenAddr, err)
}
defer packetConn.Close()
defer listener.Close()
hub := server.NewKCPHub(hubOptions...)
if *relayPeerAddr != "" && *relayListenAddr == "" {
log.Fatal("flag -relay-listen is required when -relay-peer is set")
}
if *relayLearnPeer && *relayListenAddr == "" {
log.Fatal("flag -relay-listen is required when -relay-learn-peer is set")
}
if *relayListenAddr != "" {
relayConn, err := net.ListenPacket("udp", *relayListenAddr)
if err != nil {
log.Fatalf("listen relay udp on %s: %v", *relayListenAddr, err)
}
defer relayConn.Close()
var relayPeer net.Addr
if *relayPeerAddr != "" {
relayPeer, err = net.ResolveUDPAddr("udp", *relayPeerAddr)
if err != nil {
log.Fatalf("resolve relay peer %s: %v", *relayPeerAddr, err)
}
}
hub.SetRelaySocket(relayConn, relayPeer, *relayLearnPeer)
go func() {
if serveErr := hub.ServeRelay(); serveErr != nil {
log.Printf("kcp relay loop ended: %v", serveErr)
}
}()
log.Printf("kcp relay listening on %s", relayConn.LocalAddr())
if relayPeer != nil {
log.Printf("kcp relay peer configured as %s", relayPeer)
}
}
log.Printf("kcp server listening on %s", listener.Addr())
for {
session, err := listener.AcceptKCP()
if err != nil {
if strings.Contains(err.Error(), "closed") {
return
}
log.Printf("accept kcp session: %v", err)
continue
}
go func(sess *kcp.UDPSession) {
if serveErr := hub.ServeSession(sess); serveErr != nil {
log.Printf("kcp session closed: %v", serveErr)
}
}(session)
}
}