Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 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. |
| 4 | |
Joel Sing | 9ca57a7 | 2011-12-21 21:44:47 +1100 | [diff] [blame] | 5 | // +build darwin freebsd linux netbsd openbsd |
Russ Cox | 2715956 | 2011-09-15 16:48:57 -0400 | [diff] [blame] | 6 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 7 | package net |
| 8 | |
| 9 | import ( |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 10 | "errors" |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 11 | "io" |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 12 | "os" |
| 13 | "sync" |
| 14 | "syscall" |
Russ Cox | 00f9f0c | 2010-03-30 10:34:57 -0700 | [diff] [blame] | 15 | "time" |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 16 | ) |
| 17 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 18 | // Network file descriptor. |
| 19 | type netFD struct { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 20 | // locking/lifetime of sysfd |
Mikio Hara | 8c4fecd | 2012-02-14 14:57:57 +0900 | [diff] [blame] | 21 | sysmu sync.Mutex |
| 22 | sysref int |
| 23 | |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 24 | // must lock both sysmu and pollserver to write |
| 25 | // can lock either to read |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 26 | closing bool |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 27 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 28 | // immutable until Close |
Mikio Hara | 974fa75 | 2012-01-27 01:31:42 +0900 | [diff] [blame] | 29 | sysfd int |
| 30 | family int |
| 31 | sotype int |
| 32 | isConnected bool |
| 33 | sysfile *os.File |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 34 | cr chan error |
| 35 | cw chan error |
Mikio Hara | 974fa75 | 2012-01-27 01:31:42 +0900 | [diff] [blame] | 36 | net string |
| 37 | laddr Addr |
| 38 | raddr Addr |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 39 | |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 40 | // owned by client |
Brad Fitzpatrick | b71883e | 2012-01-18 16:24:06 -0800 | [diff] [blame] | 41 | rdeadline int64 |
| 42 | rio sync.Mutex |
| 43 | wdeadline int64 |
| 44 | wio sync.Mutex |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 45 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 46 | // owned by fd wait server |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 47 | ncr, ncw int |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 48 | } |
| 49 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 50 | // A pollServer helps FDs determine when to retry a non-blocking |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 51 | // read or write after they get EAGAIN. When an FD needs to wait, |
| 52 | // send the fd on s.cr (for a read) or s.cw (for a write) to pass the |
| 53 | // request to the poll server. Then receive on fd.cr/fd.cw. |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 54 | // When the pollServer finds that i/o on FD should be possible |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 55 | // again, it will send fd on fd.cr/fd.cw to wake any waiting processes. |
| 56 | // This protocol is implemented as s.WaitRead() and s.WaitWrite(). |
| 57 | // |
| 58 | // There is one subtlety: when sending on s.cr/s.cw, the |
| 59 | // poll server is probably in a system call, waiting for an fd |
| 60 | // to become ready. It's not looking at the request channels. |
| 61 | // To resolve this, the poll server waits not just on the FDs it has |
| 62 | // been given but also its own pipe. After sending on the |
| 63 | // buffered channel s.cr/s.cw, WaitRead/WaitWrite writes a |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 64 | // byte to the pipe, causing the pollServer's poll system call to |
| 65 | // return. In response to the pipe being readable, the pollServer |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 66 | // re-polls its request channels. |
| 67 | // |
| 68 | // Note that the ordering is "send request" and then "wake up server". |
| 69 | // If the operations were reversed, there would be a race: the poll |
| 70 | // server might wake up and look at the request channel, see that it |
| 71 | // was empty, and go back to sleep, all before the requester managed |
| 72 | // to send the request. Because the send must complete before the wakeup, |
| 73 | // the request channel must be buffered. A buffer of size 1 is sufficient |
| 74 | // for any request load. If many processes are trying to submit requests, |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 75 | // one will succeed, the pollServer will read the request, and then the |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 76 | // channel will be empty for the next process's request. A larger buffer |
| 77 | // might help batch requests. |
Adam Langley | ef8f483 | 2009-11-18 13:18:34 -0800 | [diff] [blame] | 78 | // |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 79 | // To avoid races in closing, all fd operations are locked and |
| 80 | // refcounted. when netFD.Close() is called, it calls syscall.Shutdown |
| 81 | // and sets a closing flag. Only when the last reference is removed |
| 82 | // will the fd be closed. |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 83 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 84 | type pollServer struct { |
Ian Lance Taylor | 42bc7fc | 2011-03-17 13:42:40 -0700 | [diff] [blame] | 85 | cr, cw chan *netFD // buffered >= 1 |
| 86 | pr, pw *os.File |
| 87 | poll *pollster // low-level OS hooks |
| 88 | sync.Mutex // controls pending and deadline |
| 89 | pending map[int]*netFD |
| 90 | deadline int64 // next deadline (nsec since 1970) |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 91 | } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 92 | |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 93 | func (s *pollServer) AddFD(fd *netFD, mode int) error { |
Ian Lance Taylor | 42bc7fc | 2011-03-17 13:42:40 -0700 | [diff] [blame] | 94 | s.Lock() |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 95 | intfd := fd.sysfd |
| 96 | if intfd < 0 || fd.closing { |
| 97 | // fd closed underfoot |
| 98 | s.Unlock() |
| 99 | return errClosing |
| 100 | } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 101 | |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 102 | var t int64 |
| 103 | key := intfd << 1 |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 104 | if mode == 'r' { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 105 | fd.ncr++ |
| 106 | t = fd.rdeadline |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 107 | } else { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 108 | fd.ncw++ |
| 109 | key++ |
| 110 | t = fd.wdeadline |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 111 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 112 | s.pending[key] = fd |
Ian Lance Taylor | 42bc7fc | 2011-03-17 13:42:40 -0700 | [diff] [blame] | 113 | doWakeup := false |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 114 | if t > 0 && (s.deadline == 0 || t < s.deadline) { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 115 | s.deadline = t |
Ian Lance Taylor | 42bc7fc | 2011-03-17 13:42:40 -0700 | [diff] [blame] | 116 | doWakeup = true |
| 117 | } |
| 118 | |
Ian Lance Taylor | 0caa0c0 | 2011-03-28 12:39:09 -0700 | [diff] [blame] | 119 | wake, err := s.poll.AddFD(intfd, mode, false) |
| 120 | if err != nil { |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 121 | panic("pollServer AddFD " + err.Error()) |
Ian Lance Taylor | 42bc7fc | 2011-03-17 13:42:40 -0700 | [diff] [blame] | 122 | } |
Ian Lance Taylor | 0caa0c0 | 2011-03-28 12:39:09 -0700 | [diff] [blame] | 123 | if wake { |
| 124 | doWakeup = true |
| 125 | } |
Ian Lance Taylor | 42bc7fc | 2011-03-17 13:42:40 -0700 | [diff] [blame] | 126 | s.Unlock() |
| 127 | |
| 128 | if doWakeup { |
| 129 | s.Wakeup() |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 130 | } |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 131 | return nil |
| 132 | } |
| 133 | |
| 134 | // Evict evicts fd from the pending list, unblocking |
| 135 | // any I/O running on fd. The caller must have locked |
| 136 | // pollserver. |
| 137 | func (s *pollServer) Evict(fd *netFD) { |
| 138 | if s.pending[fd.sysfd<<1] == fd { |
| 139 | s.WakeFD(fd, 'r', errClosing) |
| 140 | s.poll.DelFD(fd.sysfd, 'r') |
| 141 | delete(s.pending, fd.sysfd<<1) |
| 142 | } |
| 143 | if s.pending[fd.sysfd<<1|1] == fd { |
| 144 | s.WakeFD(fd, 'w', errClosing) |
| 145 | s.poll.DelFD(fd.sysfd, 'w') |
| 146 | delete(s.pending, fd.sysfd<<1|1) |
| 147 | } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 148 | } |
| 149 | |
Ian Lance Taylor | 42bc7fc | 2011-03-17 13:42:40 -0700 | [diff] [blame] | 150 | var wakeupbuf [1]byte |
| 151 | |
| 152 | func (s *pollServer) Wakeup() { s.pw.Write(wakeupbuf[0:]) } |
| 153 | |
Russ Cox | 9e0fec9 | 2009-06-01 22:14:39 -0700 | [diff] [blame] | 154 | func (s *pollServer) LookupFD(fd int, mode int) *netFD { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 155 | key := fd << 1 |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 156 | if mode == 'w' { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 157 | key++ |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 158 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 159 | netfd, ok := s.pending[key] |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 160 | if !ok { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 161 | return nil |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 162 | } |
Russ Cox | 313c822 | 2011-10-18 09:56:34 -0400 | [diff] [blame] | 163 | delete(s.pending, key) |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 164 | return netfd |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 165 | } |
| 166 | |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 167 | func (s *pollServer) WakeFD(fd *netFD, mode int, err error) { |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 168 | if mode == 'r' { |
| 169 | for fd.ncr > 0 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 170 | fd.ncr-- |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 171 | fd.cr <- err |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 172 | } |
| 173 | } else { |
| 174 | for fd.ncw > 0 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 175 | fd.ncw-- |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 176 | fd.cw <- err |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 177 | } |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | func (s *pollServer) Now() int64 { |
Russ Cox | 03823b8 | 2011-11-30 12:01:46 -0500 | [diff] [blame] | 182 | return time.Now().UnixNano() |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | func (s *pollServer) CheckDeadlines() { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 186 | now := s.Now() |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 187 | // TODO(rsc): This will need to be handled more efficiently, |
| 188 | // probably with a heap indexed by wakeup time. |
| 189 | |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 190 | var next_deadline int64 |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 191 | for key, fd := range s.pending { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 192 | var t int64 |
| 193 | var mode int |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 194 | if key&1 == 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 195 | mode = 'r' |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 196 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 197 | mode = 'w' |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 198 | } |
| 199 | if mode == 'r' { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 200 | t = fd.rdeadline |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 201 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 202 | t = fd.wdeadline |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 203 | } |
| 204 | if t > 0 { |
| 205 | if t <= now { |
Russ Cox | 313c822 | 2011-10-18 09:56:34 -0400 | [diff] [blame] | 206 | delete(s.pending, key) |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 207 | if mode == 'r' { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 208 | s.poll.DelFD(fd.sysfd, mode) |
| 209 | fd.rdeadline = -1 |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 210 | } else { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 211 | s.poll.DelFD(fd.sysfd, mode) |
| 212 | fd.wdeadline = -1 |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 213 | } |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 214 | s.WakeFD(fd, mode, nil) |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 215 | } else if next_deadline == 0 || t < next_deadline { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 216 | next_deadline = t |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 217 | } |
| 218 | } |
| 219 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 220 | s.deadline = next_deadline |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 221 | } |
| 222 | |
Vinu Rajashekhar | 00ad47f | 2010-06-29 12:04:04 -0700 | [diff] [blame] | 223 | func (s *pollServer) Run() { |
| 224 | var scratch [100]byte |
Ian Lance Taylor | 42bc7fc | 2011-03-17 13:42:40 -0700 | [diff] [blame] | 225 | s.Lock() |
| 226 | defer s.Unlock() |
Vinu Rajashekhar | 00ad47f | 2010-06-29 12:04:04 -0700 | [diff] [blame] | 227 | for { |
| 228 | var t = s.deadline |
| 229 | if t > 0 { |
| 230 | t = t - s.Now() |
| 231 | if t <= 0 { |
| 232 | s.CheckDeadlines() |
| 233 | continue |
| 234 | } |
| 235 | } |
Ian Lance Taylor | 42bc7fc | 2011-03-17 13:42:40 -0700 | [diff] [blame] | 236 | fd, mode, err := s.poll.WaitFD(s, t) |
Vinu Rajashekhar | 00ad47f | 2010-06-29 12:04:04 -0700 | [diff] [blame] | 237 | if err != nil { |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 238 | print("pollServer WaitFD: ", err.Error(), "\n") |
Vinu Rajashekhar | 00ad47f | 2010-06-29 12:04:04 -0700 | [diff] [blame] | 239 | return |
| 240 | } |
| 241 | if fd < 0 { |
| 242 | // Timeout happened. |
| 243 | s.CheckDeadlines() |
| 244 | continue |
| 245 | } |
Brad Fitzpatrick | 4152b43 | 2012-02-10 14:16:15 +1100 | [diff] [blame] | 246 | if fd == int(s.pr.Fd()) { |
Ian Lance Taylor | c01238a | 2011-03-11 18:01:28 -0800 | [diff] [blame] | 247 | // Drain our wakeup pipe (we could loop here, |
| 248 | // but it's unlikely that there are more than |
| 249 | // len(scratch) wakeup calls). |
| 250 | s.pr.Read(scratch[0:]) |
Ian Lance Taylor | 42bc7fc | 2011-03-17 13:42:40 -0700 | [diff] [blame] | 251 | s.CheckDeadlines() |
Vinu Rajashekhar | 00ad47f | 2010-06-29 12:04:04 -0700 | [diff] [blame] | 252 | } else { |
| 253 | netfd := s.LookupFD(fd, mode) |
| 254 | if netfd == nil { |
Vinu Rajashekhar | a9a24d4 | 2010-07-10 14:40:48 -0700 | [diff] [blame] | 255 | print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n") |
Vinu Rajashekhar | 00ad47f | 2010-06-29 12:04:04 -0700 | [diff] [blame] | 256 | continue |
| 257 | } |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 258 | s.WakeFD(netfd, mode, nil) |
Vinu Rajashekhar | 00ad47f | 2010-06-29 12:04:04 -0700 | [diff] [blame] | 259 | } |
| 260 | } |
| 261 | } |
| 262 | |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 263 | func (s *pollServer) WaitRead(fd *netFD) error { |
| 264 | err := s.AddFD(fd, 'r') |
| 265 | if err == nil { |
| 266 | err = <-fd.cr |
| 267 | } |
| 268 | return err |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 269 | } |
| 270 | |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 271 | func (s *pollServer) WaitWrite(fd *netFD) error { |
| 272 | err := s.AddFD(fd, 'w') |
| 273 | if err == nil { |
| 274 | err = <-fd.cw |
| 275 | } |
| 276 | return err |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 277 | } |
| 278 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 279 | // Network FD methods. |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 280 | // All the network FDs use a single pollServer. |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 281 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 282 | var pollserver *pollServer |
Rob Pike | c78be46 | 2010-08-06 06:14:41 +1000 | [diff] [blame] | 283 | var onceStartServer sync.Once |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 284 | |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 285 | func startServer() { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 286 | p, err := newPollServer() |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 287 | if err != nil { |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 288 | print("Start pollServer: ", err.Error(), "\n") |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 289 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 290 | pollserver = p |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 291 | } |
| 292 | |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 293 | func newFD(fd, family, sotype int, net string) (*netFD, error) { |
Rob Pike | c78be46 | 2010-08-06 06:14:41 +1000 | [diff] [blame] | 294 | onceStartServer.Do(startServer) |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 295 | if err := syscall.SetNonblock(fd, true); err != nil { |
| 296 | return nil, err |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 297 | } |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 298 | netfd := &netFD{ |
Robert Griesemer | f44fa9b | 2010-03-02 13:46:51 -0800 | [diff] [blame] | 299 | sysfd: fd, |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 300 | family: family, |
Mikio Hara | 743c2d0 | 2012-01-20 07:31:13 +0900 | [diff] [blame] | 301 | sotype: sotype, |
Robert Griesemer | f44fa9b | 2010-03-02 13:46:51 -0800 | [diff] [blame] | 302 | net: net, |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 303 | } |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 304 | netfd.cr = make(chan error, 1) |
| 305 | netfd.cw = make(chan error, 1) |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 306 | return netfd, nil |
Alexey Borzenkov | 2f45f72 | 2011-03-28 23:40:01 -0400 | [diff] [blame] | 307 | } |
| 308 | |
| 309 | func (fd *netFD) setAddr(laddr, raddr Addr) { |
| 310 | fd.laddr = laddr |
| 311 | fd.raddr = raddr |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 312 | var ls, rs string |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 313 | if laddr != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 314 | ls = laddr.String() |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 315 | } |
| 316 | if raddr != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 317 | rs = raddr.String() |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 318 | } |
Brad Fitzpatrick | 4152b43 | 2012-02-10 14:16:15 +1100 | [diff] [blame] | 319 | fd.sysfile = os.NewFile(uintptr(fd.sysfd), fd.net+":"+ls+"->"+rs) |
Alexey Borzenkov | 2f45f72 | 2011-03-28 23:40:01 -0400 | [diff] [blame] | 320 | } |
| 321 | |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 322 | func (fd *netFD) connect(ra syscall.Sockaddr) error { |
| 323 | err := syscall.Connect(fd.sysfd, ra) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 324 | if err == syscall.EINPROGRESS { |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 325 | if err = pollserver.WaitWrite(fd); err != nil { |
| 326 | return err |
| 327 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 328 | var e int |
| 329 | e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) |
| 330 | if err != nil { |
| 331 | return os.NewSyscallError("getsockopt", err) |
| 332 | } |
| 333 | if e != 0 { |
| 334 | err = syscall.Errno(e) |
Alexey Borzenkov | 2f45f72 | 2011-03-28 23:40:01 -0400 | [diff] [blame] | 335 | } |
| 336 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 337 | return err |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 338 | } |
| 339 | |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 340 | var errClosing = errors.New("use of closed network connection") |
| 341 | |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 342 | // Add a reference to this fd. |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 343 | // If closing==true, pollserver must be locked; mark the fd as closing. |
| 344 | // Returns an error if the fd cannot be used. |
| 345 | func (fd *netFD) incref(closing bool) error { |
| 346 | if fd == nil { |
| 347 | return errClosing |
| 348 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 349 | fd.sysmu.Lock() |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 350 | if fd.closing { |
| 351 | fd.sysmu.Unlock() |
| 352 | return errClosing |
| 353 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 354 | fd.sysref++ |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 355 | if closing { |
| 356 | fd.closing = true |
| 357 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 358 | fd.sysmu.Unlock() |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 359 | return nil |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 360 | } |
| 361 | |
| 362 | // Remove a reference to this FD and close if we've been asked to do so (and |
| 363 | // there are no references left. |
| 364 | func (fd *netFD) decref() { |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 365 | if fd == nil { |
| 366 | return |
| 367 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 368 | fd.sysmu.Lock() |
| 369 | fd.sysref-- |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 370 | if fd.closing && fd.sysref == 0 && fd.sysfile != nil { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 371 | fd.sysfile.Close() |
| 372 | fd.sysfile = nil |
| 373 | fd.sysfd = -1 |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 374 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 375 | fd.sysmu.Unlock() |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 376 | } |
| 377 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 378 | func (fd *netFD) Close() error { |
Mikio Hara | 8c4fecd | 2012-02-14 14:57:57 +0900 | [diff] [blame] | 379 | pollserver.Lock() // needed for both fd.incref(true) and pollserver.Evict |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 380 | defer pollserver.Unlock() |
| 381 | if err := fd.incref(true); err != nil { |
| 382 | return err |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 383 | } |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 384 | // Unblock any I/O. Once it all unblocks and returns, |
| 385 | // so that it cannot be referring to fd.sysfd anymore, |
| 386 | // the final decref will close fd.sysfd. This should happen |
| 387 | // fairly quickly, since all the I/O is non-blocking, and any |
| 388 | // attempts to block in the pollserver will return errClosing. |
| 389 | pollserver.Evict(fd) |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 390 | fd.decref() |
| 391 | return nil |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 392 | } |
| 393 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 394 | func (fd *netFD) shutdown(how int) error { |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 395 | if err := fd.incref(false); err != nil { |
| 396 | return err |
Brad Fitzpatrick | 394842e | 2011-09-28 08:12:38 -0700 | [diff] [blame] | 397 | } |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 398 | defer fd.decref() |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 399 | err := syscall.Shutdown(fd.sysfd, how) |
| 400 | if err != nil { |
| 401 | return &OpError{"shutdown", fd.net, fd.laddr, err} |
Albert Strasheim | 791b2a4 | 2011-10-12 13:45:25 -0400 | [diff] [blame] | 402 | } |
Brad Fitzpatrick | 394842e | 2011-09-28 08:12:38 -0700 | [diff] [blame] | 403 | return nil |
| 404 | } |
| 405 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 406 | func (fd *netFD) CloseRead() error { |
Albert Strasheim | 791b2a4 | 2011-10-12 13:45:25 -0400 | [diff] [blame] | 407 | return fd.shutdown(syscall.SHUT_RD) |
| 408 | } |
| 409 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 410 | func (fd *netFD) CloseWrite() error { |
Albert Strasheim | 791b2a4 | 2011-10-12 13:45:25 -0400 | [diff] [blame] | 411 | return fd.shutdown(syscall.SHUT_WR) |
Brad Fitzpatrick | 394842e | 2011-09-28 08:12:38 -0700 | [diff] [blame] | 412 | } |
| 413 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 414 | func (fd *netFD) Read(p []byte) (n int, err error) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 415 | fd.rio.Lock() |
| 416 | defer fd.rio.Unlock() |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 417 | if err := fd.incref(false); err != nil { |
| 418 | return 0, err |
Michael Hoisie | 9192ec2 | 2010-05-20 17:13:50 -0700 | [diff] [blame] | 419 | } |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 420 | defer fd.decref() |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 421 | for { |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 422 | n, err = syscall.Read(int(fd.sysfd), p) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 423 | if err == syscall.EAGAIN { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 424 | err = errTimeout |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 425 | if fd.rdeadline >= 0 { |
| 426 | if err = pollserver.WaitRead(fd); err == nil { |
| 427 | continue |
| 428 | } |
| 429 | } |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 430 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 431 | if err != nil { |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 432 | n = 0 |
Mikio Hara | 743c2d0 | 2012-01-20 07:31:13 +0900 | [diff] [blame] | 433 | } else if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM { |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 434 | err = io.EOF |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 435 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 436 | break |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 437 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 438 | if err != nil && err != io.EOF { |
| 439 | err = &OpError{"read", fd.net, fd.raddr, err} |
Russ Cox | e89441b | 2009-12-02 15:17:49 -0800 | [diff] [blame] | 440 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 441 | return |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 442 | } |
| 443 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 444 | func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 445 | fd.rio.Lock() |
| 446 | defer fd.rio.Unlock() |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 447 | if err := fd.incref(false); err != nil { |
| 448 | return 0, nil, err |
| 449 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 450 | defer fd.decref() |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 451 | for { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 452 | n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0) |
| 453 | if err == syscall.EAGAIN { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 454 | err = errTimeout |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 455 | if fd.rdeadline >= 0 { |
| 456 | if err = pollserver.WaitRead(fd); err == nil { |
| 457 | continue |
| 458 | } |
| 459 | } |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 460 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 461 | if err != nil { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 462 | n = 0 |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 463 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 464 | break |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 465 | } |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 466 | if err != nil && err != io.EOF { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 467 | err = &OpError{"read", fd.net, fd.laddr, err} |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 468 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 469 | return |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 470 | } |
| 471 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 472 | func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 473 | fd.rio.Lock() |
| 474 | defer fd.rio.Unlock() |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 475 | if err := fd.incref(false); err != nil { |
| 476 | return 0, 0, 0, nil, err |
| 477 | } |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 478 | defer fd.decref() |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 479 | for { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 480 | n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0) |
| 481 | if err == syscall.EAGAIN { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 482 | err = errTimeout |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 483 | if fd.rdeadline >= 0 { |
| 484 | if err = pollserver.WaitRead(fd); err == nil { |
| 485 | continue |
| 486 | } |
| 487 | } |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 488 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 489 | if err == nil && n == 0 { |
| 490 | err = io.EOF |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 491 | } |
| 492 | break |
| 493 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 494 | if err != nil && err != io.EOF { |
| 495 | err = &OpError{"read", fd.net, fd.laddr, err} |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 496 | return |
| 497 | } |
| 498 | return |
| 499 | } |
| 500 | |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 501 | func (fd *netFD) Write(p []byte) (int, error) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 502 | fd.wio.Lock() |
| 503 | defer fd.wio.Unlock() |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 504 | if err := fd.incref(false); err != nil { |
| 505 | return 0, err |
| 506 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 507 | defer fd.decref() |
Michael Hoisie | 9192ec2 | 2010-05-20 17:13:50 -0700 | [diff] [blame] | 508 | if fd.sysfile == nil { |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 509 | return 0, syscall.EINVAL |
Michael Hoisie | 9192ec2 | 2010-05-20 17:13:50 -0700 | [diff] [blame] | 510 | } |
Michael Hoisie | 9192ec2 | 2010-05-20 17:13:50 -0700 | [diff] [blame] | 511 | |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 512 | var err error |
| 513 | nn := 0 |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 514 | for { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 515 | var n int |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 516 | n, err = syscall.Write(int(fd.sysfd), p[nn:]) |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 517 | if n > 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 518 | nn += n |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 519 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 520 | if nn == len(p) { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 521 | break |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 522 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 523 | if err == syscall.EAGAIN { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 524 | err = errTimeout |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 525 | if fd.wdeadline >= 0 { |
| 526 | if err = pollserver.WaitWrite(fd); err == nil { |
| 527 | continue |
| 528 | } |
| 529 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 530 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 531 | if err != nil { |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 532 | n = 0 |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 533 | break |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 534 | } |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 535 | if n == 0 { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 536 | err = io.ErrUnexpectedEOF |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 537 | break |
| 538 | } |
| 539 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 540 | if err != nil { |
| 541 | err = &OpError{"write", fd.net, fd.raddr, err} |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 542 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 543 | return nn, err |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 544 | } |
| 545 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 546 | func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 547 | fd.wio.Lock() |
| 548 | defer fd.wio.Unlock() |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 549 | if err := fd.incref(false); err != nil { |
| 550 | return 0, err |
| 551 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 552 | defer fd.decref() |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 553 | for { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 554 | err = syscall.Sendto(fd.sysfd, p, 0, sa) |
| 555 | if err == syscall.EAGAIN { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 556 | err = errTimeout |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 557 | if fd.wdeadline >= 0 { |
| 558 | if err = pollserver.WaitWrite(fd); err == nil { |
| 559 | continue |
| 560 | } |
| 561 | } |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 562 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 563 | break |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 564 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 565 | if err == nil { |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 566 | n = len(p) |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 567 | } else { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 568 | err = &OpError{"write", fd.net, fd.raddr, err} |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 569 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 570 | return |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 571 | } |
| 572 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 573 | func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 574 | fd.wio.Lock() |
| 575 | defer fd.wio.Unlock() |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 576 | if err := fd.incref(false); err != nil { |
| 577 | return 0, 0, err |
| 578 | } |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 579 | defer fd.decref() |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 580 | for { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 581 | err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0) |
| 582 | if err == syscall.EAGAIN { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 583 | err = errTimeout |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 584 | if fd.wdeadline >= 0 { |
| 585 | if err = pollserver.WaitWrite(fd); err == nil { |
| 586 | continue |
| 587 | } |
| 588 | } |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 589 | } |
| 590 | break |
| 591 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 592 | if err == nil { |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 593 | n = len(p) |
| 594 | oobn = len(oob) |
| 595 | } else { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 596 | err = &OpError{"write", fd.net, fd.raddr, err} |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 597 | } |
| 598 | return |
| 599 | } |
| 600 | |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 601 | func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err error) { |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 602 | if err := fd.incref(false); err != nil { |
| 603 | return nil, err |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 604 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 605 | defer fd.decref() |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 606 | |
Russ Cox | 91ceda5 | 2009-02-15 19:35:52 -0800 | [diff] [blame] | 607 | // See ../syscall/exec.go for description of ForkLock. |
| 608 | // It is okay to hold the lock across syscall.Accept |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 609 | // because we have put fd.sysfd into non-blocking mode. |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 610 | var s int |
Mikio Hara | c20ced9 | 2011-08-16 16:53:09 -0400 | [diff] [blame] | 611 | var rsa syscall.Sockaddr |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 612 | for { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 613 | syscall.ForkLock.RLock() |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 614 | s, rsa, err = syscall.Accept(fd.sysfd) |
| 615 | if err != nil { |
| 616 | syscall.ForkLock.RUnlock() |
| 617 | if err == syscall.EAGAIN { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 618 | err = errTimeout |
Russ Cox | 5e4e3d8 | 2012-02-14 00:40:37 -0500 | [diff] [blame] | 619 | if fd.rdeadline >= 0 { |
| 620 | if err = pollserver.WaitRead(fd); err == nil { |
| 621 | continue |
| 622 | } |
| 623 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 624 | } |
| 625 | return nil, &OpError{"accept", fd.net, fd.laddr, err} |
| 626 | } |
| 627 | break |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 628 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 629 | syscall.CloseOnExec(s) |
| 630 | syscall.ForkLock.RUnlock() |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 631 | |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 632 | if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 633 | syscall.Close(s) |
| 634 | return nil, err |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 635 | } |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 636 | lsa, _ := syscall.Getsockname(netfd.sysfd) |
| 637 | netfd.setAddr(toAddr(lsa), toAddr(rsa)) |
| 638 | return netfd, nil |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 639 | } |
Keith Rarick | a144e3e | 2010-11-05 14:02:03 -0400 | [diff] [blame] | 640 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 641 | func (fd *netFD) dup() (f *os.File, err error) { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 642 | ns, err := syscall.Dup(fd.sysfd) |
| 643 | if err != nil { |
| 644 | return nil, &OpError{"dup", fd.net, fd.laddr, err} |
Keith Rarick | a144e3e | 2010-11-05 14:02:03 -0400 | [diff] [blame] | 645 | } |
| 646 | |
| 647 | // We want blocking mode for the new fd, hence the double negative. |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 648 | if err = syscall.SetNonblock(ns, false); err != nil { |
| 649 | return nil, &OpError{"setnonblock", fd.net, fd.laddr, err} |
Keith Rarick | a144e3e | 2010-11-05 14:02:03 -0400 | [diff] [blame] | 650 | } |
| 651 | |
Brad Fitzpatrick | 4152b43 | 2012-02-10 14:16:15 +1100 | [diff] [blame] | 652 | return os.NewFile(uintptr(ns), fd.sysfile.Name()), nil |
Keith Rarick | a144e3e | 2010-11-05 14:02:03 -0400 | [diff] [blame] | 653 | } |
Alex Brainman | 3a052b5 | 2011-01-12 15:55:17 +1100 | [diff] [blame] | 654 | |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 655 | func closesocket(s int) error { |
Alex Brainman | 3a052b5 | 2011-01-12 15:55:17 +1100 | [diff] [blame] | 656 | return syscall.Close(s) |
| 657 | } |