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