Black Lives Matter. Support the Equal Justice Initiative.

Source file src/net/sock_posix.go

Documentation: net

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

View as plain text