github.com/telepresenceio/telepresence/v2@v2.20.0-pro.6.0.20240517030216-236ea954e789/pkg/agentconfig/portandproto.go (about)

     1  package agentconfig
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math"
     7  	"net"
     8  	"strconv"
     9  	"strings"
    10  
    11  	core "k8s.io/api/core/v1"
    12  )
    13  
    14  var ErrNotInteger = errors.New("not an integer")
    15  
    16  const ProtoSeparator = byte('/')
    17  
    18  // ParseNumericPort parses the given string into a positive unsigned 16-bit integer.
    19  // ErrNotInteger is returned if the string doesn't represent an integer.
    20  // A range error is return unless the integer is between 1 and 65535.
    21  func ParseNumericPort(portStr string) (uint16, error) {
    22  	port, err := strconv.Atoi(portStr)
    23  	if err != nil {
    24  		return 0, ErrNotInteger
    25  	}
    26  	if port < 1 || port > math.MaxUint16 {
    27  		return 0, fmt.Errorf("%s is not between 1 and 65535", portStr)
    28  	}
    29  	return uint16(port), nil
    30  }
    31  
    32  func ParseProtocol(protocol string) (core.Protocol, error) {
    33  	pr := core.Protocol(strings.ToUpper(protocol))
    34  	switch pr {
    35  	case "":
    36  		return core.ProtocolTCP, nil
    37  	case core.ProtocolUDP, core.ProtocolTCP:
    38  		return pr, nil
    39  	default:
    40  		return "", fmt.Errorf("unsupported protocol: %s", pr)
    41  	}
    42  }
    43  
    44  type PortAndProto struct {
    45  	Port  uint16
    46  	Proto core.Protocol
    47  }
    48  
    49  func NewPortAndProto(s string) (PortAndProto, error) {
    50  	pp := PortAndProto{Proto: core.ProtocolTCP}
    51  	var err error
    52  	if ix := strings.IndexByte(s, ProtoSeparator); ix > 0 {
    53  		if pp.Proto, err = ParseProtocol(s[ix+1:]); err != nil {
    54  			return pp, err
    55  		}
    56  		s = s[0:ix]
    57  	}
    58  	pp.Port, err = ParseNumericPort(s)
    59  	return pp, err
    60  }
    61  
    62  func (pp *PortAndProto) Addr() (addr net.Addr, err error) {
    63  	as := fmt.Sprintf(":%d", pp.Port)
    64  	if pp.Proto == core.ProtocolTCP {
    65  		addr, err = net.ResolveTCPAddr("tcp", as)
    66  	} else {
    67  		addr, err = net.ResolveUDPAddr("udp", as)
    68  	}
    69  	return
    70  }
    71  
    72  func (pp *PortAndProto) String() string {
    73  	if pp.Proto == core.ProtocolTCP {
    74  		return strconv.Itoa(int(pp.Port))
    75  	}
    76  	return fmt.Sprintf("%d/%s", pp.Port, pp.Proto)
    77  }