sock_posix.mx raw

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