Run starts the proxy server.
()
| 294 | |
| 295 | // Run starts the proxy server. |
| 296 | func (p *Proxy) Run() error { |
| 297 | // Start coarse clock for efficient session activity tracking |
| 298 | handler.StartCoarseClock(p.ctx) |
| 299 | |
| 300 | addr, err := net.ResolveUDPAddr("udp", p.listenAddr) |
| 301 | if err != nil { |
| 302 | return fmt.Errorf("failed to resolve address: %w", err) |
| 303 | } |
| 304 | |
| 305 | p.conn, err = net.ListenUDP("udp", addr) |
| 306 | if err != nil { |
| 307 | return fmt.Errorf("failed to listen: %w", err) |
| 308 | } |
| 309 | defer p.conn.Close() |
| 310 | |
| 311 | log.Printf("[proxy] listening on %s", p.listenAddr) |
| 312 | log.Printf("[proxy] handler chain: %v", p.handlerNames()) |
| 313 | log.Printf("[proxy] session timeout: %ds", p.sessionTimeout.Load()) |
| 314 | |
| 315 | // Start worker pool (bounded goroutines instead of unbounded per-packet) |
| 316 | // Note: workerPool.Stop() is called in Stop() for proper graceful shutdown |
| 317 | p.workerPool = NewWorkerPool(0, 0, p.handlePacket) |
| 318 | p.workerPool.Start() |
| 319 | |
| 320 | // Start session cleanup goroutine |
| 321 | go p.cleanupSessions() |
| 322 | |
| 323 | for { |
| 324 | select { |
| 325 | case <-p.ctx.Done(): |
| 326 | return nil |
| 327 | default: |
| 328 | } |
| 329 | |
| 330 | // Get buffer from pool (eliminates per-packet allocation) |
| 331 | buf := handler.GetBuffer() |
| 332 | |
| 333 | p.conn.SetReadDeadline(time.Now().Add(1 * time.Second)) |
| 334 | n, clientAddr, err := p.conn.ReadFromUDP(*buf) |
| 335 | if err != nil { |
| 336 | handler.PutBuffer(buf) |
| 337 | if netErr, ok := err.(net.Error); ok && netErr.Timeout() { |
| 338 | continue |
| 339 | } |
| 340 | log.Printf("Read error: %v", err) |
| 341 | continue |
| 342 | } |
| 343 | |
| 344 | // Submit to worker pool (non-blocking with backpressure) |
| 345 | // Buffer is returned to pool by worker after processing |
| 346 | if !p.workerPool.Submit(WorkItem{ |
| 347 | ClientAddr: clientAddr, |
| 348 | Packet: (*buf)[:n], |
| 349 | Buffer: buf, |
| 350 | }) { |
| 351 | // Queue full - packet already dropped, buffer returned by Submit |
| 352 | } |
| 353 | } |