...

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

View as plain text