// SPDX-FileCopyrightText: 2023 The Pion community // SPDX-License-Identifier: MIT // Package main implements a simple TURN server package server import ( "fmt" "net" "os" "os/signal" "strconv" "syscall" "github.com/pion/turn/v4" ) type TurnServer struct { publicIp string port int users map[string][]byte realm string } func (t *TurnServer) Start() error { // Create a UDP listener to pass into pion/turn // pion/turn itself doesn't allocate any UDP sockets, but lets the user pass them in // this allows us to add logging, storage or modify inbound/outbound traffic udpListener, err := net.ListenPacket("udp4", "0.0.0.0:"+strconv.Itoa(t.port)) if err != nil { return fmt.Errorf("failed to create TURN server listener: %s", err) } server, err := turn.NewServer(turn.ServerConfig{ Realm: t.realm, // Set AuthHandler callback // This is called every time a user tries to authenticate with the TURN server // Return the key for that user, or false when no user is found AuthHandler: func(username string, realm string, srcAddr net.Addr) ([]byte, bool) { // nolint: revive if key, ok := t.users[username]; ok { return key, true } return nil, false }, // PacketConnConfigs is a list of UDP Listeners and the configuration around them PacketConnConfigs: []turn.PacketConnConfig{ { PacketConn: udpListener, RelayAddressGenerator: &turn.RelayAddressGeneratorStatic{ // Claim that we are listening on IP passed by user (This should be your Public IP) RelayAddress: net.ParseIP(t.publicIp), // But actually be listening on every interface Address: "0.0.0.0", }, }, }, }) if err != nil { return err } // Block until user sends SIGINT or SIGTERM sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) <-sigs if err = server.Close(); err != nil { return err } return nil } func (t *TurnServer) AddUser(username string, password string) { if t.users == nil { t.users = make(map[string][]byte) } t.users[username] = turn.GenerateAuthKey(username, t.realm, password) } func (t *TurnServer) SetPublicIp(ip string) { t.publicIp = ip } func (t *TurnServer) SetPort(port int) { t.port = port } func (t *TurnServer) SetRealm(realm string) { t.realm = realm }