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