176 lines
5.7 KiB
Go
176 lines
5.7 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"log"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
kcp "github.com/xtaci/kcp-go/v5"
|
|
|
|
"omnisocketgo/cmd/internal/latencylog"
|
|
"omnisocketgo/cmd/internal/server"
|
|
"omnisocketgo/cmd/internal/transport"
|
|
)
|
|
|
|
const (
|
|
kcpServerModeHub = "hub"
|
|
kcpServerModeRelay = "relay"
|
|
)
|
|
|
|
func main() {
|
|
mode := flag.String("mode", kcpServerModeHub, "kcpserver mode: hub or relay")
|
|
listenAddr := flag.String("listen", ":9002", "listen address; KCP listener in hub mode, UDP relay listener in relay mode")
|
|
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", "", "deprecated alias for -listen in relay mode")
|
|
relayRemoteAddr := flag.String("relay-remote", "", "fixed remote UDP address used in relay mode")
|
|
relayPeerAddr := flag.String("relay-peer", "", "deprecated alias for -relay-remote")
|
|
flag.Parse()
|
|
|
|
var relayRemoteFlagSet bool
|
|
var relayPeerFlagSet bool
|
|
var relayListenFlagSet bool
|
|
flag.Visit(func(f *flag.Flag) {
|
|
switch f.Name {
|
|
case "relay-listen":
|
|
relayListenFlagSet = true
|
|
case "relay-remote":
|
|
relayRemoteFlagSet = true
|
|
case "relay-peer":
|
|
relayPeerFlagSet = true
|
|
}
|
|
})
|
|
|
|
switch {
|
|
case relayRemoteFlagSet && relayPeerFlagSet && *relayRemoteAddr != *relayPeerAddr:
|
|
log.Fatal("flags -relay-remote and -relay-peer must match when both are set")
|
|
case *relayRemoteAddr == "" && *relayPeerAddr != "":
|
|
*relayRemoteAddr = *relayPeerAddr
|
|
}
|
|
if relayPeerFlagSet {
|
|
log.Printf("warning: flag -relay-peer is deprecated; use -relay-remote instead")
|
|
}
|
|
if relayListenFlagSet {
|
|
if *relayListenAddr == "" {
|
|
log.Fatal("flag -relay-listen must not be empty when set")
|
|
}
|
|
if *mode != kcpServerModeRelay {
|
|
log.Fatal("flag -relay-listen may only be used in relay mode")
|
|
}
|
|
if *listenAddr != ":9002" && *listenAddr != *relayListenAddr {
|
|
log.Fatal("flags -listen and -relay-listen must match when both are set in relay mode")
|
|
}
|
|
*listenAddr = *relayListenAddr
|
|
log.Printf("warning: flag -relay-listen is deprecated; use -listen with -mode=relay instead")
|
|
}
|
|
|
|
statsInterval, err := transport.ParseKCPSessionStatsInterval(*kcpSessionStatsInterval)
|
|
if err != nil {
|
|
log.Fatalf("parse -kcp-session-stats-interval=%q: %v", *kcpSessionStatsInterval, err)
|
|
}
|
|
|
|
switch *mode {
|
|
case kcpServerModeHub:
|
|
if *relayRemoteAddr != "" {
|
|
log.Fatal("flag -relay-remote may only be used in relay mode")
|
|
}
|
|
runHubServer(*listenAddr, *bindDevice, *logPath, *kcpTimestampDebugLogPath, *kcpSessionStatsLogPath, statsInterval)
|
|
case kcpServerModeRelay:
|
|
if *bindDevice != "" {
|
|
log.Fatal("flag -bind-device is not supported in relay mode")
|
|
}
|
|
if *relayRemoteAddr == "" {
|
|
log.Fatal("flag -relay-remote is required in relay mode")
|
|
}
|
|
runUDPRelayServer(*listenAddr, *relayRemoteAddr)
|
|
default:
|
|
log.Fatalf("unsupported -mode=%q; want %q or %q", *mode, kcpServerModeHub, kcpServerModeRelay)
|
|
}
|
|
}
|
|
|
|
func runHubServer(listenAddr, bindDevice, logPath, packetDebugLogPath, sessionStatsLogPath string, statsInterval time.Duration) {
|
|
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 packetDebugLogPath != "" {
|
|
logger, err := transport.NewJSONLKCPPacketDebugLogger(packetDebugLogPath)
|
|
if err != nil {
|
|
log.Fatalf("create kcp packet debug logger %s: %v", packetDebugLogPath, err)
|
|
}
|
|
defer logger.Close()
|
|
packetLogger = logger
|
|
}
|
|
if sessionStatsLogPath != "" {
|
|
logger, err := transport.NewJSONLKCPSessionStatsLogger(sessionStatsLogPath)
|
|
if err != nil {
|
|
log.Fatalf("create kcp session stats logger %s: %v", sessionStatsLogPath, 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...)
|
|
|
|
log.Printf("kcp hub 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)
|
|
}
|
|
}
|
|
|
|
func runUDPRelayServer(listenAddr, remoteAddr string) {
|
|
conn, err := net.ListenPacket("udp", listenAddr)
|
|
if err != nil {
|
|
log.Fatalf("listen udp relay on %s: %v", listenAddr, err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
remote, err := net.ResolveUDPAddr("udp", remoteAddr)
|
|
if err != nil {
|
|
log.Fatalf("resolve relay remote %s: %v", remoteAddr, err)
|
|
}
|
|
|
|
relay, err := server.NewUDPRelay(conn, remote)
|
|
if err != nil {
|
|
log.Fatalf("create udp relay: %v", err)
|
|
}
|
|
|
|
log.Printf("udp relay listening on %s and forwarding to %s", conn.LocalAddr(), remote)
|
|
if err := relay.Serve(); err != nil {
|
|
log.Fatalf("udp relay stopped: %v", err)
|
|
}
|
|
}
|