pipe_windows.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // +build windows
  2. package statsd
  3. import (
  4. "net"
  5. "sync"
  6. "time"
  7. "github.com/Microsoft/go-winio"
  8. )
  9. const defaultPipeTimeout = 1 * time.Millisecond
  10. type pipeWriter struct {
  11. mu sync.RWMutex
  12. conn net.Conn
  13. timeout time.Duration
  14. pipepath string
  15. }
  16. func (p *pipeWriter) SetWriteTimeout(d time.Duration) error {
  17. p.mu.Lock()
  18. p.timeout = d
  19. p.mu.Unlock()
  20. return nil
  21. }
  22. func (p *pipeWriter) Write(data []byte) (n int, err error) {
  23. conn, err := p.ensureConnection()
  24. if err != nil {
  25. return 0, err
  26. }
  27. p.mu.RLock()
  28. conn.SetWriteDeadline(time.Now().Add(p.timeout))
  29. p.mu.RUnlock()
  30. n, err = conn.Write(data)
  31. if err != nil {
  32. if e, ok := err.(net.Error); !ok || !e.Temporary() {
  33. // disconnected; retry again on next attempt
  34. p.mu.Lock()
  35. p.conn = nil
  36. p.mu.Unlock()
  37. }
  38. }
  39. return n, err
  40. }
  41. func (p *pipeWriter) ensureConnection() (net.Conn, error) {
  42. p.mu.RLock()
  43. conn := p.conn
  44. p.mu.RUnlock()
  45. if conn != nil {
  46. return conn, nil
  47. }
  48. // looks like we might need to connect - try again with write locking.
  49. p.mu.Lock()
  50. defer p.mu.Unlock()
  51. if p.conn != nil {
  52. return p.conn, nil
  53. }
  54. newconn, err := winio.DialPipe(p.pipepath, nil)
  55. if err != nil {
  56. return nil, err
  57. }
  58. p.conn = newconn
  59. return newconn, nil
  60. }
  61. func (p *pipeWriter) Close() error {
  62. return p.conn.Close()
  63. }
  64. func newWindowsPipeWriter(pipepath string) (*pipeWriter, error) {
  65. // Defer connection establishment to first write
  66. return &pipeWriter{
  67. conn: nil,
  68. timeout: defaultPipeTimeout,
  69. pipepath: pipepath,
  70. }, nil
  71. }