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 7package net 8 9import ( 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. 18func 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 77func (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 92func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) error { 93 var c *rawConn 94 if ctrlCtxFn != nil { 95 c = newRawConn(fd) 96 var ctrlAddr string 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 150func (fd *netFD) listenStream(ctx context.Context, laddr sockaddr, backlog int, ctrlCtxFn func(context.Context, string, string, 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 181func (fd *netFD) listenDatagram(ctx context.Context, laddr sockaddr, ctrlCtxFn func(context.Context, string, string, 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