pipe_windows.go 1.3 KB

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