Source file src/net/sock_posix.go

     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 string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, ctrlCtxFn func(context.Context, string, string, 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() string {
    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) addrFunc() func(syscall.Sockaddr) Addr {
    93  	switch fd.family {
    94  	case syscall.AF_INET, syscall.AF_INET6:
    95  		switch fd.sotype {
    96  		case syscall.SOCK_STREAM:
    97  			return sockaddrToTCP
    98  		case syscall.SOCK_DGRAM:
    99  			return sockaddrToUDP
   100  		case syscall.SOCK_RAW:
   101  			return sockaddrToIP
   102  		}
   103  	case syscall.AF_UNIX:
   104  		switch fd.sotype {
   105  		case syscall.SOCK_STREAM:
   106  			return sockaddrToUnix
   107  		case syscall.SOCK_DGRAM:
   108  			return sockaddrToUnixgram
   109  		case syscall.SOCK_SEQPACKET:
   110  			return sockaddrToUnixpacket
   111  		}
   112  	}
   113  	return func(syscall.Sockaddr) Addr { return nil }
   114  }
   115  
   116  func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) error {
   117  	var c *rawConn
   118  	var err error
   119  	if ctrlCtxFn != nil {
   120  		c, err = newRawConn(fd)
   121  		if err != nil {
   122  			return err
   123  		}
   124  		var ctrlAddr string
   125  		if raddr != nil {
   126  			ctrlAddr = raddr.String()
   127  		} else if laddr != nil {
   128  			ctrlAddr = laddr.String()
   129  		}
   130  		if err := ctrlCtxFn(ctx, fd.ctrlNetwork(), ctrlAddr, c); err != nil {
   131  			return err
   132  		}
   133  	}
   134  
   135  	var lsa syscall.Sockaddr
   136  	if laddr != nil {
   137  		if lsa, err = laddr.sockaddr(fd.family); err != nil {
   138  			return err
   139  		} else if lsa != nil {
   140  			if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
   141  				return os.NewSyscallError("bind", err)
   142  			}
   143  		}
   144  	}
   145  	var rsa syscall.Sockaddr  // remote address from the user
   146  	var crsa syscall.Sockaddr // remote address we actually connected to
   147  	if raddr != nil {
   148  		if rsa, err = raddr.sockaddr(fd.family); err != nil {
   149  			return err
   150  		}
   151  		if crsa, err = fd.connect(ctx, lsa, rsa); err != nil {
   152  			return err
   153  		}
   154  		fd.isConnected = true
   155  	} else {
   156  		if err := fd.init(); err != nil {
   157  			return err
   158  		}
   159  	}
   160  	// Record the local and remote addresses from the actual socket.
   161  	// Get the local address by calling Getsockname.
   162  	// For the remote address, use
   163  	// 1) the one returned by the connect method, if any; or
   164  	// 2) the one from Getpeername, if it succeeds; or
   165  	// 3) the one passed to us as the raddr parameter.
   166  	lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
   167  	if crsa != nil {
   168  		fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(crsa))
   169  	} else if rsa, _ = syscall.Getpeername(fd.pfd.Sysfd); rsa != nil {
   170  		fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
   171  	} else {
   172  		fd.setAddr(fd.addrFunc()(lsa), raddr)
   173  	}
   174  	return nil
   175  }
   176  
   177  func (fd *netFD) listenStream(ctx context.Context, laddr sockaddr, backlog int, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) error {
   178  	var err error
   179  	if err = setDefaultListenerSockopts(fd.pfd.Sysfd); err != nil {
   180  		return err
   181  	}
   182  	var lsa syscall.Sockaddr
   183  	if lsa, err = laddr.sockaddr(fd.family); err != nil {
   184  		return err
   185  	}
   186  
   187  	if ctrlCtxFn != nil {
   188  		c, err := newRawConn(fd)
   189  		if err != nil {
   190  			return err
   191  		}
   192  		if err := ctrlCtxFn(ctx, fd.ctrlNetwork(), laddr.String(), c); err != nil {
   193  			return err
   194  		}
   195  	}
   196  
   197  	if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
   198  		return os.NewSyscallError("bind", err)
   199  	}
   200  	if err = listenFunc(fd.pfd.Sysfd, backlog); err != nil {
   201  		return os.NewSyscallError("listen", err)
   202  	}
   203  	if err = fd.init(); err != nil {
   204  		return err
   205  	}
   206  	lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
   207  	fd.setAddr(fd.addrFunc()(lsa), nil)
   208  	return nil
   209  }
   210  
   211  func (fd *netFD) listenDatagram(ctx context.Context, laddr sockaddr, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) error {
   212  	switch addr := laddr.(type) {
   213  	case *UDPAddr:
   214  		// We provide a socket that listens to a wildcard
   215  		// address with reusable UDP port when the given laddr
   216  		// is an appropriate UDP multicast address prefix.
   217  		// This makes it possible for a single UDP listener to
   218  		// join multiple different group addresses, for
   219  		// multiple UDP listeners that listen on the same UDP
   220  		// port to join the same group address.
   221  		if addr.IP != nil && addr.IP.IsMulticast() {
   222  			if err := setDefaultMulticastSockopts(fd.pfd.Sysfd); err != nil {
   223  				return err
   224  			}
   225  			addr := *addr
   226  			switch fd.family {
   227  			case syscall.AF_INET:
   228  				addr.IP = IPv4zero
   229  			case syscall.AF_INET6:
   230  				addr.IP = IPv6unspecified
   231  			}
   232  			laddr = &addr
   233  		}
   234  	}
   235  	var err error
   236  	var lsa syscall.Sockaddr
   237  	if lsa, err = laddr.sockaddr(fd.family); err != nil {
   238  		return err
   239  	}
   240  
   241  	if ctrlCtxFn != nil {
   242  		c, err := newRawConn(fd)
   243  		if err != nil {
   244  			return err
   245  		}
   246  		if err := ctrlCtxFn(ctx, fd.ctrlNetwork(), laddr.String(), c); err != nil {
   247  			return err
   248  		}
   249  	}
   250  	if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
   251  		return os.NewSyscallError("bind", err)
   252  	}
   253  	if err = fd.init(); err != nil {
   254  		return err
   255  	}
   256  	lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
   257  	fd.setAddr(fd.addrFunc()(lsa), nil)
   258  	return nil
   259  }
   260  

View as plain text