github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/net/sock_posix.go (about)

     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  // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
     6  
     7  package net
     8  
     9  import (
    10  	"os"
    11  	"syscall"
    12  	"time"
    13  )
    14  
    15  // A sockaddr represents a TCP, UDP, IP or Unix network endpoint
    16  // address that can be converted into a syscall.Sockaddr.
    17  type sockaddr interface {
    18  	Addr
    19  
    20  	netaddr
    21  
    22  	// family returns the platform-dependent address family
    23  	// identifier.
    24  	family() int
    25  
    26  	// isWildcard reports whether the address is a wildcard
    27  	// address.
    28  	isWildcard() bool
    29  
    30  	// sockaddr returns the address converted into a syscall
    31  	// sockaddr type that implements syscall.Sockaddr
    32  	// interface. It returns a nil interface when the address is
    33  	// nil.
    34  	sockaddr(family int) (syscall.Sockaddr, error)
    35  }
    36  
    37  // socket returns a network file descriptor that is ready for
    38  // asynchronous I/O using the network poller.
    39  func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time) (fd *netFD, err error) {
    40  	s, err := sysSocket(family, sotype, proto)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
    45  		closesocket(s)
    46  		return nil, err
    47  	}
    48  	if fd, err = newFD(s, family, sotype, net); err != nil {
    49  		closesocket(s)
    50  		return nil, err
    51  	}
    52  
    53  	// This function makes a network file descriptor for the
    54  	// following applications:
    55  	//
    56  	// - An endpoint holder that opens a passive stream
    57  	//   connenction, known as a stream listener
    58  	//
    59  	// - An endpoint holder that opens a destination-unspecific
    60  	//   datagram connection, known as a datagram listener
    61  	//
    62  	// - An endpoint holder that opens an active stream or a
    63  	//   destination-specific datagram connection, known as a
    64  	//   dialer
    65  	//
    66  	// - An endpoint holder that opens the other connection, such
    67  	//   as talking to the protocol stack inside the kernel
    68  	//
    69  	// For stream and datagram listeners, they will only require
    70  	// named sockets, so we can assume that it's just a request
    71  	// from stream or datagram listeners when laddr is not nil but
    72  	// raddr is nil. Otherwise we assume it's just for dialers or
    73  	// the other connection holders.
    74  
    75  	if laddr != nil && raddr == nil {
    76  		switch sotype {
    77  		case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
    78  			if err := fd.listenStream(laddr, listenerBacklog); err != nil {
    79  				fd.Close()
    80  				return nil, err
    81  			}
    82  			return fd, nil
    83  		case syscall.SOCK_DGRAM:
    84  			if err := fd.listenDatagram(laddr); err != nil {
    85  				fd.Close()
    86  				return nil, err
    87  			}
    88  			return fd, nil
    89  		}
    90  	}
    91  	if err := fd.dial(laddr, raddr, deadline); err != nil {
    92  		fd.Close()
    93  		return nil, err
    94  	}
    95  	return fd, nil
    96  }
    97  
    98  func (fd *netFD) addrFunc() func(syscall.Sockaddr) Addr {
    99  	switch fd.family {
   100  	case syscall.AF_INET, syscall.AF_INET6:
   101  		switch fd.sotype {
   102  		case syscall.SOCK_STREAM:
   103  			return sockaddrToTCP
   104  		case syscall.SOCK_DGRAM:
   105  			return sockaddrToUDP
   106  		case syscall.SOCK_RAW:
   107  			return sockaddrToIP
   108  		}
   109  	case syscall.AF_UNIX:
   110  		switch fd.sotype {
   111  		case syscall.SOCK_STREAM:
   112  			return sockaddrToUnix
   113  		case syscall.SOCK_DGRAM:
   114  			return sockaddrToUnixgram
   115  		case syscall.SOCK_SEQPACKET:
   116  			return sockaddrToUnixpacket
   117  		}
   118  	}
   119  	return func(syscall.Sockaddr) Addr { return nil }
   120  }
   121  
   122  func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time) error {
   123  	var err error
   124  	var lsa syscall.Sockaddr
   125  	if laddr != nil {
   126  		if lsa, err = laddr.sockaddr(fd.family); err != nil {
   127  			return err
   128  		} else if lsa != nil {
   129  			if err := syscall.Bind(fd.sysfd, lsa); err != nil {
   130  				return os.NewSyscallError("bind", err)
   131  			}
   132  		}
   133  	}
   134  	var rsa syscall.Sockaddr
   135  	if raddr != nil {
   136  		if rsa, err = raddr.sockaddr(fd.family); err != nil {
   137  			return err
   138  		}
   139  		if err := fd.connect(lsa, rsa, deadline); err != nil {
   140  			return err
   141  		}
   142  		fd.isConnected = true
   143  	} else {
   144  		if err := fd.init(); err != nil {
   145  			return err
   146  		}
   147  	}
   148  	lsa, _ = syscall.Getsockname(fd.sysfd)
   149  	if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil {
   150  		fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
   151  	} else {
   152  		fd.setAddr(fd.addrFunc()(lsa), raddr)
   153  	}
   154  	return nil
   155  }
   156  
   157  func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
   158  	if err := setDefaultListenerSockopts(fd.sysfd); err != nil {
   159  		return err
   160  	}
   161  	if lsa, err := laddr.sockaddr(fd.family); err != nil {
   162  		return err
   163  	} else if lsa != nil {
   164  		if err := syscall.Bind(fd.sysfd, lsa); err != nil {
   165  			return os.NewSyscallError("bind", err)
   166  		}
   167  	}
   168  	if err := syscall.Listen(fd.sysfd, backlog); err != nil {
   169  		return os.NewSyscallError("listen", err)
   170  	}
   171  	if err := fd.init(); err != nil {
   172  		return err
   173  	}
   174  	lsa, _ := syscall.Getsockname(fd.sysfd)
   175  	fd.setAddr(fd.addrFunc()(lsa), nil)
   176  	return nil
   177  }
   178  
   179  func (fd *netFD) listenDatagram(laddr sockaddr) error {
   180  	switch addr := laddr.(type) {
   181  	case *UDPAddr:
   182  		// We provide a socket that listens to a wildcard
   183  		// address with reusable UDP port when the given laddr
   184  		// is an appropriate UDP multicast address prefix.
   185  		// This makes it possible for a single UDP listener to
   186  		// join multiple different group addresses, for
   187  		// multiple UDP listeners that listen on the same UDP
   188  		// port to join the same group address.
   189  		if addr.IP != nil && addr.IP.IsMulticast() {
   190  			if err := setDefaultMulticastSockopts(fd.sysfd); err != nil {
   191  				return err
   192  			}
   193  			addr := *addr
   194  			switch fd.family {
   195  			case syscall.AF_INET:
   196  				addr.IP = IPv4zero
   197  			case syscall.AF_INET6:
   198  				addr.IP = IPv6unspecified
   199  			}
   200  			laddr = &addr
   201  		}
   202  	}
   203  	if lsa, err := laddr.sockaddr(fd.family); err != nil {
   204  		return err
   205  	} else if lsa != nil {
   206  		if err := syscall.Bind(fd.sysfd, lsa); err != nil {
   207  			return os.NewSyscallError("bind", err)
   208  		}
   209  	}
   210  	if err := fd.init(); err != nil {
   211  		return err
   212  	}
   213  	lsa, _ := syscall.Getsockname(fd.sysfd)
   214  	fd.setAddr(fd.addrFunc()(lsa), nil)
   215  	return nil
   216  }