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

Golang

Source file src/pkg/net/cgo_unix.go

     1	// Copyright 2011 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	// +build darwin freebsd linux
     6	
     7	package net
     8	
     9	/*
    10	#include <sys/types.h>
    11	#include <sys/socket.h>
    12	#include <netinet/in.h>
    13	#include <netdb.h>
    14	#include <stdlib.h>
    15	#include <unistd.h>
    16	#include <string.h>
    17	*/
    18	import "C"
    19	
    20	import (
    21		"syscall"
    22		"unsafe"
    23	)
    24	
    25	func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
    26		ip, err, completed := cgoLookupIP(name)
    27		for _, p := range ip {
    28			addrs = append(addrs, p.String())
    29		}
    30		return
    31	}
    32	
    33	func cgoLookupPort(net, service string) (port int, err error, completed bool) {
    34		var res *C.struct_addrinfo
    35		var hints C.struct_addrinfo
    36	
    37		switch net {
    38		case "":
    39			// no hints
    40		case "tcp", "tcp4", "tcp6":
    41			hints.ai_socktype = C.SOCK_STREAM
    42			hints.ai_protocol = C.IPPROTO_TCP
    43		case "udp", "udp4", "udp6":
    44			hints.ai_socktype = C.SOCK_DGRAM
    45			hints.ai_protocol = C.IPPROTO_UDP
    46		default:
    47			return 0, UnknownNetworkError(net), true
    48		}
    49		if len(net) >= 4 {
    50			switch net[3] {
    51			case '4':
    52				hints.ai_family = C.AF_INET
    53			case '6':
    54				hints.ai_family = C.AF_INET6
    55			}
    56		}
    57	
    58		s := C.CString(service)
    59		defer C.free(unsafe.Pointer(s))
    60		if C.getaddrinfo(nil, s, &hints, &res) == 0 {
    61			defer C.freeaddrinfo(res)
    62			for r := res; r != nil; r = r.ai_next {
    63				switch r.ai_family {
    64				default:
    65					continue
    66				case C.AF_INET:
    67					sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
    68					p := (*[2]byte)(unsafe.Pointer(&sa.Port))
    69					return int(p[0])<<8 | int(p[1]), nil, true
    70				case C.AF_INET6:
    71					sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
    72					p := (*[2]byte)(unsafe.Pointer(&sa.Port))
    73					return int(p[0])<<8 | int(p[1]), nil, true
    74				}
    75			}
    76		}
    77		return 0, &AddrError{"unknown port", net + "/" + service}, true
    78	}
    79	
    80	func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, completed bool) {
    81		var res *C.struct_addrinfo
    82		var hints C.struct_addrinfo
    83	
    84		// NOTE(rsc): In theory there are approximately balanced
    85		// arguments for and against including AI_ADDRCONFIG
    86		// in the flags (it includes IPv4 results only on IPv4 systems,
    87		// and similarly for IPv6), but in practice setting it causes
    88		// getaddrinfo to return the wrong canonical name on Linux.
    89		// So definitely leave it out.
    90		hints.ai_flags = (C.AI_ALL | C.AI_V4MAPPED | C.AI_CANONNAME) & cgoAddrInfoMask()
    91	
    92		h := C.CString(name)
    93		defer C.free(unsafe.Pointer(h))
    94		gerrno, err := C.getaddrinfo(h, nil, &hints, &res)
    95		if gerrno != 0 {
    96			var str string
    97			if gerrno == C.EAI_NONAME {
    98				str = noSuchHost
    99			} else if gerrno == C.EAI_SYSTEM {
   100				str = err.Error()
   101			} else {
   102				str = C.GoString(C.gai_strerror(gerrno))
   103			}
   104			return nil, "", &DNSError{Err: str, Name: name}, true
   105		}
   106		defer C.freeaddrinfo(res)
   107		if res != nil {
   108			cname = C.GoString(res.ai_canonname)
   109			if cname == "" {
   110				cname = name
   111			}
   112			if len(cname) > 0 && cname[len(cname)-1] != '.' {
   113				cname += "."
   114			}
   115		}
   116		for r := res; r != nil; r = r.ai_next {
   117			// Everything comes back twice, once for UDP and once for TCP.
   118			if r.ai_socktype != C.SOCK_STREAM {
   119				continue
   120			}
   121			switch r.ai_family {
   122			default:
   123				continue
   124			case C.AF_INET:
   125				sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
   126				addrs = append(addrs, copyIP(sa.Addr[:]))
   127			case C.AF_INET6:
   128				sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
   129				addrs = append(addrs, copyIP(sa.Addr[:]))
   130			}
   131		}
   132		return addrs, cname, nil, true
   133	}
   134	
   135	func cgoLookupIP(name string) (addrs []IP, err error, completed bool) {
   136		addrs, _, err, completed = cgoLookupIPCNAME(name)
   137		return
   138	}
   139	
   140	func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
   141		_, cname, err, completed = cgoLookupIPCNAME(name)
   142		return
   143	}
   144	
   145	func copyIP(x IP) IP {
   146		y := make(IP, len(x))
   147		copy(y, x)
   148		return y
   149	}