新增stun服务
This commit is contained in:
@@ -25,6 +25,13 @@ func main() {
|
|||||||
go handleShutdownSignals()
|
go handleShutdownSignals()
|
||||||
libs.Connect()
|
libs.Connect()
|
||||||
grpcClient.UserClientInit()
|
grpcClient.UserClientInit()
|
||||||
|
// 创建 STUN 服务器实例
|
||||||
|
stunServer := libs.NewSTUNServer(appConfig.StunPort)
|
||||||
|
// 启动 STUN 服务器
|
||||||
|
if err1 := stunServer.Start(); err1 != nil {
|
||||||
|
log.Fatalf("Failed to start STUN server: %v", err1)
|
||||||
|
}
|
||||||
|
defer stunServer.Close()
|
||||||
app := gin.Default()
|
app := gin.Default()
|
||||||
router.Init(app)
|
router.Init(app)
|
||||||
app.Run(":" + strconv.Itoa(appConfig.Port))
|
app.Run(":" + strconv.Itoa(appConfig.Port))
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ type AppConfig struct {
|
|||||||
WorkerID int64 `yaml:"workerID"`
|
WorkerID int64 `yaml:"workerID"`
|
||||||
DatacenterID int64 `yaml:"datacenterID"`
|
DatacenterID int64 `yaml:"datacenterID"`
|
||||||
GrpcUrl string `yaml:"grpcUrl"`
|
GrpcUrl string `yaml:"grpcUrl"`
|
||||||
|
StunPort string `yaml:"stunPort"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DatabaseConfig struct {
|
type DatabaseConfig struct {
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -34,6 +34,10 @@ require (
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
|
github.com/pion/dtls/v2 v2.2.7 // indirect
|
||||||
|
github.com/pion/logging v0.2.2 // indirect
|
||||||
|
github.com/pion/stun v0.6.1 // indirect
|
||||||
|
github.com/pion/transport/v2 v2.2.1 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||||
golang.org/x/arch v0.20.0 // indirect
|
golang.org/x/arch v0.20.0 // indirect
|
||||||
|
|||||||
132
libs/stun_service.go
Normal file
132
libs/stun_service.go
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
package libs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pion/stun"
|
||||||
|
)
|
||||||
|
|
||||||
|
// STUNServer 表示 STUN 服务器实例
|
||||||
|
type STUNServer struct {
|
||||||
|
conn net.PacketConn
|
||||||
|
isRunning bool
|
||||||
|
mu sync.RWMutex
|
||||||
|
port string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSTUNServer 创建新的 STUN 服务器实例
|
||||||
|
func NewSTUNServer(port string) *STUNServer {
|
||||||
|
return &STUNServer{
|
||||||
|
port: port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start 启动 STUN 服务器
|
||||||
|
func (s *STUNServer) Start() error {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
if s.isRunning {
|
||||||
|
return fmt.Errorf("STUN server is already running")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 UDP 监听器
|
||||||
|
conn, err := net.ListenPacket("udp4", ":"+s.port)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to listen on port %s: %v", s.port, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.conn = conn
|
||||||
|
s.isRunning = true
|
||||||
|
|
||||||
|
// 启动 STUN 服务器 goroutine
|
||||||
|
go s.run()
|
||||||
|
|
||||||
|
log.Printf("STUN server started on port %s", s.port)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSTUNAddress 获取 STUN 服务器地址
|
||||||
|
func (s *STUNServer) GetSTUNAddress() string {
|
||||||
|
return fmt.Sprintf("stun:%s", s.port)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run 运行 STUN 服务器的主循环
|
||||||
|
func (s *STUNServer) run() {
|
||||||
|
buf := make([]byte, 1024)
|
||||||
|
|
||||||
|
for {
|
||||||
|
// 读取数据包
|
||||||
|
n, addr, err := s.conn.ReadFrom(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error reading from connection: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理 STUN 消息
|
||||||
|
s.handleSTUNMessage(addr, buf[:n])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleSTUNMessage 处理 STUN 消息
|
||||||
|
func (s *STUNServer) handleSTUNMessage(addr net.Addr, buf []byte) {
|
||||||
|
// 解析 STUN 消息
|
||||||
|
msg := &stun.Message{Raw: buf}
|
||||||
|
if err := msg.Decode(); err != nil {
|
||||||
|
// 不是有效的 STUN 消息,可能是其他协议
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只处理绑定请求
|
||||||
|
if msg.Type != stun.BindingRequest {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建响应消息
|
||||||
|
response, err := stun.Build(stun.BindingSuccess, stun.TransactionID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error building STUN response: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加 XOR-MAPPED-ADDRESS 属性 - 使用正确的方法
|
||||||
|
udpAddr := addr.(*net.UDPAddr)
|
||||||
|
xorAddr := stun.XORMappedAddress{
|
||||||
|
IP: udpAddr.IP,
|
||||||
|
Port: udpAddr.Port,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 AddTo 方法而不是 Add 方法
|
||||||
|
if err := xorAddr.AddTo(response); err != nil {
|
||||||
|
log.Printf("Error adding XOR-MAPPED-ADDRESS: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送响应
|
||||||
|
if _, err := s.conn.WriteTo(response.Raw, addr); err != nil {
|
||||||
|
log.Printf("Error sending response: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Handled STUN request from %s", addr.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close 关闭 STUN 服务器
|
||||||
|
func (s *STUNServer) Close() error {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
if !s.isRunning {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.conn.Close(); err != nil {
|
||||||
|
return fmt.Errorf("error closing STUN server: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.isRunning = false
|
||||||
|
log.Println("STUN server stopped")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user