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.
5 // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris windows
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
)
23 if err
= setDefaultSockopts(s
, family
, sotype
, ipv6only
); err
!= nil {
27 if fd
, err
= newFD(s
, family
, sotype
, net
); err
!= nil {
32 // This function makes a network file descriptor for the
33 // following applications:
35 // - An endpoint holder that opens a passive stream
36 // connection, known as a stream listener
38 // - An endpoint holder that opens a destination-unspecific
39 // datagram connection, known as a datagram listener
41 // - An endpoint holder that opens an active stream or a
42 // destination-specific datagram connection, known as a
45 // - An endpoint holder that opens the other connection, such
46 // as talking to the protocol stack inside the kernel
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.
54 if laddr
!= nil && raddr
== nil {
56 case syscall
.SOCK_STREAM
, syscall
.SOCK_SEQPACKET
:
57 if err
:= fd
.listenStream(laddr
, listenerBacklog(), ctrlFn
); err
!= nil {
62 case syscall
.SOCK_DGRAM
:
63 if err
:= fd
.listenDatagram(laddr
, ctrlFn
); err
!= nil {
70 if err
:= fd
.dial(ctx
, laddr
, raddr
, ctrlFn
); err
!= nil {
77 func (fd
*netFD
) ctrlNetwork() string {
79 case "unix", "unixgram", "unixpacket":
82 switch fd
.net
[len(fd
.net
)-1] {
86 if fd
.family
== syscall
.AF_INET
{
92 func (fd
*netFD
) addrFunc() func(syscall
.Sockaddr
) Addr
{
94 case syscall
.AF_INET
, syscall
.AF_INET6
:
96 case syscall
.SOCK_STREAM
:
98 case syscall
.SOCK_DGRAM
:
100 case syscall
.SOCK_RAW
:
103 case syscall
.AF_UNIX
:
105 case syscall
.SOCK_STREAM
:
106 return sockaddrToUnix
107 case syscall
.SOCK_DGRAM
:
108 return sockaddrToUnixgram
109 case syscall
.SOCK_SEQPACKET
:
110 return sockaddrToUnixpacket
113 return func(syscall
.Sockaddr
) Addr
{ return nil }
116 func (fd
*netFD
) dial(ctx context
.Context
, laddr
, raddr sockaddr
, ctrlFn
func(string, string, syscall
.RawConn
) error
) error
{
118 c
, err
:= newRawConn(fd
)
124 ctrlAddr
= raddr
.String()
125 } else if laddr
!= nil {
126 ctrlAddr
= laddr
.String()
128 if err
:= ctrlFn(fd
.ctrlNetwork(), ctrlAddr
, c
); err
!= nil {
133 var lsa syscall
.Sockaddr
135 if lsa
, err
= laddr
.sockaddr(fd
.family
); err
!= nil {
137 } else if lsa
!= nil {
138 if err
= syscall
.Bind(fd
.pfd
.Sysfd
, lsa
); err
!= nil {
139 return os
.NewSyscallError("bind", err
)
143 var rsa syscall
.Sockaddr
// remote address from the user
144 var crsa syscall
.Sockaddr
// remote address we actually connected to
146 if rsa
, err
= raddr
.sockaddr(fd
.family
); err
!= nil {
149 if crsa
, err
= fd
.connect(ctx
, lsa
, rsa
); err
!= nil {
152 fd
.isConnected
= true
154 if err
:= fd
.init(); err
!= nil {
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
)
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
))
170 fd
.setAddr(fd
.addrFunc()(lsa
), raddr
)
175 func (fd
*netFD
) listenStream(laddr sockaddr
, backlog
int, ctrlFn
func(string, string, syscall
.RawConn
) error
) error
{
177 if err
= setDefaultListenerSockopts(fd
.pfd
.Sysfd
); err
!= nil {
180 var lsa syscall
.Sockaddr
181 if lsa
, err
= laddr
.sockaddr(fd
.family
); err
!= nil {
185 c
, err
:= newRawConn(fd
)
189 if err
:= ctrlFn(fd
.ctrlNetwork(), laddr
.String(), c
); err
!= nil {
193 if err
= syscall
.Bind(fd
.pfd
.Sysfd
, lsa
); err
!= nil {
194 return os
.NewSyscallError("bind", err
)
196 if err
= listenFunc(fd
.pfd
.Sysfd
, backlog
); err
!= nil {
197 return os
.NewSyscallError("listen", err
)
199 if err
= fd
.init(); err
!= nil {
202 lsa
, err
= syscall
.Getsockname(fd
.pfd
.Sysfd
)
204 return os
.NewSyscallError("getsockname", err
)
206 fd
.setAddr(fd
.addrFunc()(lsa
), nil)
210 func (fd
*netFD
) listenDatagram(laddr sockaddr
, ctrlFn
func(string, string, syscall
.RawConn
) error
) error
{
211 switch addr
:= laddr
.(type) {
213 // We provide a socket that listens to a wildcard
214 // address with reusable UDP port when the given laddr
215 // is an appropriate UDP multicast address prefix.
216 // This makes it possible for a single UDP listener to
217 // join multiple different group addresses, for
218 // multiple UDP listeners that listen on the same UDP
219 // port to join the same group address.
220 if addr
.IP
!= nil && addr
.IP
.IsMulticast() {
221 if err
:= setDefaultMulticastSockopts(fd
.pfd
.Sysfd
); err
!= nil {
226 case syscall
.AF_INET
:
228 case syscall
.AF_INET6
:
229 addr
.IP
= IPv6unspecified
235 var lsa syscall
.Sockaddr
236 if lsa
, err
= laddr
.sockaddr(fd
.family
); err
!= nil {
240 c
, err
:= newRawConn(fd
)
244 if err
:= ctrlFn(fd
.ctrlNetwork(), laddr
.String(), c
); err
!= nil {
248 if err
= syscall
.Bind(fd
.pfd
.Sysfd
, lsa
); err
!= nil {
249 return os
.NewSyscallError("bind", err
)
251 if err
= fd
.init(); err
!= nil {
254 lsa
, err
= syscall
.Getsockname(fd
.pfd
.Sysfd
)
256 return os
.NewSyscallError("getsockname", err
)
258 fd
.setAddr(fd
.addrFunc()(lsa
), nil)