Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // +build darwin freebsd linux netbsd openbsd windows | 5 // +build darwin freebsd linux netbsd openbsd windows |
6 | 6 |
7 // TCP sockets | 7 // TCP sockets |
8 | 8 |
9 package net | 9 package net |
10 | 10 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
133 // (Nagle's algorithm). The default is true (no delay), meaning | 133 // (Nagle's algorithm). The default is true (no delay), meaning |
134 // that data is sent as soon as possible after a Write. | 134 // that data is sent as soon as possible after a Write. |
135 func (c *TCPConn) SetNoDelay(noDelay bool) error { | 135 func (c *TCPConn) SetNoDelay(noDelay bool) error { |
136 if !c.ok() { | 136 if !c.ok() { |
137 return syscall.EINVAL | 137 return syscall.EINVAL |
138 } | 138 } |
139 return setNoDelay(c.fd, noDelay) | 139 return setNoDelay(c.fd, noDelay) |
140 } | 140 } |
141 | 141 |
142 // DialTCP connects to the remote address raddr on the network net, | 142 // DialTCP connects to the remote address raddr on the network net, |
143 // which must be "tcp", "tcp4" or "tcp6". If laddr is not nil, it is | 143 // which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used |
iant
2012/10/13 17:40:49
Do not remove the comma after "tcp4". It is corre
| |
144 // used as the local address for the connection. | 144 // as the local address for the connection. |
145 func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) { | 145 func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) { |
146 switch net { | 146 switch net { |
147 case "tcp", "tcp4", "tcp6": | 147 case "tcp", "tcp4", "tcp6": |
148 default: | 148 default: |
149 return nil, UnknownNetworkError(net) | 149 return nil, UnknownNetworkError(net) |
150 } | 150 } |
151 if raddr == nil { | 151 if raddr == nil { |
152 return nil, &OpError{"dial", net, nil, errMissingAddress} | 152 return nil, &OpError{"dial", net, nil, errMissingAddress} |
153 } | 153 } |
154 | 154 » return dialTCP(net, laddr, raddr, noDeadline) |
155 » fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.S OCK_STREAM, 0, "dial", sockaddrToTCP) | 155 } |
156 | |
157 func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e rror) { | |
158 » fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP) | |
156 | 159 |
157 // TCP has a rarely used mechanism called a 'simultaneous connection' in | 160 // TCP has a rarely used mechanism called a 'simultaneous connection' in |
158 // which Dial("tcp", addr1, addr2) run on the machine at addr1 can | 161 // which Dial("tcp", addr1, addr2) run on the machine at addr1 can |
159 // connect to a simultaneous Dial("tcp", addr2, addr1) run on the machin e | 162 // connect to a simultaneous Dial("tcp", addr2, addr1) run on the machin e |
160 // at addr2, without either machine executing Listen. If laddr == nil, | 163 // at addr2, without either machine executing Listen. If laddr == nil, |
161 // it means we want the kernel to pick an appropriate originating local | 164 // it means we want the kernel to pick an appropriate originating local |
162 // address. Some Linux kernels cycle blindly through a fixed range of | 165 // address. Some Linux kernels cycle blindly through a fixed range of |
163 // local ports, regardless of destination port. If a kernel happens to | 166 // local ports, regardless of destination port. If a kernel happens to |
164 // pick local port 50001 as the source for a Dial("tcp", "", "localhost: 50001"), | 167 // pick local port 50001 as the source for a Dial("tcp", "", "localhost: 50001"), |
165 // then the Dial will succeed, having simultaneously connected to itself . | 168 // then the Dial will succeed, having simultaneously connected to itself . |
166 // This can only happen when we are letting the kernel pick a port (ladd r == nil) | 169 // This can only happen when we are letting the kernel pick a port (ladd r == nil) |
167 // and when there is no listener for the destination address. | 170 // and when there is no listener for the destination address. |
168 // It's hard to argue this is anything other than a kernel bug. If we | 171 // It's hard to argue this is anything other than a kernel bug. If we |
169 // see this happen, rather than expose the buggy effect to users, we | 172 // see this happen, rather than expose the buggy effect to users, we |
170 // close the fd and try again. If it happens twice more, we relent and | 173 // close the fd and try again. If it happens twice more, we relent and |
171 // use the result. See also: | 174 // use the result. See also: |
172 // http://golang.org/issue/2690 | 175 // http://golang.org/issue/2690 |
173 // http://stackoverflow.com/questions/4949858/ | 176 // http://stackoverflow.com/questions/4949858/ |
174 // | 177 // |
175 // The opposite can also happen: if we ask the kernel to pick an appropr iate | 178 // The opposite can also happen: if we ask the kernel to pick an appropr iate |
176 // originating local address, sometimes it picks one that is already in use. | 179 // originating local address, sometimes it picks one that is already in use. |
177 // So if the error is EADDRNOTAVAIL, we have to try again too, just for | 180 // So if the error is EADDRNOTAVAIL, we have to try again too, just for |
178 // a different reason. | 181 // a different reason. |
179 // | 182 // |
180 // The kernel socket code is no doubt enjoying watching us squirm. | 183 // The kernel socket code is no doubt enjoying watching us squirm. |
181 for i := 0; i < 2 && (laddr == nil || laddr.Port == 0) && (selfConnect(f d, err) || spuriousENOTAVAIL(err)); i++ { | 184 for i := 0; i < 2 && (laddr == nil || laddr.Port == 0) && (selfConnect(f d, err) || spuriousENOTAVAIL(err)); i++ { |
182 if err == nil { | 185 if err == nil { |
183 fd.Close() | 186 fd.Close() |
184 } | 187 } |
185 » » fd, err = internetSocket(net, laddr.toAddr(), raddr.toAddr(), sy scall.SOCK_STREAM, 0, "dial", sockaddrToTCP) | 188 » » fd, err = internetSocket(net, laddr.toAddr(), raddr.toAddr(), de adline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP) |
186 } | 189 } |
187 | 190 |
188 if err != nil { | 191 if err != nil { |
189 return nil, err | 192 return nil, err |
190 } | 193 } |
191 return newTCPConn(fd), nil | 194 return newTCPConn(fd), nil |
192 } | 195 } |
193 | 196 |
194 func selfConnect(fd *netFD, err error) bool { | 197 func selfConnect(fd *netFD, err error) bool { |
195 // If the connect failed, we clearly didn't connect to ourselves. | 198 // If the connect failed, we clearly didn't connect to ourselves. |
(...skipping 22 matching lines...) Expand all Loading... | |
218 return ok && e.Err == syscall.EADDRNOTAVAIL | 221 return ok && e.Err == syscall.EADDRNOTAVAIL |
219 } | 222 } |
220 | 223 |
221 // TCPListener is a TCP network listener. | 224 // TCPListener is a TCP network listener. |
222 // Clients should typically use variables of type Listener | 225 // Clients should typically use variables of type Listener |
223 // instead of assuming TCP. | 226 // instead of assuming TCP. |
224 type TCPListener struct { | 227 type TCPListener struct { |
225 fd *netFD | 228 fd *netFD |
226 } | 229 } |
227 | 230 |
228 // ListenTCP announces on the TCP address laddr on the network net, | 231 // AcceptTCP accepts the next incoming call and returns the new connection |
229 // which must be "tcp", "tcp4" or "tcp6" and returns a TCP listener. | 232 // and the remote address. |
iant
2012/10/13 17:40:49
Need comma after "tcp6".
| |
230 // If laddr has a port of 0, it means to listen on some available | 233 func (l *TCPListener) AcceptTCP() (c *TCPConn, err error) { |
231 // port. The caller can use Addr() of TCPListener to retrieve the | 234 » if l == nil || l.fd == nil || l.fd.sysfd < 0 { |
232 // chosen address. | 235 » » return nil, syscall.EINVAL |
236 » } | |
237 » fd, err := l.fd.accept(sockaddrToTCP) | |
238 » if err != nil { | |
239 » » return nil, err | |
240 » } | |
241 » return newTCPConn(fd), nil | |
242 } | |
243 | |
244 // Accept implements the Accept method in the Listener interface; | |
245 // it waits for the next call and returns a generic Conn. | |
246 func (l *TCPListener) Accept() (c Conn, err error) { | |
247 » c1, err := l.AcceptTCP() | |
248 » if err != nil { | |
249 » » return nil, err | |
250 » } | |
251 » return c1, nil | |
252 } | |
253 | |
254 // Close stops listening on the TCP address. | |
255 // Already Accepted connections are not closed. | |
256 func (l *TCPListener) Close() error { | |
257 » if l == nil || l.fd == nil { | |
258 » » return syscall.EINVAL | |
259 » } | |
260 » return l.fd.Close() | |
261 } | |
262 | |
263 // Addr returns the listener's network address, a *TCPAddr. | |
264 func (l *TCPListener) Addr() Addr { return l.fd.laddr } | |
265 | |
266 // SetDeadline sets the deadline associated with the listener. | |
267 // A zero time value disables the deadline. | |
268 func (l *TCPListener) SetDeadline(t time.Time) error { | |
269 » if l == nil || l.fd == nil { | |
270 » » return syscall.EINVAL | |
271 » } | |
272 » return setDeadline(l.fd, t) | |
273 } | |
274 | |
275 // File returns a copy of the underlying os.File, set to blocking mode. | |
276 // It is the caller's responsibility to close f when finished. | |
277 // Closing l does not affect f, and closing f does not affect l. | |
278 func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() } | |
279 | |
280 // ListenTCP announces on the TCP address laddr and returns a TCP listener. | |
281 // Net must be "tcp", "tcp4", or "tcp6". | |
282 // If laddr has a port of 0, it means to listen on some available port. | |
283 // The caller can use l.Addr() to retrieve the chosen address. | |
233 func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) { | 284 func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) { |
234 switch net { | 285 switch net { |
235 case "tcp", "tcp4", "tcp6": | 286 case "tcp", "tcp4", "tcp6": |
236 default: | 287 default: |
237 return nil, UnknownNetworkError(net) | 288 return nil, UnknownNetworkError(net) |
238 } | 289 } |
239 if laddr == nil { | 290 if laddr == nil { |
240 » » return nil, &OpError{"listen", net, nil, errMissingAddress} | 291 » » laddr = &TCPAddr{} |
241 » } | 292 » } |
242 » fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP) | 293 » fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall. SOCK_STREAM, 0, "listen", sockaddrToTCP) |
243 if err != nil { | 294 if err != nil { |
244 return nil, err | 295 return nil, err |
245 } | 296 } |
246 err = syscall.Listen(fd.sysfd, listenerBacklog) | 297 err = syscall.Listen(fd.sysfd, listenerBacklog) |
247 if err != nil { | 298 if err != nil { |
248 closesocket(fd.sysfd) | 299 closesocket(fd.sysfd) |
249 return nil, &OpError{"listen", net, laddr, err} | 300 return nil, &OpError{"listen", net, laddr, err} |
250 } | 301 } |
251 l := new(TCPListener) | 302 l := new(TCPListener) |
252 l.fd = fd | 303 l.fd = fd |
253 return l, nil | 304 return l, nil |
254 } | 305 } |
255 | |
256 // AcceptTCP accepts the next incoming call and returns the new connection | |
257 // and the remote address. | |
258 func (l *TCPListener) AcceptTCP() (c *TCPConn, err error) { | |
259 if l == nil || l.fd == nil || l.fd.sysfd < 0 { | |
260 return nil, syscall.EINVAL | |
261 } | |
262 fd, err := l.fd.accept(sockaddrToTCP) | |
263 if err != nil { | |
264 return nil, err | |
265 } | |
266 return newTCPConn(fd), nil | |
267 } | |
268 | |
269 // Accept implements the Accept method in the Listener interface; | |
270 // it waits for the next call and returns a generic Conn. | |
271 func (l *TCPListener) Accept() (c Conn, err error) { | |
272 c1, err := l.AcceptTCP() | |
273 if err != nil { | |
274 return nil, err | |
275 } | |
276 return c1, nil | |
277 } | |
278 | |
279 // Close stops listening on the TCP address. | |
280 // Already Accepted connections are not closed. | |
281 func (l *TCPListener) Close() error { | |
282 if l == nil || l.fd == nil { | |
283 return syscall.EINVAL | |
284 } | |
285 return l.fd.Close() | |
286 } | |
287 | |
288 // Addr returns the listener's network address, a *TCPAddr. | |
289 func (l *TCPListener) Addr() Addr { return l.fd.laddr } | |
290 | |
291 // SetDeadline sets the deadline associated with the listener. | |
292 // A zero time value disables the deadline. | |
293 func (l *TCPListener) SetDeadline(t time.Time) error { | |
294 if l == nil || l.fd == nil { | |
295 return syscall.EINVAL | |
296 } | |
297 return setDeadline(l.fd, t) | |
298 } | |
299 | |
300 // File returns a copy of the underlying os.File, set to blocking mode. | |
301 // It is the caller's responsibility to close f when finished. | |
302 // Closing l does not affect f, and closing f does not affect l. | |
303 func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() } | |
LEFT | RIGHT |