The Go Programming Language

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

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.