src/pkg/net/ipsock.go - The Go Programming Language

Golang

Source file src/pkg/net/ipsock.go

     1	// Copyright 2009 The Go Authors.  All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// IP sockets
     6	
     7	package net
     8	
     9	var supportsIPv6, supportsIPv4map = probeIPv6Stack()
    10	
    11	func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
    12		if filter == nil {
    13			// We'll take any IP address, but since the dialing code
    14			// does not yet try multiple addresses, prefer to use
    15			// an IPv4 address if possible.  This is especially relevant
    16			// if localhost resolves to [ipv6-localhost, ipv4-localhost].
    17			// Too much code assumes localhost == ipv4-localhost.
    18			addr = firstSupportedAddr(ipv4only, addrs)
    19			if addr == nil {
    20				addr = firstSupportedAddr(anyaddr, addrs)
    21			}
    22		} else {
    23			addr = firstSupportedAddr(filter, addrs)
    24		}
    25		return
    26	}
    27	
    28	func firstSupportedAddr(filter func(IP) IP, addrs []string) IP {
    29		for _, s := range addrs {
    30			if addr := filter(ParseIP(s)); addr != nil {
    31				return addr
    32			}
    33		}
    34		return nil
    35	}
    36	
    37	func anyaddr(x IP) IP {
    38		if x4 := x.To4(); x4 != nil {
    39			return x4
    40		}
    41		if supportsIPv6 {
    42			return x
    43		}
    44		return nil
    45	}
    46	
    47	func ipv4only(x IP) IP { return x.To4() }
    48	
    49	func ipv6only(x IP) IP {
    50		// Only return addresses that we can use
    51		// with the kernel's IPv6 addressing modes.
    52		if len(x) == IPv6len && x.To4() == nil && supportsIPv6 {
    53			return x
    54		}
    55		return nil
    56	}
    57	
    58	type InvalidAddrError string
    59	
    60	func (e InvalidAddrError) Error() string   { return string(e) }
    61	func (e InvalidAddrError) Timeout() bool   { return false }
    62	func (e InvalidAddrError) Temporary() bool { return false }
    63	
    64	// SplitHostPort splits a network address of the form
    65	// "host:port" or "[host]:port" into host and port.
    66	// The latter form must be used when host contains a colon.
    67	func SplitHostPort(hostport string) (host, port string, err error) {
    68		// The port starts after the last colon.
    69		i := last(hostport, ':')
    70		if i < 0 {
    71			err = &AddrError{"missing port in address", hostport}
    72			return
    73		}
    74	
    75		host, port = hostport[0:i], hostport[i+1:]
    76	
    77		// Can put brackets around host ...
    78		if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
    79			host = host[1 : len(host)-1]
    80		} else {
    81			// ... but if there are no brackets, no colons.
    82			if byteIndex(host, ':') >= 0 {
    83				err = &AddrError{"too many colons in address", hostport}
    84				return
    85			}
    86		}
    87		return
    88	}
    89	
    90	// JoinHostPort combines host and port into a network address
    91	// of the form "host:port" or, if host contains a colon, "[host]:port".
    92	func JoinHostPort(host, port string) string {
    93		// If host has colons, have to bracket it.
    94		if byteIndex(host, ':') >= 0 {
    95			return "[" + host + "]:" + port
    96		}
    97		return host + ":" + port
    98	}
    99	
   100	// Convert "host:port" into IP address and port.
   101	func hostPortToIP(net, hostport string) (ip IP, iport int, err error) {
   102		host, port, err := SplitHostPort(hostport)
   103		if err != nil {
   104			return nil, 0, err
   105		}
   106	
   107		var addr IP
   108		if host != "" {
   109			// Try as an IP address.
   110			addr = ParseIP(host)
   111			if addr == nil {
   112				var filter func(IP) IP
   113				if net != "" && net[len(net)-1] == '4' {
   114					filter = ipv4only
   115				}
   116				if net != "" && net[len(net)-1] == '6' {
   117					filter = ipv6only
   118				}
   119				// Not an IP address.  Try as a DNS name.
   120				addrs, err := LookupHost(host)
   121				if err != nil {
   122					return nil, 0, err
   123				}
   124				addr = firstFavoriteAddr(filter, addrs)
   125				if addr == nil {
   126					// should not happen
   127					return nil, 0, &AddrError{"LookupHost returned no suitable address", addrs[0]}
   128				}
   129			}
   130		}
   131	
   132		p, i, ok := dtoi(port, 0)
   133		if !ok || i != len(port) {
   134			p, err = LookupPort(net, port)
   135			if err != nil {
   136				return nil, 0, err
   137			}
   138		}
   139		if p < 0 || p > 0xFFFF {
   140			return nil, 0, &AddrError{"invalid port", port}
   141		}
   142	
   143		return addr, p, nil
   144	
   145	}