listener.go 1.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. package service
  2. import (
  3. "net"
  4. "sync"
  5. )
  6. type tcpListener struct {
  7. port uint16
  8. s *Service
  9. addr *net.TCPAddr
  10. accept chan net.Conn
  11. // closed is closed instead of accept so a handler blocked handing off a
  12. // connection can't send on a closed channel.
  13. closed chan struct{}
  14. closeOnce sync.Once
  15. }
  16. func (l *tcpListener) Accept() (net.Conn, error) {
  17. // select picks randomly among ready cases, so without this a handler still
  18. // waiting to hand off could win over closed after Close has returned.
  19. select {
  20. case <-l.closed:
  21. return nil, net.ErrClosed
  22. default:
  23. }
  24. select {
  25. case conn := <-l.accept:
  26. return conn, nil
  27. case <-l.closed:
  28. return nil, net.ErrClosed
  29. }
  30. }
  31. func (l *tcpListener) Close() error {
  32. l.closeOnce.Do(func() {
  33. // Close before leaving the map so a concurrent closeListeners that
  34. // no longer sees this listener knows Accept is already released.
  35. close(l.closed)
  36. l.s.mu.Lock()
  37. delete(l.s.mu.listeners, l.port)
  38. l.s.mu.Unlock()
  39. })
  40. return nil
  41. }
  42. // Addr returns the listener's network address.
  43. func (l *tcpListener) Addr() net.Addr {
  44. return l.addr
  45. }