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 | |
| 5 | // TODO(rsc): All the prints in this file should go to standard error. |
| 6 | |
| 7 | package net |
| 8 | |
| 9 | import ( |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 10 | "io" |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 11 | "os" |
| 12 | "sync" |
| 13 | "syscall" |
Russ Cox | 00f9f0c | 2010-03-30 10:34:57 -0700 | [diff] [blame] | 14 | "time" |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 15 | ) |
| 16 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 17 | // Network file descriptor. |
| 18 | type netFD struct { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 19 | // locking/lifetime of sysfd |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 20 | sysmu sync.Mutex |
| 21 | sysref int |
| 22 | closing bool |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 23 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 24 | // immutable until Close |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 25 | sysfd int |
| 26 | family int |
| 27 | proto int |
| 28 | sysfile *os.File |
Russ Cox | caa149f | 2010-04-06 16:50:27 -0700 | [diff] [blame] | 29 | cr chan bool |
| 30 | cw chan bool |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 31 | net string |
| 32 | laddr Addr |
| 33 | raddr Addr |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 34 | |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 35 | // owned by client |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 36 | rdeadline_delta int64 |
| 37 | rdeadline int64 |
| 38 | rio sync.Mutex |
| 39 | wdeadline_delta int64 |
| 40 | wdeadline int64 |
| 41 | wio sync.Mutex |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 42 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 43 | // owned by fd wait server |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 44 | ncr, ncw int |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 45 | } |
| 46 | |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 47 | type InvalidConnError struct{} |
| 48 | |
| 49 | func (e *InvalidConnError) String() string { return "invalid net.Conn" } |
| 50 | func (e *InvalidConnError) Temporary() bool { return false } |
| 51 | func (e *InvalidConnError) Timeout() bool { return false } |
| 52 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 53 | // A pollServer helps FDs determine when to retry a non-blocking |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 54 | // 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 Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 57 | // When the pollServer finds that i/o on FD should be possible |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 58 | // 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 Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 67 | // byte to the pipe, causing the pollServer's poll system call to |
| 68 | // return. In response to the pipe being readable, the pollServer |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 69 | // 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 Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 78 | // one will succeed, the pollServer will read the request, and then the |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 79 | // channel will be empty for the next process's request. A larger buffer |
| 80 | // might help batch requests. |
Adam Langley | ef8f483 | 2009-11-18 13:18:34 -0800 | [diff] [blame] | 81 | // |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 82 | // 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 Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 86 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 87 | type pollServer struct { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 88 | 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 Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 93 | } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 94 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 95 | func (s *pollServer) AddFD(fd *netFD, mode int) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 96 | intfd := fd.sysfd |
Russ Cox | 37a5374 | 2009-04-15 19:01:48 -0700 | [diff] [blame] | 97 | if intfd < 0 { |
| 98 | // fd closed underfoot |
| 99 | if mode == 'r' { |
Russ Cox | caa149f | 2010-04-06 16:50:27 -0700 | [diff] [blame] | 100 | fd.cr <- true |
Russ Cox | 37a5374 | 2009-04-15 19:01:48 -0700 | [diff] [blame] | 101 | } else { |
Russ Cox | caa149f | 2010-04-06 16:50:27 -0700 | [diff] [blame] | 102 | fd.cw <- true |
Russ Cox | 37a5374 | 2009-04-15 19:01:48 -0700 | [diff] [blame] | 103 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 104 | return |
Russ Cox | 37a5374 | 2009-04-15 19:01:48 -0700 | [diff] [blame] | 105 | } |
| 106 | if err := s.poll.AddFD(intfd, mode, false); err != nil { |
Rob Pike | 325cf8e | 2010-03-24 16:46:53 -0700 | [diff] [blame] | 107 | panic("pollServer AddFD " + err.String()) |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 108 | return |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 109 | } |
| 110 | |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 111 | var t int64 |
| 112 | key := intfd << 1 |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 113 | if mode == 'r' { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 114 | fd.ncr++ |
| 115 | t = fd.rdeadline |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 116 | } else { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 117 | fd.ncw++ |
| 118 | key++ |
| 119 | t = fd.wdeadline |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 120 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 121 | s.pending[key] = fd |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 122 | if t > 0 && (s.deadline == 0 || t < s.deadline) { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 123 | s.deadline = t |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 124 | } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 125 | } |
| 126 | |
Russ Cox | 9e0fec9 | 2009-06-01 22:14:39 -0700 | [diff] [blame] | 127 | func (s *pollServer) LookupFD(fd int, mode int) *netFD { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 128 | key := fd << 1 |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 129 | if mode == 'w' { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 130 | key++ |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 131 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 132 | netfd, ok := s.pending[key] |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 133 | if !ok { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 134 | return nil |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 135 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 136 | s.pending[key] = nil, false |
| 137 | return netfd |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 138 | } |
| 139 | |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 140 | func (s *pollServer) WakeFD(fd *netFD, mode int) { |
| 141 | if mode == 'r' { |
| 142 | for fd.ncr > 0 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 143 | fd.ncr-- |
Russ Cox | caa149f | 2010-04-06 16:50:27 -0700 | [diff] [blame] | 144 | fd.cr <- true |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 145 | } |
| 146 | } else { |
| 147 | for fd.ncw > 0 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 148 | fd.ncw-- |
Russ Cox | caa149f | 2010-04-06 16:50:27 -0700 | [diff] [blame] | 149 | fd.cw <- true |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 150 | } |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | func (s *pollServer) Now() int64 { |
Russ Cox | 00f9f0c | 2010-03-30 10:34:57 -0700 | [diff] [blame] | 155 | return time.Nanoseconds() |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 156 | } |
| 157 | |
| 158 | func (s *pollServer) CheckDeadlines() { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 159 | now := s.Now() |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 160 | // TODO(rsc): This will need to be handled more efficiently, |
| 161 | // probably with a heap indexed by wakeup time. |
| 162 | |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 163 | var next_deadline int64 |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 164 | for key, fd := range s.pending { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 165 | var t int64 |
| 166 | var mode int |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 167 | if key&1 == 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 168 | mode = 'r' |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 169 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 170 | mode = 'w' |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 171 | } |
| 172 | if mode == 'r' { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 173 | t = fd.rdeadline |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 174 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 175 | t = fd.wdeadline |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 176 | } |
| 177 | if t > 0 { |
| 178 | if t <= now { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 179 | s.pending[key] = nil, false |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 180 | if mode == 'r' { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 181 | s.poll.DelFD(fd.sysfd, mode) |
| 182 | fd.rdeadline = -1 |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 183 | } else { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 184 | s.poll.DelFD(fd.sysfd, mode) |
| 185 | fd.wdeadline = -1 |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 186 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 187 | s.WakeFD(fd, mode) |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 188 | } else if next_deadline == 0 || t < next_deadline { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 189 | next_deadline = t |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 190 | } |
| 191 | } |
| 192 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 193 | s.deadline = next_deadline |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 194 | } |
| 195 | |
Vinu Rajashekhar | 00ad47f | 2010-06-29 12:04:04 -0700 | [diff] [blame] | 196 | func (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 Rajashekhar | a9a24d4 | 2010-07-10 14:40:48 -0700 | [diff] [blame] | 232 | print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n") |
Vinu Rajashekhar | 00ad47f | 2010-06-29 12:04:04 -0700 | [diff] [blame] | 233 | continue |
| 234 | } |
| 235 | s.WakeFD(netfd, mode) |
| 236 | } |
| 237 | } |
| 238 | } |
| 239 | |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 240 | var wakeupbuf [1]byte |
| 241 | |
Russ Cox | bb84f4b | 2010-05-27 14:51:47 -0700 | [diff] [blame] | 242 | func (s *pollServer) Wakeup() { s.pw.Write(wakeupbuf[0:]) } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 243 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 244 | func (s *pollServer) WaitRead(fd *netFD) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 245 | s.cr <- fd |
| 246 | s.Wakeup() |
| 247 | <-fd.cr |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 248 | } |
| 249 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 250 | func (s *pollServer) WaitWrite(fd *netFD) { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 251 | s.cw <- fd |
| 252 | s.Wakeup() |
| 253 | <-fd.cw |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 254 | } |
| 255 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 256 | // Network FD methods. |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 257 | // All the network FDs use a single pollServer. |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 258 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 259 | var pollserver *pollServer |
Rob Pike | c78be46 | 2010-08-06 06:14:41 +1000 | [diff] [blame] | 260 | var onceStartServer sync.Once |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 261 | |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 262 | func startServer() { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 263 | p, err := newPollServer() |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 264 | if err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 265 | print("Start pollServer: ", err.String(), "\n") |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 266 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 267 | pollserver = p |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 268 | } |
| 269 | |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 270 | func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) { |
Rob Pike | c78be46 | 2010-08-06 06:14:41 +1000 | [diff] [blame] | 271 | onceStartServer.Do(startServer) |
Russ Cox | 9e0fec9 | 2009-06-01 22:14:39 -0700 | [diff] [blame] | 272 | if e := syscall.SetNonblock(fd, true); e != 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 273 | return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)} |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 274 | } |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 275 | f = &netFD{ |
Robert Griesemer | f44fa9b | 2010-03-02 13:46:51 -0800 | [diff] [blame] | 276 | sysfd: fd, |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 277 | family: family, |
Robert Griesemer | f44fa9b | 2010-03-02 13:46:51 -0800 | [diff] [blame] | 278 | proto: proto, |
| 279 | net: net, |
| 280 | laddr: laddr, |
| 281 | raddr: raddr, |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 282 | } |
| 283 | var ls, rs string |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 284 | if laddr != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 285 | ls = laddr.String() |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 286 | } |
| 287 | if raddr != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 288 | rs = raddr.String() |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 289 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 290 | f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs) |
Russ Cox | caa149f | 2010-04-06 16:50:27 -0700 | [diff] [blame] | 291 | f.cr = make(chan bool, 1) |
| 292 | f.cw = make(chan bool, 1) |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 293 | return f, nil |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 294 | } |
| 295 | |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 296 | // Add a reference to this fd. |
| 297 | func (fd *netFD) incref() { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 298 | fd.sysmu.Lock() |
| 299 | fd.sysref++ |
| 300 | fd.sysmu.Unlock() |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 301 | } |
| 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. |
| 305 | func (fd *netFD) decref() { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 306 | fd.sysmu.Lock() |
| 307 | fd.sysref-- |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 308 | 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 Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 313 | syscall.SetNonblock(fd.sysfd, false) |
| 314 | fd.sysfile.Close() |
| 315 | fd.sysfile = nil |
| 316 | fd.sysfd = -1 |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 317 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 318 | fd.sysmu.Unlock() |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 319 | } |
| 320 | |
Rob Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 321 | func (fd *netFD) Close() os.Error { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 322 | if fd == nil || fd.sysfile == nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 323 | return os.EINVAL |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 324 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 325 | |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 326 | fd.incref() |
| 327 | syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR) |
| 328 | fd.closing = true |
| 329 | fd.decref() |
| 330 | return nil |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 331 | } |
| 332 | |
Rob Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 333 | func (fd *netFD) Read(p []byte) (n int, err os.Error) { |
Michael Hoisie | 9192ec2 | 2010-05-20 17:13:50 -0700 | [diff] [blame] | 334 | if fd == nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 335 | return 0, os.EINVAL |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 336 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 337 | fd.rio.Lock() |
| 338 | defer fd.rio.Unlock() |
| 339 | fd.incref() |
| 340 | defer fd.decref() |
Michael Hoisie | 9192ec2 | 2010-05-20 17:13:50 -0700 | [diff] [blame] | 341 | if fd.sysfile == nil { |
| 342 | return 0, os.EINVAL |
| 343 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 344 | if fd.rdeadline_delta > 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 345 | fd.rdeadline = pollserver.Now() + fd.rdeadline_delta |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 346 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 347 | fd.rdeadline = 0 |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 348 | } |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 349 | var oserr os.Error |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 350 | for { |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 351 | var errno int |
| 352 | n, errno = syscall.Read(fd.sysfile.Fd(), p) |
| 353 | if errno == syscall.EAGAIN && fd.rdeadline >= 0 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 354 | pollserver.WaitRead(fd) |
| 355 | continue |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 356 | } |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 357 | 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 Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 363 | break |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 364 | } |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 365 | if oserr != nil { |
| 366 | err = &OpError{"read", fd.net, fd.raddr, oserr} |
Russ Cox | e89441b | 2009-12-02 15:17:49 -0800 | [diff] [blame] | 367 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 368 | return |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 369 | } |
| 370 | |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 371 | func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 372 | if fd == nil || fd.sysfile == nil { |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 373 | return 0, nil, os.EINVAL |
| 374 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 375 | fd.rio.Lock() |
| 376 | defer fd.rio.Unlock() |
| 377 | fd.incref() |
| 378 | defer fd.decref() |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 379 | if fd.rdeadline_delta > 0 { |
| 380 | fd.rdeadline = pollserver.Now() + fd.rdeadline_delta |
| 381 | } else { |
| 382 | fd.rdeadline = 0 |
| 383 | } |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 384 | var oserr os.Error |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 385 | for { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 386 | var errno int |
| 387 | n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0) |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 388 | if errno == syscall.EAGAIN && fd.rdeadline >= 0 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 389 | pollserver.WaitRead(fd) |
| 390 | continue |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 391 | } |
| 392 | if errno != 0 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 393 | n = 0 |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 394 | oserr = os.Errno(errno) |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 395 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 396 | break |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 397 | } |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 398 | if oserr != nil { |
| 399 | err = &OpError{"read", fd.net, fd.laddr, oserr} |
| 400 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 401 | return |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 402 | } |
| 403 | |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 404 | func (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 Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 440 | func (fd *netFD) Write(p []byte) (n int, err os.Error) { |
Michael Hoisie | 9192ec2 | 2010-05-20 17:13:50 -0700 | [diff] [blame] | 441 | if fd == nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 442 | return 0, os.EINVAL |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 443 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 444 | fd.wio.Lock() |
| 445 | defer fd.wio.Unlock() |
| 446 | fd.incref() |
| 447 | defer fd.decref() |
Michael Hoisie | 9192ec2 | 2010-05-20 17:13:50 -0700 | [diff] [blame] | 448 | if fd.sysfile == nil { |
| 449 | return 0, os.EINVAL |
| 450 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 451 | if fd.wdeadline_delta > 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 452 | fd.wdeadline = pollserver.Now() + fd.wdeadline_delta |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 453 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 454 | fd.wdeadline = 0 |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 455 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 456 | nn := 0 |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 457 | var oserr os.Error |
Michael Hoisie | 9192ec2 | 2010-05-20 17:13:50 -0700 | [diff] [blame] | 458 | |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 459 | for { |
| 460 | n, errno := syscall.Write(fd.sysfile.Fd(), p[nn:]) |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 461 | if n > 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 462 | nn += n |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 463 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 464 | if nn == len(p) { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 465 | break |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 466 | } |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 467 | if errno == syscall.EAGAIN && fd.wdeadline >= 0 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 468 | pollserver.WaitWrite(fd) |
| 469 | continue |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 470 | } |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 471 | if errno != 0 { |
| 472 | n = 0 |
| 473 | oserr = os.Errno(errno) |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 474 | break |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 475 | } |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 476 | 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 Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 483 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 484 | return nn, err |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 485 | } |
| 486 | |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 487 | func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 488 | if fd == nil || fd.sysfile == nil { |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 489 | return 0, os.EINVAL |
| 490 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 491 | fd.wio.Lock() |
| 492 | defer fd.wio.Unlock() |
| 493 | fd.incref() |
| 494 | defer fd.decref() |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 495 | if fd.wdeadline_delta > 0 { |
| 496 | fd.wdeadline = pollserver.Now() + fd.wdeadline_delta |
| 497 | } else { |
| 498 | fd.wdeadline = 0 |
| 499 | } |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 500 | var oserr os.Error |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 501 | for { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 502 | errno := syscall.Sendto(fd.sysfd, p, 0, sa) |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 503 | if errno == syscall.EAGAIN && fd.wdeadline >= 0 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 504 | pollserver.WaitWrite(fd) |
| 505 | continue |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 506 | } |
| 507 | if errno != 0 { |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 508 | oserr = os.Errno(errno) |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 509 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 510 | break |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 511 | } |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 512 | if oserr == nil { |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 513 | n = len(p) |
Russ Cox | 47a0533 | 2010-04-26 22:15:25 -0700 | [diff] [blame] | 514 | } else { |
| 515 | err = &OpError{"write", fd.net, fd.raddr, oserr} |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 516 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 517 | return |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 518 | } |
| 519 | |
Albert Strasheim | cf6c212 | 2010-12-07 13:40:14 -0500 | [diff] [blame] | 520 | func (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 Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 555 | func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 556 | if fd == nil || fd.sysfile == nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 557 | return nil, os.EINVAL |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 558 | } |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 559 | |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 560 | fd.incref() |
| 561 | defer fd.decref() |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 562 | |
Russ Cox | 91ceda5 | 2009-02-15 19:35:52 -0800 | [diff] [blame] | 563 | // See ../syscall/exec.go for description of ForkLock. |
| 564 | // It is okay to hold the lock across syscall.Accept |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 565 | // because we have put fd.sysfd into non-blocking mode. |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 566 | syscall.ForkLock.RLock() |
| 567 | var s, e int |
| 568 | var sa syscall.Sockaddr |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 569 | for { |
Michael Hoisie | ed1cbca | 2011-01-04 11:55:13 -0500 | [diff] [blame] | 570 | if fd.closing { |
| 571 | syscall.ForkLock.RUnlock() |
| 572 | return nil, os.EINVAL |
| 573 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 574 | s, sa, e = syscall.Accept(fd.sysfd) |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 575 | if e != syscall.EAGAIN { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 576 | break |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 577 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 578 | syscall.ForkLock.RUnlock() |
| 579 | pollserver.WaitRead(fd) |
| 580 | syscall.ForkLock.RLock() |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 581 | } |
| 582 | if e != 0 { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 583 | syscall.ForkLock.RUnlock() |
| 584 | return nil, &OpError{"accept", fd.net, fd.laddr, os.Errno(e)} |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 585 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 586 | syscall.CloseOnExec(s) |
| 587 | syscall.ForkLock.RUnlock() |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 588 | |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 589 | if nfd, err = newFD(s, fd.family, fd.proto, fd.net, fd.laddr, toAddr(sa)); err != nil { |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 590 | syscall.Close(s) |
| 591 | return nil, err |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 592 | } |
Robert Griesemer | a3d1045 | 2009-12-15 15:35:38 -0800 | [diff] [blame] | 593 | return nfd, nil |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 594 | } |
Keith Rarick | a144e3e | 2010-11-05 14:02:03 -0400 | [diff] [blame] | 595 | |
| 596 | func (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 Brainman | 3a052b5 | 2011-01-12 15:55:17 +1100 | [diff] [blame^] | 609 | |
| 610 | func closesocket(s int) (errno int) { |
| 611 | return syscall.Close(s) |
| 612 | } |