blob: e1592eb2691f3faed858ae00474ad667e1715423 [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 Coxe4a61c62008-09-29 13:37:00 -070010 "once";
11 "os";
Russ Cox1e37e8a2009-03-06 17:51:31 -080012 "sync";
Russ Coxe4a61c62008-09-29 13:37:00 -070013 "syscall";
14)
15
Russ Coxd8921c52009-02-15 14:18:39 -080016// Network file descriptor.
17type netFD struct {
Devon H. O'Delleb163462009-12-01 23:28:57 -080018 // locking/lifetime of sysfd
19 sysmu sync.Mutex;
20 sysref int;
21 closing bool;
22
Russ Coxe4a61c62008-09-29 13:37:00 -070023 // immutable until Close
Devon H. O'Delleb163462009-12-01 23:28:57 -080024 sysfd int;
Robert Griesemer5d377052009-11-04 23:16:46 -080025 family int;
26 proto int;
Devon H. O'Delleb163462009-12-01 23:28:57 -080027 sysfile *os.File;
Robert Griesemer5d377052009-11-04 23:16:46 -080028 cr chan *netFD;
29 cw chan *netFD;
30 net string;
31 laddr Addr;
32 raddr Addr;
Russ Coxe4a61c62008-09-29 13:37:00 -070033
Russ Cox1e37e8a2009-03-06 17:51:31 -080034 // owned by client
Robert Griesemer5d377052009-11-04 23:16:46 -080035 rdeadline_delta int64;
36 rdeadline int64;
37 rio sync.Mutex;
38 wdeadline_delta int64;
39 wdeadline int64;
40 wio sync.Mutex;
Russ Cox1e37e8a2009-03-06 17:51:31 -080041
Russ Coxe4a61c62008-09-29 13:37:00 -070042 // owned by fd wait server
Robert Griesemer5d377052009-11-04 23:16:46 -080043 ncr, ncw int;
Russ Coxe4a61c62008-09-29 13:37:00 -070044}
45
Russ Coxd8921c52009-02-15 14:18:39 -080046// A pollServer helps FDs determine when to retry a non-blocking
Russ Coxe4a61c62008-09-29 13:37:00 -070047// read or write after they get EAGAIN. When an FD needs to wait,
48// send the fd on s.cr (for a read) or s.cw (for a write) to pass the
49// request to the poll server. Then receive on fd.cr/fd.cw.
Russ Coxd8921c52009-02-15 14:18:39 -080050// When the pollServer finds that i/o on FD should be possible
Russ Coxe4a61c62008-09-29 13:37:00 -070051// again, it will send fd on fd.cr/fd.cw to wake any waiting processes.
52// This protocol is implemented as s.WaitRead() and s.WaitWrite().
53//
54// There is one subtlety: when sending on s.cr/s.cw, the
55// poll server is probably in a system call, waiting for an fd
56// to become ready. It's not looking at the request channels.
57// To resolve this, the poll server waits not just on the FDs it has
58// been given but also its own pipe. After sending on the
59// buffered channel s.cr/s.cw, WaitRead/WaitWrite writes a
Russ Coxd8921c52009-02-15 14:18:39 -080060// byte to the pipe, causing the pollServer's poll system call to
61// return. In response to the pipe being readable, the pollServer
Russ Coxe4a61c62008-09-29 13:37:00 -070062// re-polls its request channels.
63//
64// Note that the ordering is "send request" and then "wake up server".
65// If the operations were reversed, there would be a race: the poll
66// server might wake up and look at the request channel, see that it
67// was empty, and go back to sleep, all before the requester managed
68// to send the request. Because the send must complete before the wakeup,
69// the request channel must be buffered. A buffer of size 1 is sufficient
70// for any request load. If many processes are trying to submit requests,
Russ Coxd8921c52009-02-15 14:18:39 -080071// one will succeed, the pollServer will read the request, and then the
Russ Coxe4a61c62008-09-29 13:37:00 -070072// channel will be empty for the next process's request. A larger buffer
73// might help batch requests.
Adam Langleyef8f4832009-11-18 13:18:34 -080074//
Devon H. O'Delleb163462009-12-01 23:28:57 -080075// To avoid races in closing, all fd operations are locked and
76// refcounted. when netFD.Close() is called, it calls syscall.Shutdown
77// and sets a closing flag. Only when the last reference is removed
78// will the fd be closed.
Russ Coxe4a61c62008-09-29 13:37:00 -070079
Russ Coxd8921c52009-02-15 14:18:39 -080080type pollServer struct {
Devon H. O'Delleb163462009-12-01 23:28:57 -080081 cr, cw chan *netFD; // buffered >= 1
Robert Griesemer5d377052009-11-04 23:16:46 -080082 pr, pw *os.File;
83 pending map[int]*netFD;
84 poll *pollster; // low-level OS hooks
85 deadline int64; // next deadline (nsec since 1970)
Russ Coxe4a61c62008-09-29 13:37:00 -070086}
Russ Coxe4a61c62008-09-29 13:37:00 -070087
Rob Pikeaaf63f82009-04-17 00:08:24 -070088func newPollServer() (s *pollServer, err os.Error) {
Russ Coxd8921c52009-02-15 14:18:39 -080089 s = new(pollServer);
90 s.cr = make(chan *netFD, 1);
91 s.cw = make(chan *netFD, 1);
Russ Coxe4a61c62008-09-29 13:37:00 -070092 if s.pr, s.pw, err = os.Pipe(); err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -080093 return nil, err
Russ Coxe4a61c62008-09-29 13:37:00 -070094 }
Russ Cox9e0fec92009-06-01 22:14:39 -070095 var e int;
96 if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
97 Errno:
Russ Coxa0bcaf42009-06-25 20:24:55 -070098 err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)};
Russ Coxe4a61c62008-09-29 13:37:00 -070099 Error:
100 s.pr.Close();
Russ Cox983f06b2008-10-07 12:31:31 -0700101 s.pw.Close();
Russ Cox9e0fec92009-06-01 22:14:39 -0700102 return nil, err;
Russ Coxe4a61c62008-09-29 13:37:00 -0700103 }
Russ Cox9e0fec92009-06-01 22:14:39 -0700104 if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800105 goto Errno
Russ Coxe4a61c62008-09-29 13:37:00 -0700106 }
Russ Coxc93da7c72009-03-05 15:48:12 -0800107 if s.poll, err = newpollster(); err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800108 goto Error
Russ Coxe4a61c62008-09-29 13:37:00 -0700109 }
Rob Pike704bc9d2009-02-06 17:54:26 -0800110 if err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil {
Russ Cox983f06b2008-10-07 12:31:31 -0700111 s.poll.Close();
Robert Griesemer5d377052009-11-04 23:16:46 -0800112 goto Error;
Russ Coxe4a61c62008-09-29 13:37:00 -0700113 }
Robert Griesemer5d377052009-11-04 23:16:46 -0800114 s.pending = make(map[int]*netFD);
Russ Cox983f06b2008-10-07 12:31:31 -0700115 go s.Run();
Robert Griesemer5d377052009-11-04 23:16:46 -0800116 return s, nil;
Russ Coxe4a61c62008-09-29 13:37:00 -0700117}
118
Russ Coxd8921c52009-02-15 14:18:39 -0800119func (s *pollServer) AddFD(fd *netFD, mode int) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800120 intfd := fd.sysfd;
Russ Cox37a53742009-04-15 19:01:48 -0700121 if intfd < 0 {
122 // fd closed underfoot
123 if mode == 'r' {
Robert Griesemer40621d52009-11-09 12:07:39 -0800124 fd.cr <- fd
Russ Cox37a53742009-04-15 19:01:48 -0700125 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800126 fd.cw <- fd
Russ Cox37a53742009-04-15 19:01:48 -0700127 }
Robert Griesemer5d377052009-11-04 23:16:46 -0800128 return;
Russ Cox37a53742009-04-15 19:01:48 -0700129 }
130 if err := s.poll.AddFD(intfd, mode, false); err != nil {
131 panicln("pollServer AddFD ", intfd, ": ", err.String(), "\n");
Robert Griesemer5d377052009-11-04 23:16:46 -0800132 return;
Russ Coxe4a61c62008-09-29 13:37:00 -0700133 }
134
Russ Cox1e37e8a2009-03-06 17:51:31 -0800135 var t int64;
Robert Griesemer3bb00322009-11-09 21:23:52 -0800136 key := intfd << 1;
Russ Coxe4a61c62008-09-29 13:37:00 -0700137 if mode == 'r' {
Russ Cox983f06b2008-10-07 12:31:31 -0700138 fd.ncr++;
Russ Cox1e37e8a2009-03-06 17:51:31 -0800139 t = fd.rdeadline;
Russ Coxe4a61c62008-09-29 13:37:00 -0700140 } else {
Russ Cox983f06b2008-10-07 12:31:31 -0700141 fd.ncw++;
142 key++;
Russ Cox1e37e8a2009-03-06 17:51:31 -0800143 t = fd.wdeadline;
Russ Coxe4a61c62008-09-29 13:37:00 -0700144 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800145 s.pending[key] = fd;
146 if t > 0 && (s.deadline == 0 || t < s.deadline) {
Robert Griesemer40621d52009-11-09 12:07:39 -0800147 s.deadline = t
Russ Cox1e37e8a2009-03-06 17:51:31 -0800148 }
Russ Coxe4a61c62008-09-29 13:37:00 -0700149}
150
Russ Cox9e0fec92009-06-01 22:14:39 -0700151func (s *pollServer) LookupFD(fd int, mode int) *netFD {
Robert Griesemer3bb00322009-11-09 21:23:52 -0800152 key := fd << 1;
Russ Coxe4a61c62008-09-29 13:37:00 -0700153 if mode == 'w' {
Robert Griesemer40621d52009-11-09 12:07:39 -0800154 key++
Russ Coxe4a61c62008-09-29 13:37:00 -0700155 }
Russ Cox983f06b2008-10-07 12:31:31 -0700156 netfd, ok := s.pending[key];
Russ Coxe4a61c62008-09-29 13:37:00 -0700157 if !ok {
Robert Griesemer40621d52009-11-09 12:07:39 -0800158 return nil
Russ Coxe4a61c62008-09-29 13:37:00 -0700159 }
Russ Cox983f06b2008-10-07 12:31:31 -0700160 s.pending[key] = nil, false;
Robert Griesemer5d377052009-11-04 23:16:46 -0800161 return netfd;
Russ Coxe4a61c62008-09-29 13:37:00 -0700162}
163
Russ Cox1e37e8a2009-03-06 17:51:31 -0800164func (s *pollServer) WakeFD(fd *netFD, mode int) {
165 if mode == 'r' {
166 for fd.ncr > 0 {
167 fd.ncr--;
Robert Griesemer5d377052009-11-04 23:16:46 -0800168 fd.cr <- fd;
Russ Cox1e37e8a2009-03-06 17:51:31 -0800169 }
170 } else {
171 for fd.ncw > 0 {
172 fd.ncw--;
Robert Griesemer5d377052009-11-04 23:16:46 -0800173 fd.cw <- fd;
Russ Cox1e37e8a2009-03-06 17:51:31 -0800174 }
175 }
176}
177
178func (s *pollServer) Now() int64 {
179 sec, nsec, err := os.Time();
180 if err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800181 panic("net: os.Time: ", err.String())
Russ Cox1e37e8a2009-03-06 17:51:31 -0800182 }
Robert Griesemer3bb00322009-11-09 21:23:52 -0800183 nsec += sec * 1e9;
Russ Cox1e37e8a2009-03-06 17:51:31 -0800184 return nsec;
185}
186
187func (s *pollServer) CheckDeadlines() {
188 now := s.Now();
189 // TODO(rsc): This will need to be handled more efficiently,
190 // probably with a heap indexed by wakeup time.
191
192 var next_deadline int64;
193 for key, fd := range s.pending {
194 var t int64;
195 var mode int;
196 if key&1 == 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800197 mode = 'r'
Russ Cox1e37e8a2009-03-06 17:51:31 -0800198 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800199 mode = 'w'
Russ Cox1e37e8a2009-03-06 17:51:31 -0800200 }
201 if mode == 'r' {
Robert Griesemer40621d52009-11-09 12:07:39 -0800202 t = fd.rdeadline
Russ Cox1e37e8a2009-03-06 17:51:31 -0800203 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800204 t = fd.wdeadline
Russ Cox1e37e8a2009-03-06 17:51:31 -0800205 }
206 if t > 0 {
207 if t <= now {
208 s.pending[key] = nil, false;
209 if mode == 'r' {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800210 s.poll.DelFD(fd.sysfd, mode);
Russ Cox1e37e8a2009-03-06 17:51:31 -0800211 fd.rdeadline = -1;
212 } else {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800213 s.poll.DelFD(fd.sysfd, mode);
Russ Cox1e37e8a2009-03-06 17:51:31 -0800214 fd.wdeadline = -1;
215 }
216 s.WakeFD(fd, mode);
217 } else if next_deadline == 0 || t < next_deadline {
Robert Griesemer40621d52009-11-09 12:07:39 -0800218 next_deadline = t
Russ Cox1e37e8a2009-03-06 17:51:31 -0800219 }
220 }
221 }
222 s.deadline = next_deadline;
223}
224
Russ Coxd8921c52009-02-15 14:18:39 -0800225func (s *pollServer) Run() {
Russ Coxe4a61c62008-09-29 13:37:00 -0700226 var scratch [100]byte;
227 for {
Russ Cox1e37e8a2009-03-06 17:51:31 -0800228 var t = s.deadline;
229 if t > 0 {
230 t = t - s.Now();
231 if t < 0 {
232 s.CheckDeadlines();
233 continue;
234 }
235 }
236 fd, mode, err := s.poll.WaitFD(t);
Russ Coxe4a61c62008-09-29 13:37:00 -0700237 if err != nil {
Russ Coxd8921c52009-02-15 14:18:39 -0800238 print("pollServer WaitFD: ", err.String(), "\n");
Robert Griesemer5d377052009-11-04 23:16:46 -0800239 return;
Russ Coxe4a61c62008-09-29 13:37:00 -0700240 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800241 if fd < 0 {
242 // Timeout happened.
243 s.CheckDeadlines();
244 continue;
245 }
Rob Pike704bc9d2009-02-06 17:54:26 -0800246 if fd == s.pr.Fd() {
Russ Coxe4a61c62008-09-29 13:37:00 -0700247 // Drain our wakeup pipe.
Russ Coxca6a0fe2009-09-15 09:41:59 -0700248 for nn, _ := s.pr.Read(&scratch); nn > 0; {
Robert Griesemer40621d52009-11-09 12:07:39 -0800249 nn, _ = s.pr.Read(&scratch)
Russ Coxe4a61c62008-09-29 13:37:00 -0700250 }
Russ Coxe4a61c62008-09-29 13:37:00 -0700251 // Read from channels
252 for fd, ok := <-s.cr; ok; fd, ok = <-s.cr {
Robert Griesemer40621d52009-11-09 12:07:39 -0800253 s.AddFD(fd, 'r')
Russ Coxe4a61c62008-09-29 13:37:00 -0700254 }
255 for fd, ok := <-s.cw; ok; fd, ok = <-s.cw {
Robert Griesemer40621d52009-11-09 12:07:39 -0800256 s.AddFD(fd, 'w')
Russ Coxe4a61c62008-09-29 13:37:00 -0700257 }
258 } else {
Russ Cox983f06b2008-10-07 12:31:31 -0700259 netfd := s.LookupFD(fd, mode);
Russ Coxe4a61c62008-09-29 13:37:00 -0700260 if netfd == nil {
Russ Coxd8921c52009-02-15 14:18:39 -0800261 print("pollServer: unexpected wakeup for fd=", netfd, " mode=", string(mode), "\n");
Robert Griesemer5d377052009-11-04 23:16:46 -0800262 continue;
Russ Coxe4a61c62008-09-29 13:37:00 -0700263 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800264 s.WakeFD(netfd, mode);
Russ Coxe4a61c62008-09-29 13:37:00 -0700265 }
266 }
267}
268
Robert Griesemer5d377052009-11-04 23:16:46 -0800269var wakeupbuf [1]byte
270
Robert Griesemer368f8cb2009-11-06 14:24:38 -0800271func (s *pollServer) Wakeup() { s.pw.Write(&wakeupbuf) }
Russ Coxe4a61c62008-09-29 13:37:00 -0700272
Russ Coxd8921c52009-02-15 14:18:39 -0800273func (s *pollServer) WaitRead(fd *netFD) {
Russ Coxe4a61c62008-09-29 13:37:00 -0700274 s.cr <- fd;
275 s.Wakeup();
Robert Griesemer5d377052009-11-04 23:16:46 -0800276 <-fd.cr;
Russ Coxe4a61c62008-09-29 13:37:00 -0700277}
278
Russ Coxd8921c52009-02-15 14:18:39 -0800279func (s *pollServer) WaitWrite(fd *netFD) {
Brendan O'Dea7326a382009-04-29 17:36:37 -0700280 s.cw <- fd;
Russ Coxe4a61c62008-09-29 13:37:00 -0700281 s.Wakeup();
Robert Griesemer5d377052009-11-04 23:16:46 -0800282 <-fd.cw;
Russ Coxe4a61c62008-09-29 13:37:00 -0700283}
284
Russ Coxe4a61c62008-09-29 13:37:00 -0700285// Network FD methods.
Russ Coxd8921c52009-02-15 14:18:39 -0800286// All the network FDs use a single pollServer.
Russ Coxe4a61c62008-09-29 13:37:00 -0700287
Russ Coxd8921c52009-02-15 14:18:39 -0800288var pollserver *pollServer
Russ Coxe4a61c62008-09-29 13:37:00 -0700289
Russ Coxc83b8382009-11-02 18:37:30 -0800290func startServer() {
Russ Coxd8921c52009-02-15 14:18:39 -0800291 p, err := newPollServer();
Russ Coxe4a61c62008-09-29 13:37:00 -0700292 if err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800293 print("Start pollServer: ", err.String(), "\n")
Russ Coxe4a61c62008-09-29 13:37:00 -0700294 }
Robert Griesemer5d377052009-11-04 23:16:46 -0800295 pollserver = p;
Russ Coxe4a61c62008-09-29 13:37:00 -0700296}
297
Russ Coxc83b8382009-11-02 18:37:30 -0800298func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
299 once.Do(startServer);
Russ Cox9e0fec92009-06-01 22:14:39 -0700300 if e := syscall.SetNonblock(fd, true); e != 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800301 return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)}
Russ Coxe4a61c62008-09-29 13:37:00 -0700302 }
Russ Coxc83b8382009-11-02 18:37:30 -0800303 f = &netFD{
Devon H. O'Delleb163462009-12-01 23:28:57 -0800304 sysfd: fd,
Russ Coxc83b8382009-11-02 18:37:30 -0800305 family: family,
306 proto: proto,
307 net: net,
308 laddr: laddr,
309 raddr: raddr,
310 };
311 var ls, rs string;
312 if laddr != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800313 ls = laddr.String()
Russ Coxc83b8382009-11-02 18:37:30 -0800314 }
315 if raddr != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800316 rs = raddr.String()
Russ Coxc83b8382009-11-02 18:37:30 -0800317 }
Devon H. O'Delleb163462009-12-01 23:28:57 -0800318 f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs);
Russ Coxd8921c52009-02-15 14:18:39 -0800319 f.cr = make(chan *netFD, 1);
320 f.cw = make(chan *netFD, 1);
Robert Griesemer5d377052009-11-04 23:16:46 -0800321 return f, nil;
Russ Coxe4a61c62008-09-29 13:37:00 -0700322}
323
Devon H. O'Delleb163462009-12-01 23:28:57 -0800324// Add a reference to this fd.
325func (fd *netFD) incref() {
326 fd.sysmu.Lock();
327 fd.sysref++;
328 fd.sysmu.Unlock();
329}
330
331// Remove a reference to this FD and close if we've been asked to do so (and
332// there are no references left.
333func (fd *netFD) decref() {
334 fd.sysmu.Lock();
335 fd.sysref--;
336 if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
337 // In case the user has set linger, switch to blocking mode so
338 // the close blocks. As long as this doesn't happen often, we
339 // can handle the extra OS processes. Otherwise we'll need to
340 // use the pollserver for Close too. Sigh.
341 syscall.SetNonblock(fd.sysfd, false);
342 fd.sysfile.Close();
343 fd.sysfile = nil;
344 fd.sysfd = -1;
345 }
346 fd.sysmu.Unlock();
347}
348
Russ Coxa0bcaf42009-06-25 20:24:55 -0700349func isEAGAIN(e os.Error) bool {
350 if e1, ok := e.(*os.PathError); ok {
Robert Griesemer40621d52009-11-09 12:07:39 -0800351 return e1.Error == os.EAGAIN
Russ Coxa0bcaf42009-06-25 20:24:55 -0700352 }
353 return e == os.EAGAIN;
354}
355
Rob Pikeaaf63f82009-04-17 00:08:24 -0700356func (fd *netFD) Close() os.Error {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800357 if fd == nil || fd.sysfile == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800358 return os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700359 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800360
Devon H. O'Delleb163462009-12-01 23:28:57 -0800361 fd.incref();
362 syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR);
363 fd.closing = true;
364 fd.decref();
365 return nil;
Russ Coxe4a61c62008-09-29 13:37:00 -0700366}
367
Rob Pikeaaf63f82009-04-17 00:08:24 -0700368func (fd *netFD) Read(p []byte) (n int, err os.Error) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800369 if fd == nil || fd.sysfile == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800370 return 0, os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700371 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800372 fd.rio.Lock();
373 defer fd.rio.Unlock();
Devon H. O'Delleb163462009-12-01 23:28:57 -0800374 fd.incref();
375 defer fd.decref();
Russ Cox1e37e8a2009-03-06 17:51:31 -0800376 if fd.rdeadline_delta > 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800377 fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
Russ Cox1e37e8a2009-03-06 17:51:31 -0800378 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800379 fd.rdeadline = 0
Russ Cox1e37e8a2009-03-06 17:51:31 -0800380 }
Russ Coxa0bcaf42009-06-25 20:24:55 -0700381 for {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800382 n, err = fd.sysfile.Read(p);
Russ Coxa0bcaf42009-06-25 20:24:55 -0700383 if isEAGAIN(err) && fd.rdeadline >= 0 {
384 pollserver.WaitRead(fd);
385 continue;
386 }
387 break;
Russ Coxe4a61c62008-09-29 13:37:00 -0700388 }
Russ Coxa0bcaf42009-06-25 20:24:55 -0700389 return;
Russ Coxe4a61c62008-09-29 13:37:00 -0700390}
391
Russ Cox6e788e02009-11-17 08:39:17 -0800392func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800393 if fd == nil || fd.sysfile == nil {
Russ Cox6e788e02009-11-17 08:39:17 -0800394 return 0, nil, os.EINVAL
395 }
396 fd.rio.Lock();
397 defer fd.rio.Unlock();
Devon H. O'Delleb163462009-12-01 23:28:57 -0800398 fd.incref();
399 defer fd.decref();
Russ Cox6e788e02009-11-17 08:39:17 -0800400 if fd.rdeadline_delta > 0 {
401 fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
402 } else {
403 fd.rdeadline = 0
404 }
405 for {
406 var errno int;
Devon H. O'Delleb163462009-12-01 23:28:57 -0800407 n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0);
Russ Cox6e788e02009-11-17 08:39:17 -0800408 if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
409 pollserver.WaitRead(fd);
410 continue;
411 }
412 if errno != 0 {
413 n = 0;
Devon H. O'Delleb163462009-12-01 23:28:57 -0800414 err = &os.PathError{"recvfrom", fd.sysfile.Name(), os.Errno(errno)};
Russ Cox6e788e02009-11-17 08:39:17 -0800415 }
416 break;
417 }
418 return;
419}
420
Rob Pikeaaf63f82009-04-17 00:08:24 -0700421func (fd *netFD) Write(p []byte) (n int, err os.Error) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800422 if fd == nil || fd.sysfile == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800423 return 0, os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700424 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800425 fd.wio.Lock();
426 defer fd.wio.Unlock();
Devon H. O'Delleb163462009-12-01 23:28:57 -0800427 fd.incref();
428 defer fd.decref();
Russ Cox1e37e8a2009-03-06 17:51:31 -0800429 if fd.wdeadline_delta > 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800430 fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
Russ Cox1e37e8a2009-03-06 17:51:31 -0800431 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800432 fd.wdeadline = 0
Russ Cox1e37e8a2009-03-06 17:51:31 -0800433 }
Russ Coxe4a61c62008-09-29 13:37:00 -0700434 err = nil;
Russ Cox983f06b2008-10-07 12:31:31 -0700435 nn := 0;
Russ Cox1e37e8a2009-03-06 17:51:31 -0800436 for nn < len(p) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800437 n, err = fd.sysfile.Write(p[nn:]);
Russ Coxe4a61c62008-09-29 13:37:00 -0700438 if n > 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800439 nn += n
Russ Coxe4a61c62008-09-29 13:37:00 -0700440 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800441 if nn == len(p) {
Robert Griesemer40621d52009-11-09 12:07:39 -0800442 break
Russ Cox1e37e8a2009-03-06 17:51:31 -0800443 }
Russ Coxa0bcaf42009-06-25 20:24:55 -0700444 if isEAGAIN(err) && fd.wdeadline >= 0 {
Russ Cox1e37e8a2009-03-06 17:51:31 -0800445 pollserver.WaitWrite(fd);
446 continue;
447 }
448 if n == 0 || err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800449 break
Russ Coxe4a61c62008-09-29 13:37:00 -0700450 }
451 }
Robert Griesemer5d377052009-11-04 23:16:46 -0800452 return nn, err;
Russ Coxe4a61c62008-09-29 13:37:00 -0700453}
454
Russ Cox6e788e02009-11-17 08:39:17 -0800455func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800456 if fd == nil || fd.sysfile == nil {
Russ Cox6e788e02009-11-17 08:39:17 -0800457 return 0, os.EINVAL
458 }
459 fd.wio.Lock();
460 defer fd.wio.Unlock();
Devon H. O'Delleb163462009-12-01 23:28:57 -0800461 fd.incref();
462 defer fd.decref();
Russ Cox6e788e02009-11-17 08:39:17 -0800463 if fd.wdeadline_delta > 0 {
464 fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
465 } else {
466 fd.wdeadline = 0
467 }
468 err = nil;
469 for {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800470 errno := syscall.Sendto(fd.sysfd, p, 0, sa);
Russ Cox6e788e02009-11-17 08:39:17 -0800471 if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
472 pollserver.WaitWrite(fd);
473 continue;
474 }
475 if errno != 0 {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800476 err = &os.PathError{"sendto", fd.sysfile.Name(), os.Errno(errno)}
Russ Cox6e788e02009-11-17 08:39:17 -0800477 }
478 break;
479 }
480 if err == nil {
481 n = len(p)
482 }
483 return;
484}
485
Robert Griesemer5d377052009-11-04 23:16:46 -0800486func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800487 if fd == nil || fd.sysfile == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800488 return nil, os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700489 }
Russ Coxd8921c52009-02-15 14:18:39 -0800490
Devon H. O'Delleb163462009-12-01 23:28:57 -0800491 fd.incref();
492 defer fd.decref();
493
Russ Cox91ceda52009-02-15 19:35:52 -0800494 // See ../syscall/exec.go for description of ForkLock.
495 // It is okay to hold the lock across syscall.Accept
Devon H. O'Delleb163462009-12-01 23:28:57 -0800496 // because we have put fd.sysfd into non-blocking mode.
Russ Cox91ceda52009-02-15 19:35:52 -0800497 syscall.ForkLock.RLock();
Russ Cox9e0fec92009-06-01 22:14:39 -0700498 var s, e int;
499 var sa syscall.Sockaddr;
Russ Coxd8921c52009-02-15 14:18:39 -0800500 for {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800501 s, sa, e = syscall.Accept(fd.sysfd);
Russ Coxd8921c52009-02-15 14:18:39 -0800502 if e != syscall.EAGAIN {
Robert Griesemer40621d52009-11-09 12:07:39 -0800503 break
Russ Coxd8921c52009-02-15 14:18:39 -0800504 }
Russ Cox91ceda52009-02-15 19:35:52 -0800505 syscall.ForkLock.RUnlock();
Russ Coxe4a61c62008-09-29 13:37:00 -0700506 pollserver.WaitRead(fd);
Russ Cox91ceda52009-02-15 19:35:52 -0800507 syscall.ForkLock.RLock();
Russ Coxe4a61c62008-09-29 13:37:00 -0700508 }
509 if e != 0 {
Russ Cox91ceda52009-02-15 19:35:52 -0800510 syscall.ForkLock.RUnlock();
Robert Griesemer5d377052009-11-04 23:16:46 -0800511 return nil, &OpError{"accept", fd.net, fd.laddr, os.Errno(e)};
Russ Coxe4a61c62008-09-29 13:37:00 -0700512 }
Russ Cox91ceda52009-02-15 19:35:52 -0800513 syscall.CloseOnExec(s);
514 syscall.ForkLock.RUnlock();
Russ Coxd8921c52009-02-15 14:18:39 -0800515
Russ Coxc83b8382009-11-02 18:37:30 -0800516 if nfd, err = newFD(s, fd.family, fd.proto, fd.net, fd.laddr, toAddr(sa)); err != nil {
Rob Pike1a91b9a2009-01-16 11:36:44 -0800517 syscall.Close(s);
Robert Griesemer5d377052009-11-04 23:16:46 -0800518 return nil, err;
Russ Coxe4a61c62008-09-29 13:37:00 -0700519 }
Robert Griesemer5d377052009-11-04 23:16:46 -0800520 return nfd, nil;
Russ Coxe4a61c62008-09-29 13:37:00 -0700521}