client_io_windows.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package remote // import "github.com/docker/docker/libcontainerd/remote"
  2. import (
  3. "io"
  4. "net"
  5. "sync"
  6. winio "github.com/Microsoft/go-winio"
  7. "github.com/containerd/containerd/cio"
  8. "github.com/pkg/errors"
  9. "github.com/sirupsen/logrus"
  10. )
  11. type delayedConnection struct {
  12. l net.Listener
  13. con net.Conn
  14. wg sync.WaitGroup
  15. once sync.Once
  16. }
  17. func (dc *delayedConnection) Write(p []byte) (int, error) {
  18. dc.wg.Wait()
  19. if dc.con != nil {
  20. return dc.con.Write(p)
  21. }
  22. return 0, errors.New("use of closed network connection")
  23. }
  24. func (dc *delayedConnection) Read(p []byte) (int, error) {
  25. dc.wg.Wait()
  26. if dc.con != nil {
  27. return dc.con.Read(p)
  28. }
  29. return 0, errors.New("use of closed network connection")
  30. }
  31. func (dc *delayedConnection) unblockConnectionWaiters() {
  32. defer dc.once.Do(func() {
  33. dc.wg.Done()
  34. })
  35. }
  36. func (dc *delayedConnection) Close() error {
  37. dc.l.Close()
  38. if dc.con != nil {
  39. return dc.con.Close()
  40. }
  41. dc.unblockConnectionWaiters()
  42. return nil
  43. }
  44. type stdioPipes struct {
  45. stdin io.WriteCloser
  46. stdout io.ReadCloser
  47. stderr io.ReadCloser
  48. }
  49. // newStdioPipes creates actual fifos for stdio.
  50. func (c *client) newStdioPipes(fifos *cio.FIFOSet) (_ *stdioPipes, err error) {
  51. p := &stdioPipes{}
  52. if fifos.Stdin != "" {
  53. c.logger.WithFields(logrus.Fields{"stdin": fifos.Stdin}).Debug("listen")
  54. l, err := winio.ListenPipe(fifos.Stdin, nil)
  55. if err != nil {
  56. return nil, errors.Wrapf(err, "failed to create stdin pipe %s", fifos.Stdin)
  57. }
  58. dc := &delayedConnection{
  59. l: l,
  60. }
  61. dc.wg.Add(1)
  62. defer func() {
  63. if err != nil {
  64. dc.Close()
  65. }
  66. }()
  67. p.stdin = dc
  68. go func() {
  69. c.logger.WithFields(logrus.Fields{"stdin": fifos.Stdin}).Debug("accept")
  70. conn, err := l.Accept()
  71. if err != nil {
  72. dc.Close()
  73. if err != winio.ErrPipeListenerClosed {
  74. c.logger.WithError(err).Errorf("failed to accept stdin connection on %s", fifos.Stdin)
  75. }
  76. return
  77. }
  78. c.logger.WithFields(logrus.Fields{"stdin": fifos.Stdin}).Debug("connected")
  79. dc.con = conn
  80. dc.unblockConnectionWaiters()
  81. }()
  82. }
  83. if fifos.Stdout != "" {
  84. c.logger.WithFields(logrus.Fields{"stdout": fifos.Stdout}).Debug("listen")
  85. l, err := winio.ListenPipe(fifos.Stdout, nil)
  86. if err != nil {
  87. return nil, errors.Wrapf(err, "failed to create stdout pipe %s", fifos.Stdout)
  88. }
  89. dc := &delayedConnection{
  90. l: l,
  91. }
  92. dc.wg.Add(1)
  93. defer func() {
  94. if err != nil {
  95. dc.Close()
  96. }
  97. }()
  98. p.stdout = dc
  99. go func() {
  100. c.logger.WithFields(logrus.Fields{"stdout": fifos.Stdout}).Debug("accept")
  101. conn, err := l.Accept()
  102. if err != nil {
  103. dc.Close()
  104. if err != winio.ErrPipeListenerClosed {
  105. c.logger.WithError(err).Errorf("failed to accept stdout connection on %s", fifos.Stdout)
  106. }
  107. return
  108. }
  109. c.logger.WithFields(logrus.Fields{"stdout": fifos.Stdout}).Debug("connected")
  110. dc.con = conn
  111. dc.unblockConnectionWaiters()
  112. }()
  113. }
  114. if fifos.Stderr != "" {
  115. c.logger.WithFields(logrus.Fields{"stderr": fifos.Stderr}).Debug("listen")
  116. l, err := winio.ListenPipe(fifos.Stderr, nil)
  117. if err != nil {
  118. return nil, errors.Wrapf(err, "failed to create stderr pipe %s", fifos.Stderr)
  119. }
  120. dc := &delayedConnection{
  121. l: l,
  122. }
  123. dc.wg.Add(1)
  124. defer func() {
  125. if err != nil {
  126. dc.Close()
  127. }
  128. }()
  129. p.stderr = dc
  130. go func() {
  131. c.logger.WithFields(logrus.Fields{"stderr": fifos.Stderr}).Debug("accept")
  132. conn, err := l.Accept()
  133. if err != nil {
  134. dc.Close()
  135. if err != winio.ErrPipeListenerClosed {
  136. c.logger.WithError(err).Errorf("failed to accept stderr connection on %s", fifos.Stderr)
  137. }
  138. return
  139. }
  140. c.logger.WithFields(logrus.Fields{"stderr": fifos.Stderr}).Debug("connected")
  141. dc.con = conn
  142. dc.unblockConnectionWaiters()
  143. }()
  144. }
  145. return p, nil
  146. }