github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/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/docker/libnetwork/portmapper"
    13  	"github.com/docker/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  }