compiler: Do not declare type switch variable outside case statements.
[official-gcc.git] / libgo / go / net / sock_posix.go
blob3f956df65a6abc410b966984cf8e731306c9703c
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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
7 package net
9 import (
10 "os"
11 "syscall"
12 "time"
15 // A sockaddr represents a TCP, UDP, IP or Unix network endpoint
16 // address that can be converted into a syscall.Sockaddr.
17 type sockaddr interface {
18 Addr
20 netaddr
22 // family returns the platform-dependent address family
23 // identifier.
24 family() int
26 // isWildcard reports whether the address is a wildcard
27 // address.
28 isWildcard() bool
30 // sockaddr returns the address converted into a syscall
31 // sockaddr type that implements syscall.Sockaddr
32 // interface. It returns a nil interface when the address is
33 // nil.
34 sockaddr(family int) (syscall.Sockaddr, error)
37 // socket returns a network file descriptor that is ready for
38 // asynchronous I/O using the network poller.
39 func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time) (fd *netFD, err error) {
40 s, err := sysSocket(family, sotype, proto)
41 if err != nil {
42 return nil, err
44 if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
45 closesocket(s)
46 return nil, err
48 if fd, err = newFD(s, family, sotype, net); err != nil {
49 closesocket(s)
50 return nil, err
53 // This function makes a network file descriptor for the
54 // following applications:
56 // - An endpoint holder that opens a passive stream
57 // connenction, known as a stream listener
59 // - An endpoint holder that opens a destination-unspecific
60 // datagram connection, known as a datagram listener
62 // - An endpoint holder that opens an active stream or a
63 // destination-specific datagram connection, known as a
64 // dialer
66 // - An endpoint holder that opens the other connection, such
67 // as talking to the protocol stack inside the kernel
69 // For stream and datagram listeners, they will only require
70 // named sockets, so we can assume that it's just a request
71 // from stream or datagram listeners when laddr is not nil but
72 // raddr is nil. Otherwise we assume it's just for dialers or
73 // the other connection holders.
75 if laddr != nil && raddr == nil {
76 switch sotype {
77 case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
78 if err := fd.listenStream(laddr, listenerBacklog); err != nil {
79 fd.Close()
80 return nil, err
82 return fd, nil
83 case syscall.SOCK_DGRAM:
84 if err := fd.listenDatagram(laddr); err != nil {
85 fd.Close()
86 return nil, err
88 return fd, nil
91 if err := fd.dial(laddr, raddr, deadline); err != nil {
92 fd.Close()
93 return nil, err
95 return fd, nil
98 func (fd *netFD) addrFunc() func(syscall.Sockaddr) Addr {
99 switch fd.family {
100 case syscall.AF_INET, syscall.AF_INET6:
101 switch fd.sotype {
102 case syscall.SOCK_STREAM:
103 return sockaddrToTCP
104 case syscall.SOCK_DGRAM:
105 return sockaddrToUDP
106 case syscall.SOCK_RAW:
107 return sockaddrToIP
109 case syscall.AF_UNIX:
110 switch fd.sotype {
111 case syscall.SOCK_STREAM:
112 return sockaddrToUnix
113 case syscall.SOCK_DGRAM:
114 return sockaddrToUnixgram
115 case syscall.SOCK_SEQPACKET:
116 return sockaddrToUnixpacket
119 return func(syscall.Sockaddr) Addr { return nil }
122 func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time) error {
123 var err error
124 var lsa syscall.Sockaddr
125 if laddr != nil {
126 if lsa, err = laddr.sockaddr(fd.family); err != nil {
127 return err
128 } else if lsa != nil {
129 if err := syscall.Bind(fd.sysfd, lsa); err != nil {
130 return os.NewSyscallError("bind", err)
134 var rsa syscall.Sockaddr
135 if raddr != nil {
136 if rsa, err = raddr.sockaddr(fd.family); err != nil {
137 return err
139 if err := fd.connect(lsa, rsa, deadline); err != nil {
140 return err
142 fd.isConnected = true
143 } else {
144 if err := fd.init(); err != nil {
145 return err
148 lsa, _ = syscall.Getsockname(fd.sysfd)
149 if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil {
150 fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
151 } else {
152 fd.setAddr(fd.addrFunc()(lsa), raddr)
154 return nil
157 func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
158 if err := setDefaultListenerSockopts(fd.sysfd); err != nil {
159 return err
161 if lsa, err := laddr.sockaddr(fd.family); err != nil {
162 return err
163 } else if lsa != nil {
164 if err := syscall.Bind(fd.sysfd, lsa); err != nil {
165 return os.NewSyscallError("bind", err)
168 if err := syscall.Listen(fd.sysfd, backlog); err != nil {
169 return os.NewSyscallError("listen", err)
171 if err := fd.init(); err != nil {
172 return err
174 lsa, _ := syscall.Getsockname(fd.sysfd)
175 fd.setAddr(fd.addrFunc()(lsa), nil)
176 return nil
179 func (fd *netFD) listenDatagram(laddr sockaddr) error {
180 switch addr := laddr.(type) {
181 case *UDPAddr:
182 // We provide a socket that listens to a wildcard
183 // address with reusable UDP port when the given laddr
184 // is an appropriate UDP multicast address prefix.
185 // This makes it possible for a single UDP listener to
186 // join multiple different group addresses, for
187 // multiple UDP listeners that listen on the same UDP
188 // port to join the same group address.
189 if addr.IP != nil && addr.IP.IsMulticast() {
190 if err := setDefaultMulticastSockopts(fd.sysfd); err != nil {
191 return err
193 addr := *addr
194 switch fd.family {
195 case syscall.AF_INET:
196 addr.IP = IPv4zero
197 case syscall.AF_INET6:
198 addr.IP = IPv6unspecified
200 laddr = &addr
203 if lsa, err := laddr.sockaddr(fd.family); err != nil {
204 return err
205 } else if lsa != nil {
206 if err := syscall.Bind(fd.sysfd, lsa); err != nil {
207 return os.NewSyscallError("bind", err)
210 if err := fd.init(); err != nil {
211 return err
213 lsa, _ := syscall.Getsockname(fd.sysfd)
214 fd.setAddr(fd.addrFunc()(lsa), nil)
215 return nil