port_mapping.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // +build windows
  2. package windows
  3. import (
  4. "bytes"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "github.com/docker/libnetwork/portmapper"
  9. "github.com/docker/libnetwork/types"
  10. "github.com/ishidawataru/sctp"
  11. "github.com/sirupsen/logrus"
  12. )
  13. const (
  14. maxAllocatePortAttempts = 10
  15. )
  16. // ErrUnsupportedAddressType is returned when the specified address type is not supported.
  17. type ErrUnsupportedAddressType string
  18. func (uat ErrUnsupportedAddressType) Error() string {
  19. return fmt.Sprintf("unsupported address type: %s", string(uat))
  20. }
  21. // AllocatePorts allocates ports specified in bindings from the portMapper
  22. func AllocatePorts(portMapper *portmapper.PortMapper, bindings []types.PortBinding, containerIP net.IP) ([]types.PortBinding, error) {
  23. bs := make([]types.PortBinding, 0, len(bindings))
  24. for _, c := range bindings {
  25. b := c.GetCopy()
  26. if err := allocatePort(portMapper, &b, containerIP); err != nil {
  27. // On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
  28. if cuErr := ReleasePorts(portMapper, bs); cuErr != nil {
  29. logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
  30. }
  31. return nil, err
  32. }
  33. bs = append(bs, b)
  34. }
  35. return bs, nil
  36. }
  37. func allocatePort(portMapper *portmapper.PortMapper, bnd *types.PortBinding, containerIP net.IP) error {
  38. var (
  39. host net.Addr
  40. err error
  41. )
  42. // Windows does not support a host ip for port bindings (this is validated in ConvertPortBindings()).
  43. // If the HostIP is nil, force it to be 0.0.0.0 for use as the key in portMapper.
  44. if bnd.HostIP == nil {
  45. bnd.HostIP = net.IPv4zero
  46. }
  47. // Store the container interface address in the operational binding
  48. bnd.IP = containerIP
  49. // Adjust HostPortEnd if this is not a range.
  50. if bnd.HostPortEnd == 0 {
  51. bnd.HostPortEnd = bnd.HostPort
  52. }
  53. // Construct the container side transport address
  54. container, err := bnd.ContainerAddr()
  55. if err != nil {
  56. return err
  57. }
  58. // Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
  59. for i := 0; i < maxAllocatePortAttempts; i++ {
  60. if host, err = portMapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), false); err == nil {
  61. break
  62. }
  63. // There is no point in immediately retrying to map an explicitly chosen port.
  64. if bnd.HostPort != 0 {
  65. logrus.Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err)
  66. break
  67. }
  68. logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
  69. }
  70. if err != nil {
  71. return err
  72. }
  73. // Save the host port (regardless it was or not specified in the binding)
  74. switch netAddr := host.(type) {
  75. case *net.TCPAddr:
  76. bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
  77. break
  78. case *net.UDPAddr:
  79. bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
  80. break
  81. case *sctp.SCTPAddr:
  82. bnd.HostPort = uint16(host.(*sctp.SCTPAddr).Port)
  83. break
  84. default:
  85. // For completeness
  86. return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
  87. }
  88. //Windows does not support host port ranges.
  89. bnd.HostPortEnd = bnd.HostPort
  90. return nil
  91. }
  92. // ReleasePorts releases ports specified in bindings from the portMapper
  93. func ReleasePorts(portMapper *portmapper.PortMapper, bindings []types.PortBinding) error {
  94. var errorBuf bytes.Buffer
  95. // Attempt to release all port bindings, do not stop on failure
  96. for _, m := range bindings {
  97. if err := releasePort(portMapper, m); err != nil {
  98. errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
  99. }
  100. }
  101. if errorBuf.Len() != 0 {
  102. return errors.New(errorBuf.String())
  103. }
  104. return nil
  105. }
  106. func releasePort(portMapper *portmapper.PortMapper, bnd types.PortBinding) error {
  107. // Construct the host side transport address
  108. host, err := bnd.HostAddr()
  109. if err != nil {
  110. return err
  111. }
  112. return portMapper.Unmap(host)
  113. }