package udp import ( "context" "fmt" "net" "runtime" "sync" ) type Server struct { bindAddr string routingTable *RoutingTable conns []*net.UDPConn wg sync.WaitGroup ctx context.Context cancel context.CancelFunc } func NewServer(bindAddr string) *Server { ctx, cancel := context.WithCancel(context.Background()) return &Server{ bindAddr: bindAddr, ctx: ctx, cancel: cancel, } } func (s *Server) Run() error { workerCount := runtime.NumCPU() conns, err := listenUDP(s.bindAddr, workerCount) if err != nil { return fmt.Errorf("cannot listen on address: %w", err) } if len(conns) == 0 { return fmt.Errorf("no UDP connections created") } s.conns = conns for _, conn := range s.conns { conn.SetReadBuffer(8 * 1024 * 1024) conn.SetWriteBuffer(8 * 1024 * 1024) } fmt.Println("Listening on", s.bindAddr) for i, conn := range s.conns { s.wg.Add(1) go s.workerLoop(i, conn) } return nil } func (s *Server) sendTo(data []byte, addr *net.UDPAddr) error { if len(s.conns) == 0 || s.conns[0] == nil { return fmt.Errorf("server not started") } // On utilise la première conn pour l’envoi (c’est suffisant pour UDP). _, err := s.conns[0].WriteToUDP(data, addr) return err } func (s *Server) workerLoop(id int, conn *net.UDPConn) { defer s.wg.Done() buffer := make([]byte, 1500) fmt.Println("Worker", id, "started") for { select { case <-s.ctx.Done(): fmt.Println("Worker", id, "stopped") return default: size, addr, err := conn.ReadFromUDP(buffer) if err != nil { if s.ctx.Err() != nil { return } if opErr, ok := err.(*net.OpError); ok && opErr.Temporary() { continue } fmt.Printf("Error reading from UDP (worker %d): %v\n", id, err) continue } s.handlePacket(buffer[:size], addr) } } } func (s *Server) handlePacket(data []byte, addr *net.UDPAddr) { if len(data) == 0 { return } pt := PacketType(data[0]) switch pt { case PacketTypePing: _ = s.sendTo([]byte{byte(PacketTypePing)}, addr) return case PacketTypeConnect: return case PacketTypeDisconnect: return case PacketTypeVoiceData: // todo : déterminer le format du packet // channelID := string(data[1:5]) return default: return } }