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