blob: 5ec91845dfc5bcb3cef22358f0e47204d30b4542 [file] [log] [blame]
Russ Coxe4a61c62008-09-29 13:37:00 -07001// 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// TODO(rsc): All the prints in this file should go to standard error.
6
7package net
8
9import (
Russ Cox47a05332010-04-26 22:15:25 -070010 "io"
Robert Griesemera3d10452009-12-15 15:35:38 -080011 "os"
12 "sync"
13 "syscall"
Russ Cox00f9f0c2010-03-30 10:34:57 -070014 "time"
Russ Coxe4a61c62008-09-29 13:37:00 -070015)
16
Russ Coxd8921c52009-02-15 14:18:39 -080017// Network file descriptor.
18type netFD struct {
Devon H. O'Delleb163462009-12-01 23:28:57 -080019 // locking/lifetime of sysfd
Robert Griesemera3d10452009-12-15 15:35:38 -080020 sysmu sync.Mutex
21 sysref int
22 closing bool
Devon H. O'Delleb163462009-12-01 23:28:57 -080023
Russ Coxe4a61c62008-09-29 13:37:00 -070024 // immutable until Close
Robert Griesemera3d10452009-12-15 15:35:38 -080025 sysfd int
26 family int
27 proto int
28 sysfile *os.File
Russ Coxcaa149f2010-04-06 16:50:27 -070029 cr chan bool
30 cw chan bool
Robert Griesemera3d10452009-12-15 15:35:38 -080031 net string
32 laddr Addr
33 raddr Addr
Russ Coxe4a61c62008-09-29 13:37:00 -070034
Russ Cox1e37e8a2009-03-06 17:51:31 -080035 // owned by client
Robert Griesemera3d10452009-12-15 15:35:38 -080036 rdeadline_delta int64
37 rdeadline int64
38 rio sync.Mutex
39 wdeadline_delta int64
40 wdeadline int64
41 wio sync.Mutex
Russ Cox1e37e8a2009-03-06 17:51:31 -080042
Russ Coxe4a61c62008-09-29 13:37:00 -070043 // owned by fd wait server
Robert Griesemera3d10452009-12-15 15:35:38 -080044 ncr, ncw int
Russ Coxe4a61c62008-09-29 13:37:00 -070045}
46
Russ Cox47a05332010-04-26 22:15:25 -070047type InvalidConnError struct{}
48
49func (e *InvalidConnError) String() string { return "invalid net.Conn" }
50func (e *InvalidConnError) Temporary() bool { return false }
51func (e *InvalidConnError) Timeout() bool { return false }
52
Russ Coxd8921c52009-02-15 14:18:39 -080053// A pollServer helps FDs determine when to retry a non-blocking
Russ Coxe4a61c62008-09-29 13:37:00 -070054// read or write after they get EAGAIN. When an FD needs to wait,
55// send the fd on s.cr (for a read) or s.cw (for a write) to pass the
56// request to the poll server. Then receive on fd.cr/fd.cw.
Russ Coxd8921c52009-02-15 14:18:39 -080057// When the pollServer finds that i/o on FD should be possible
Russ Coxe4a61c62008-09-29 13:37:00 -070058// again, it will send fd on fd.cr/fd.cw to wake any waiting processes.
59// This protocol is implemented as s.WaitRead() and s.WaitWrite().
60//
61// There is one subtlety: when sending on s.cr/s.cw, the
62// poll server is probably in a system call, waiting for an fd
63// to become ready. It's not looking at the request channels.
64// To resolve this, the poll server waits not just on the FDs it has
65// been given but also its own pipe. After sending on the
66// buffered channel s.cr/s.cw, WaitRead/WaitWrite writes a
Russ Coxd8921c52009-02-15 14:18:39 -080067// byte to the pipe, causing the pollServer's poll system call to
68// return. In response to the pipe being readable, the pollServer
Russ Coxe4a61c62008-09-29 13:37:00 -070069// re-polls its request channels.
70//
71// Note that the ordering is "send request" and then "wake up server".
72// If the operations were reversed, there would be a race: the poll
73// server might wake up and look at the request channel, see that it
74// was empty, and go back to sleep, all before the requester managed
75// to send the request. Because the send must complete before the wakeup,
76// the request channel must be buffered. A buffer of size 1 is sufficient
77// for any request load. If many processes are trying to submit requests,
Russ Coxd8921c52009-02-15 14:18:39 -080078// one will succeed, the pollServer will read the request, and then the
Russ Coxe4a61c62008-09-29 13:37:00 -070079// channel will be empty for the next process's request. A larger buffer
80// might help batch requests.
Adam Langleyef8f4832009-11-18 13:18:34 -080081//
Devon H. O'Delleb163462009-12-01 23:28:57 -080082// To avoid races in closing, all fd operations are locked and
83// refcounted. when netFD.Close() is called, it calls syscall.Shutdown
84// and sets a closing flag. Only when the last reference is removed
85// will the fd be closed.
Russ Coxe4a61c62008-09-29 13:37:00 -070086
Russ Coxd8921c52009-02-15 14:18:39 -080087type pollServer struct {
Robert Griesemera3d10452009-12-15 15:35:38 -080088 cr, cw chan *netFD // buffered >= 1
89 pr, pw *os.File
90 pending map[int]*netFD
91 poll *pollster // low-level OS hooks
92 deadline int64 // next deadline (nsec since 1970)
Russ Coxe4a61c62008-09-29 13:37:00 -070093}
Russ Coxe4a61c62008-09-29 13:37:00 -070094
Russ Coxd8921c52009-02-15 14:18:39 -080095func (s *pollServer) AddFD(fd *netFD, mode int) {
Robert Griesemera3d10452009-12-15 15:35:38 -080096 intfd := fd.sysfd
Russ Cox37a53742009-04-15 19:01:48 -070097 if intfd < 0 {
98 // fd closed underfoot
99 if mode == 'r' {
Russ Coxcaa149f2010-04-06 16:50:27 -0700100 fd.cr <- true
Russ Cox37a53742009-04-15 19:01:48 -0700101 } else {
Russ Coxcaa149f2010-04-06 16:50:27 -0700102 fd.cw <- true
Russ Cox37a53742009-04-15 19:01:48 -0700103 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800104 return
Russ Cox37a53742009-04-15 19:01:48 -0700105 }
106 if err := s.poll.AddFD(intfd, mode, false); err != nil {
Rob Pike325cf8e2010-03-24 16:46:53 -0700107 panic("pollServer AddFD " + err.String())
Robert Griesemera3d10452009-12-15 15:35:38 -0800108 return
Russ Coxe4a61c62008-09-29 13:37:00 -0700109 }
110
Robert Griesemera3d10452009-12-15 15:35:38 -0800111 var t int64
112 key := intfd << 1
Russ Coxe4a61c62008-09-29 13:37:00 -0700113 if mode == 'r' {
Robert Griesemera3d10452009-12-15 15:35:38 -0800114 fd.ncr++
115 t = fd.rdeadline
Russ Coxe4a61c62008-09-29 13:37:00 -0700116 } else {
Robert Griesemera3d10452009-12-15 15:35:38 -0800117 fd.ncw++
118 key++
119 t = fd.wdeadline
Russ Coxe4a61c62008-09-29 13:37:00 -0700120 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800121 s.pending[key] = fd
Russ Cox1e37e8a2009-03-06 17:51:31 -0800122 if t > 0 && (s.deadline == 0 || t < s.deadline) {
Robert Griesemer40621d52009-11-09 12:07:39 -0800123 s.deadline = t
Russ Cox1e37e8a2009-03-06 17:51:31 -0800124 }
Russ Coxe4a61c62008-09-29 13:37:00 -0700125}
126
Russ Cox9e0fec92009-06-01 22:14:39 -0700127func (s *pollServer) LookupFD(fd int, mode int) *netFD {
Robert Griesemera3d10452009-12-15 15:35:38 -0800128 key := fd << 1
Russ Coxe4a61c62008-09-29 13:37:00 -0700129 if mode == 'w' {
Robert Griesemer40621d52009-11-09 12:07:39 -0800130 key++
Russ Coxe4a61c62008-09-29 13:37:00 -0700131 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800132 netfd, ok := s.pending[key]
Russ Coxe4a61c62008-09-29 13:37:00 -0700133 if !ok {
Robert Griesemer40621d52009-11-09 12:07:39 -0800134 return nil
Russ Coxe4a61c62008-09-29 13:37:00 -0700135 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800136 s.pending[key] = nil, false
137 return netfd
Russ Coxe4a61c62008-09-29 13:37:00 -0700138}
139
Russ Cox1e37e8a2009-03-06 17:51:31 -0800140func (s *pollServer) WakeFD(fd *netFD, mode int) {
141 if mode == 'r' {
142 for fd.ncr > 0 {
Robert Griesemera3d10452009-12-15 15:35:38 -0800143 fd.ncr--
Russ Coxcaa149f2010-04-06 16:50:27 -0700144 fd.cr <- true
Russ Cox1e37e8a2009-03-06 17:51:31 -0800145 }
146 } else {
147 for fd.ncw > 0 {
Robert Griesemera3d10452009-12-15 15:35:38 -0800148 fd.ncw--
Russ Coxcaa149f2010-04-06 16:50:27 -0700149 fd.cw <- true
Russ Cox1e37e8a2009-03-06 17:51:31 -0800150 }
151 }
152}
153
154func (s *pollServer) Now() int64 {
Russ Cox00f9f0c2010-03-30 10:34:57 -0700155 return time.Nanoseconds()
Russ Cox1e37e8a2009-03-06 17:51:31 -0800156}
157
158func (s *pollServer) CheckDeadlines() {
Robert Griesemera3d10452009-12-15 15:35:38 -0800159 now := s.Now()
Russ Cox1e37e8a2009-03-06 17:51:31 -0800160 // TODO(rsc): This will need to be handled more efficiently,
161 // probably with a heap indexed by wakeup time.
162
Robert Griesemera3d10452009-12-15 15:35:38 -0800163 var next_deadline int64
Russ Cox1e37e8a2009-03-06 17:51:31 -0800164 for key, fd := range s.pending {
Robert Griesemera3d10452009-12-15 15:35:38 -0800165 var t int64
166 var mode int
Russ Cox1e37e8a2009-03-06 17:51:31 -0800167 if key&1 == 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800168 mode = 'r'
Russ Cox1e37e8a2009-03-06 17:51:31 -0800169 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800170 mode = 'w'
Russ Cox1e37e8a2009-03-06 17:51:31 -0800171 }
172 if mode == 'r' {
Robert Griesemer40621d52009-11-09 12:07:39 -0800173 t = fd.rdeadline
Russ Cox1e37e8a2009-03-06 17:51:31 -0800174 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800175 t = fd.wdeadline
Russ Cox1e37e8a2009-03-06 17:51:31 -0800176 }
177 if t > 0 {
178 if t <= now {
Robert Griesemera3d10452009-12-15 15:35:38 -0800179 s.pending[key] = nil, false
Russ Cox1e37e8a2009-03-06 17:51:31 -0800180 if mode == 'r' {
Robert Griesemera3d10452009-12-15 15:35:38 -0800181 s.poll.DelFD(fd.sysfd, mode)
182 fd.rdeadline = -1
Russ Cox1e37e8a2009-03-06 17:51:31 -0800183 } else {
Robert Griesemera3d10452009-12-15 15:35:38 -0800184 s.poll.DelFD(fd.sysfd, mode)
185 fd.wdeadline = -1
Russ Cox1e37e8a2009-03-06 17:51:31 -0800186 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800187 s.WakeFD(fd, mode)
Russ Cox1e37e8a2009-03-06 17:51:31 -0800188 } else if next_deadline == 0 || t < next_deadline {
Robert Griesemer40621d52009-11-09 12:07:39 -0800189 next_deadline = t
Russ Cox1e37e8a2009-03-06 17:51:31 -0800190 }
191 }
192 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800193 s.deadline = next_deadline
Russ Cox1e37e8a2009-03-06 17:51:31 -0800194}
195
Vinu Rajashekhar00ad47f2010-06-29 12:04:04 -0700196func (s *pollServer) Run() {
197 var scratch [100]byte
198 for {
199 var t = s.deadline
200 if t > 0 {
201 t = t - s.Now()
202 if t <= 0 {
203 s.CheckDeadlines()
204 continue
205 }
206 }
207 fd, mode, err := s.poll.WaitFD(t)
208 if err != nil {
209 print("pollServer WaitFD: ", err.String(), "\n")
210 return
211 }
212 if fd < 0 {
213 // Timeout happened.
214 s.CheckDeadlines()
215 continue
216 }
217 if fd == s.pr.Fd() {
218 // Drain our wakeup pipe.
219 for nn, _ := s.pr.Read(scratch[0:]); nn > 0; {
220 nn, _ = s.pr.Read(scratch[0:])
221 }
222 // Read from channels
223 for fd, ok := <-s.cr; ok; fd, ok = <-s.cr {
224 s.AddFD(fd, 'r')
225 }
226 for fd, ok := <-s.cw; ok; fd, ok = <-s.cw {
227 s.AddFD(fd, 'w')
228 }
229 } else {
230 netfd := s.LookupFD(fd, mode)
231 if netfd == nil {
Vinu Rajashekhara9a24d42010-07-10 14:40:48 -0700232 print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n")
Vinu Rajashekhar00ad47f2010-06-29 12:04:04 -0700233 continue
234 }
235 s.WakeFD(netfd, mode)
236 }
237 }
238}
239
Robert Griesemer5d377052009-11-04 23:16:46 -0800240var wakeupbuf [1]byte
241
Russ Coxbb84f4b2010-05-27 14:51:47 -0700242func (s *pollServer) Wakeup() { s.pw.Write(wakeupbuf[0:]) }
Russ Coxe4a61c62008-09-29 13:37:00 -0700243
Russ Coxd8921c52009-02-15 14:18:39 -0800244func (s *pollServer) WaitRead(fd *netFD) {
Robert Griesemera3d10452009-12-15 15:35:38 -0800245 s.cr <- fd
246 s.Wakeup()
247 <-fd.cr
Russ Coxe4a61c62008-09-29 13:37:00 -0700248}
249
Russ Coxd8921c52009-02-15 14:18:39 -0800250func (s *pollServer) WaitWrite(fd *netFD) {
Robert Griesemera3d10452009-12-15 15:35:38 -0800251 s.cw <- fd
252 s.Wakeup()
253 <-fd.cw
Russ Coxe4a61c62008-09-29 13:37:00 -0700254}
255
Russ Coxe4a61c62008-09-29 13:37:00 -0700256// Network FD methods.
Russ Coxd8921c52009-02-15 14:18:39 -0800257// All the network FDs use a single pollServer.
Russ Coxe4a61c62008-09-29 13:37:00 -0700258
Russ Coxd8921c52009-02-15 14:18:39 -0800259var pollserver *pollServer
Rob Pikec78be462010-08-06 06:14:41 +1000260var onceStartServer sync.Once
Russ Coxe4a61c62008-09-29 13:37:00 -0700261
Russ Coxc83b8382009-11-02 18:37:30 -0800262func startServer() {
Robert Griesemera3d10452009-12-15 15:35:38 -0800263 p, err := newPollServer()
Russ Coxe4a61c62008-09-29 13:37:00 -0700264 if err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800265 print("Start pollServer: ", err.String(), "\n")
Russ Coxe4a61c62008-09-29 13:37:00 -0700266 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800267 pollserver = p
Russ Coxe4a61c62008-09-29 13:37:00 -0700268}
269
Russ Coxc83b8382009-11-02 18:37:30 -0800270func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
Rob Pikec78be462010-08-06 06:14:41 +1000271 onceStartServer.Do(startServer)
Russ Cox9e0fec92009-06-01 22:14:39 -0700272 if e := syscall.SetNonblock(fd, true); e != 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800273 return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)}
Russ Coxe4a61c62008-09-29 13:37:00 -0700274 }
Russ Coxc83b8382009-11-02 18:37:30 -0800275 f = &netFD{
Robert Griesemerf44fa9b2010-03-02 13:46:51 -0800276 sysfd: fd,
Russ Coxc83b8382009-11-02 18:37:30 -0800277 family: family,
Robert Griesemerf44fa9b2010-03-02 13:46:51 -0800278 proto: proto,
279 net: net,
280 laddr: laddr,
281 raddr: raddr,
Robert Griesemera3d10452009-12-15 15:35:38 -0800282 }
283 var ls, rs string
Russ Coxc83b8382009-11-02 18:37:30 -0800284 if laddr != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800285 ls = laddr.String()
Russ Coxc83b8382009-11-02 18:37:30 -0800286 }
287 if raddr != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800288 rs = raddr.String()
Russ Coxc83b8382009-11-02 18:37:30 -0800289 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800290 f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs)
Russ Coxcaa149f2010-04-06 16:50:27 -0700291 f.cr = make(chan bool, 1)
292 f.cw = make(chan bool, 1)
Robert Griesemera3d10452009-12-15 15:35:38 -0800293 return f, nil
Russ Coxe4a61c62008-09-29 13:37:00 -0700294}
295
Devon H. O'Delleb163462009-12-01 23:28:57 -0800296// Add a reference to this fd.
297func (fd *netFD) incref() {
Robert Griesemera3d10452009-12-15 15:35:38 -0800298 fd.sysmu.Lock()
299 fd.sysref++
300 fd.sysmu.Unlock()
Devon H. O'Delleb163462009-12-01 23:28:57 -0800301}
302
303// Remove a reference to this FD and close if we've been asked to do so (and
304// there are no references left.
305func (fd *netFD) decref() {
Robert Griesemera3d10452009-12-15 15:35:38 -0800306 fd.sysmu.Lock()
307 fd.sysref--
Devon H. O'Delleb163462009-12-01 23:28:57 -0800308 if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
309 // In case the user has set linger, switch to blocking mode so
310 // the close blocks. As long as this doesn't happen often, we
311 // can handle the extra OS processes. Otherwise we'll need to
312 // use the pollserver for Close too. Sigh.
Robert Griesemera3d10452009-12-15 15:35:38 -0800313 syscall.SetNonblock(fd.sysfd, false)
314 fd.sysfile.Close()
315 fd.sysfile = nil
316 fd.sysfd = -1
Devon H. O'Delleb163462009-12-01 23:28:57 -0800317 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800318 fd.sysmu.Unlock()
Devon H. O'Delleb163462009-12-01 23:28:57 -0800319}
320
Rob Pikeaaf63f82009-04-17 00:08:24 -0700321func (fd *netFD) Close() os.Error {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800322 if fd == nil || fd.sysfile == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800323 return os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700324 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800325
Robert Griesemera3d10452009-12-15 15:35:38 -0800326 fd.incref()
327 syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
328 fd.closing = true
329 fd.decref()
330 return nil
Russ Coxe4a61c62008-09-29 13:37:00 -0700331}
332
Rob Pikeaaf63f82009-04-17 00:08:24 -0700333func (fd *netFD) Read(p []byte) (n int, err os.Error) {
Michael Hoisie9192ec22010-05-20 17:13:50 -0700334 if fd == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800335 return 0, os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700336 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800337 fd.rio.Lock()
338 defer fd.rio.Unlock()
339 fd.incref()
340 defer fd.decref()
Michael Hoisie9192ec22010-05-20 17:13:50 -0700341 if fd.sysfile == nil {
342 return 0, os.EINVAL
343 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800344 if fd.rdeadline_delta > 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800345 fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
Russ Cox1e37e8a2009-03-06 17:51:31 -0800346 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800347 fd.rdeadline = 0
Russ Cox1e37e8a2009-03-06 17:51:31 -0800348 }
Russ Cox47a05332010-04-26 22:15:25 -0700349 var oserr os.Error
Russ Coxa0bcaf42009-06-25 20:24:55 -0700350 for {
Russ Cox47a05332010-04-26 22:15:25 -0700351 var errno int
352 n, errno = syscall.Read(fd.sysfile.Fd(), p)
353 if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
Robert Griesemera3d10452009-12-15 15:35:38 -0800354 pollserver.WaitRead(fd)
355 continue
Russ Coxa0bcaf42009-06-25 20:24:55 -0700356 }
Russ Cox47a05332010-04-26 22:15:25 -0700357 if errno != 0 {
358 n = 0
359 oserr = os.Errno(errno)
360 } else if n == 0 && errno == 0 && fd.proto != syscall.SOCK_DGRAM {
361 err = os.EOF
362 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800363 break
Russ Coxe4a61c62008-09-29 13:37:00 -0700364 }
Russ Cox47a05332010-04-26 22:15:25 -0700365 if oserr != nil {
366 err = &OpError{"read", fd.net, fd.raddr, oserr}
Russ Coxe89441b2009-12-02 15:17:49 -0800367 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800368 return
Russ Coxe4a61c62008-09-29 13:37:00 -0700369}
370
Russ Cox6e788e02009-11-17 08:39:17 -0800371func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800372 if fd == nil || fd.sysfile == nil {
Russ Cox6e788e02009-11-17 08:39:17 -0800373 return 0, nil, os.EINVAL
374 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800375 fd.rio.Lock()
376 defer fd.rio.Unlock()
377 fd.incref()
378 defer fd.decref()
Russ Cox6e788e02009-11-17 08:39:17 -0800379 if fd.rdeadline_delta > 0 {
380 fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
381 } else {
382 fd.rdeadline = 0
383 }
Russ Cox47a05332010-04-26 22:15:25 -0700384 var oserr os.Error
Russ Cox6e788e02009-11-17 08:39:17 -0800385 for {
Robert Griesemera3d10452009-12-15 15:35:38 -0800386 var errno int
387 n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0)
Russ Cox6e788e02009-11-17 08:39:17 -0800388 if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
Robert Griesemera3d10452009-12-15 15:35:38 -0800389 pollserver.WaitRead(fd)
390 continue
Russ Cox6e788e02009-11-17 08:39:17 -0800391 }
392 if errno != 0 {
Robert Griesemera3d10452009-12-15 15:35:38 -0800393 n = 0
Russ Cox47a05332010-04-26 22:15:25 -0700394 oserr = os.Errno(errno)
Russ Cox6e788e02009-11-17 08:39:17 -0800395 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800396 break
Russ Cox6e788e02009-11-17 08:39:17 -0800397 }
Russ Cox47a05332010-04-26 22:15:25 -0700398 if oserr != nil {
399 err = &OpError{"read", fd.net, fd.laddr, oserr}
400 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800401 return
Russ Cox6e788e02009-11-17 08:39:17 -0800402}
403
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500404func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) {
405 if fd == nil || fd.sysfile == nil {
406 return 0, 0, 0, nil, os.EINVAL
407 }
408 fd.rio.Lock()
409 defer fd.rio.Unlock()
410 fd.incref()
411 defer fd.decref()
412 if fd.rdeadline_delta > 0 {
413 fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
414 } else {
415 fd.rdeadline = 0
416 }
417 var oserr os.Error
418 for {
419 var errno int
420 n, oobn, flags, errno = syscall.Recvmsg(fd.sysfd, p, oob, sa, 0)
421 if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
422 pollserver.WaitRead(fd)
423 continue
424 }
425 if errno != 0 {
426 oserr = os.Errno(errno)
427 }
428 if n == 0 {
429 oserr = os.EOF
430 }
431 break
432 }
433 if oserr != nil {
434 err = &OpError{"read", fd.net, fd.laddr, oserr}
435 return
436 }
437 return
438}
439
Rob Pikeaaf63f82009-04-17 00:08:24 -0700440func (fd *netFD) Write(p []byte) (n int, err os.Error) {
Michael Hoisie9192ec22010-05-20 17:13:50 -0700441 if fd == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800442 return 0, os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700443 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800444 fd.wio.Lock()
445 defer fd.wio.Unlock()
446 fd.incref()
447 defer fd.decref()
Michael Hoisie9192ec22010-05-20 17:13:50 -0700448 if fd.sysfile == nil {
449 return 0, os.EINVAL
450 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800451 if fd.wdeadline_delta > 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800452 fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
Russ Cox1e37e8a2009-03-06 17:51:31 -0800453 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800454 fd.wdeadline = 0
Russ Cox1e37e8a2009-03-06 17:51:31 -0800455 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800456 nn := 0
Russ Cox47a05332010-04-26 22:15:25 -0700457 var oserr os.Error
Michael Hoisie9192ec22010-05-20 17:13:50 -0700458
Russ Cox47a05332010-04-26 22:15:25 -0700459 for {
460 n, errno := syscall.Write(fd.sysfile.Fd(), p[nn:])
Russ Coxe4a61c62008-09-29 13:37:00 -0700461 if n > 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800462 nn += n
Russ Coxe4a61c62008-09-29 13:37:00 -0700463 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800464 if nn == len(p) {
Robert Griesemer40621d52009-11-09 12:07:39 -0800465 break
Russ Cox1e37e8a2009-03-06 17:51:31 -0800466 }
Russ Cox47a05332010-04-26 22:15:25 -0700467 if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
Robert Griesemera3d10452009-12-15 15:35:38 -0800468 pollserver.WaitWrite(fd)
469 continue
Russ Cox1e37e8a2009-03-06 17:51:31 -0800470 }
Russ Cox47a05332010-04-26 22:15:25 -0700471 if errno != 0 {
472 n = 0
473 oserr = os.Errno(errno)
Robert Griesemer40621d52009-11-09 12:07:39 -0800474 break
Russ Coxe4a61c62008-09-29 13:37:00 -0700475 }
Russ Cox47a05332010-04-26 22:15:25 -0700476 if n == 0 {
477 oserr = io.ErrUnexpectedEOF
478 break
479 }
480 }
481 if oserr != nil {
482 err = &OpError{"write", fd.net, fd.raddr, oserr}
Russ Coxe4a61c62008-09-29 13:37:00 -0700483 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800484 return nn, err
Russ Coxe4a61c62008-09-29 13:37:00 -0700485}
486
Russ Cox6e788e02009-11-17 08:39:17 -0800487func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800488 if fd == nil || fd.sysfile == nil {
Russ Cox6e788e02009-11-17 08:39:17 -0800489 return 0, os.EINVAL
490 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800491 fd.wio.Lock()
492 defer fd.wio.Unlock()
493 fd.incref()
494 defer fd.decref()
Russ Cox6e788e02009-11-17 08:39:17 -0800495 if fd.wdeadline_delta > 0 {
496 fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
497 } else {
498 fd.wdeadline = 0
499 }
Russ Cox47a05332010-04-26 22:15:25 -0700500 var oserr os.Error
Russ Cox6e788e02009-11-17 08:39:17 -0800501 for {
Robert Griesemera3d10452009-12-15 15:35:38 -0800502 errno := syscall.Sendto(fd.sysfd, p, 0, sa)
Russ Cox6e788e02009-11-17 08:39:17 -0800503 if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
Robert Griesemera3d10452009-12-15 15:35:38 -0800504 pollserver.WaitWrite(fd)
505 continue
Russ Cox6e788e02009-11-17 08:39:17 -0800506 }
507 if errno != 0 {
Russ Cox47a05332010-04-26 22:15:25 -0700508 oserr = os.Errno(errno)
Russ Cox6e788e02009-11-17 08:39:17 -0800509 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800510 break
Russ Cox6e788e02009-11-17 08:39:17 -0800511 }
Russ Cox47a05332010-04-26 22:15:25 -0700512 if oserr == nil {
Russ Cox6e788e02009-11-17 08:39:17 -0800513 n = len(p)
Russ Cox47a05332010-04-26 22:15:25 -0700514 } else {
515 err = &OpError{"write", fd.net, fd.raddr, oserr}
Russ Cox6e788e02009-11-17 08:39:17 -0800516 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800517 return
Russ Cox6e788e02009-11-17 08:39:17 -0800518}
519
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500520func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) {
521 if fd == nil || fd.sysfile == nil {
522 return 0, 0, os.EINVAL
523 }
524 fd.wio.Lock()
525 defer fd.wio.Unlock()
526 fd.incref()
527 defer fd.decref()
528 if fd.wdeadline_delta > 0 {
529 fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
530 } else {
531 fd.wdeadline = 0
532 }
533 var oserr os.Error
534 for {
535 var errno int
536 errno = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
537 if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
538 pollserver.WaitWrite(fd)
539 continue
540 }
541 if errno != 0 {
542 oserr = os.Errno(errno)
543 }
544 break
545 }
546 if oserr == nil {
547 n = len(p)
548 oobn = len(oob)
549 } else {
550 err = &OpError{"write", fd.net, fd.raddr, oserr}
551 }
552 return
553}
554
Robert Griesemer5d377052009-11-04 23:16:46 -0800555func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800556 if fd == nil || fd.sysfile == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800557 return nil, os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700558 }
Russ Coxd8921c52009-02-15 14:18:39 -0800559
Robert Griesemera3d10452009-12-15 15:35:38 -0800560 fd.incref()
561 defer fd.decref()
Devon H. O'Delleb163462009-12-01 23:28:57 -0800562
Russ Cox91ceda52009-02-15 19:35:52 -0800563 // See ../syscall/exec.go for description of ForkLock.
564 // It is okay to hold the lock across syscall.Accept
Devon H. O'Delleb163462009-12-01 23:28:57 -0800565 // because we have put fd.sysfd into non-blocking mode.
Robert Griesemera3d10452009-12-15 15:35:38 -0800566 syscall.ForkLock.RLock()
567 var s, e int
568 var sa syscall.Sockaddr
Russ Coxd8921c52009-02-15 14:18:39 -0800569 for {
Michael Hoisieed1cbca2011-01-04 11:55:13 -0500570 if fd.closing {
571 syscall.ForkLock.RUnlock()
572 return nil, os.EINVAL
573 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800574 s, sa, e = syscall.Accept(fd.sysfd)
Russ Coxd8921c52009-02-15 14:18:39 -0800575 if e != syscall.EAGAIN {
Robert Griesemer40621d52009-11-09 12:07:39 -0800576 break
Russ Coxd8921c52009-02-15 14:18:39 -0800577 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800578 syscall.ForkLock.RUnlock()
579 pollserver.WaitRead(fd)
580 syscall.ForkLock.RLock()
Russ Coxe4a61c62008-09-29 13:37:00 -0700581 }
582 if e != 0 {
Robert Griesemera3d10452009-12-15 15:35:38 -0800583 syscall.ForkLock.RUnlock()
584 return nil, &OpError{"accept", fd.net, fd.laddr, os.Errno(e)}
Russ Coxe4a61c62008-09-29 13:37:00 -0700585 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800586 syscall.CloseOnExec(s)
587 syscall.ForkLock.RUnlock()
Russ Coxd8921c52009-02-15 14:18:39 -0800588
Russ Coxc83b8382009-11-02 18:37:30 -0800589 if nfd, err = newFD(s, fd.family, fd.proto, fd.net, fd.laddr, toAddr(sa)); err != nil {
Robert Griesemera3d10452009-12-15 15:35:38 -0800590 syscall.Close(s)
591 return nil, err
Russ Coxe4a61c62008-09-29 13:37:00 -0700592 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800593 return nfd, nil
Russ Coxe4a61c62008-09-29 13:37:00 -0700594}
Keith Raricka144e3e2010-11-05 14:02:03 -0400595
596func (fd *netFD) dup() (f *os.File, err os.Error) {
597 ns, e := syscall.Dup(fd.sysfd)
598 if e != 0 {
599 return nil, &OpError{"dup", fd.net, fd.laddr, os.Errno(e)}
600 }
601
602 // We want blocking mode for the new fd, hence the double negative.
603 if e = syscall.SetNonblock(ns, false); e != 0 {
604 return nil, &OpError{"setnonblock", fd.net, fd.laddr, os.Errno(e)}
605 }
606
607 return os.NewFile(ns, fd.sysfile.Name()), nil
608}
Alex Brainman3a052b52011-01-12 15:55:17 +1100609
610func closesocket(s int) (errno int) {
611 return syscall.Close(s)
612}