blob: 7ecd135d20645c9ffa87e140336b1008e0756b47 [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
Joel Sing9ca57a72011-12-21 21:44:47 +11005// +build darwin freebsd linux netbsd openbsd
Russ Cox27159562011-09-15 16:48:57 -04006
Russ Coxe4a61c62008-09-29 13:37:00 -07007package net
8
9import (
Russ Cox47a05332010-04-26 22:15:25 -070010 "io"
Robert Griesemera3d10452009-12-15 15:35:38 -080011 "os"
12 "sync"
13 "syscall"
Russ Cox00f9f0c2010-03-30 10:34:57 -070014 "time"
Russ Coxe4a61c62008-09-29 13:37:00 -070015)
16
Russ Coxd8921c52009-02-15 14:18:39 -080017// Network file descriptor.
18type netFD struct {
Devon H. O'Delleb163462009-12-01 23:28:57 -080019 // locking/lifetime of sysfd
Robert Griesemera3d10452009-12-15 15:35:38 -080020 sysmu sync.Mutex
21 sysref int
22 closing bool
Devon H. O'Delleb163462009-12-01 23:28:57 -080023
Russ Coxe4a61c62008-09-29 13:37:00 -070024 // immutable until Close
Robert Griesemera3d10452009-12-15 15:35:38 -080025 sysfd int
26 family int
Mikio Hara743c2d02012-01-20 07:31:13 +090027 sotype int
Robert Griesemera3d10452009-12-15 15:35:38 -080028 sysfile *os.File
Russ Coxcaa149f2010-04-06 16:50:27 -070029 cr chan bool
30 cw chan bool
Robert Griesemera3d10452009-12-15 15:35:38 -080031 net string
32 laddr Addr
33 raddr Addr
Russ Coxe4a61c62008-09-29 13:37:00 -070034
Russ Cox1e37e8a2009-03-06 17:51:31 -080035 // owned by client
Brad Fitzpatrickb71883e2012-01-18 16:24:06 -080036 rdeadline int64
37 rio sync.Mutex
38 wdeadline int64
39 wio sync.Mutex
Russ Cox1e37e8a2009-03-06 17:51:31 -080040
Russ Coxe4a61c62008-09-29 13:37:00 -070041 // owned by fd wait server
Robert Griesemera3d10452009-12-15 15:35:38 -080042 ncr, ncw int
Russ Coxe4a61c62008-09-29 13:37:00 -070043}
44
Russ Cox47a05332010-04-26 22:15:25 -070045type InvalidConnError struct{}
46
Russ Coxeb692922011-11-01 22:05:34 -040047func (e *InvalidConnError) Error() string { return "invalid net.Conn" }
Russ Cox47a05332010-04-26 22:15:25 -070048func (e *InvalidConnError) Temporary() bool { return false }
49func (e *InvalidConnError) Timeout() bool { return false }
50
Russ Coxd8921c52009-02-15 14:18:39 -080051// A pollServer helps FDs determine when to retry a non-blocking
Russ Coxe4a61c62008-09-29 13:37:00 -070052// read or write after they get EAGAIN. When an FD needs to wait,
53// send the fd on s.cr (for a read) or s.cw (for a write) to pass the
54// request to the poll server. Then receive on fd.cr/fd.cw.
Russ Coxd8921c52009-02-15 14:18:39 -080055// When the pollServer finds that i/o on FD should be possible
Russ Coxe4a61c62008-09-29 13:37:00 -070056// again, it will send fd on fd.cr/fd.cw to wake any waiting processes.
57// This protocol is implemented as s.WaitRead() and s.WaitWrite().
58//
59// There is one subtlety: when sending on s.cr/s.cw, the
60// poll server is probably in a system call, waiting for an fd
61// to become ready. It's not looking at the request channels.
62// To resolve this, the poll server waits not just on the FDs it has
63// been given but also its own pipe. After sending on the
64// buffered channel s.cr/s.cw, WaitRead/WaitWrite writes a
Russ Coxd8921c52009-02-15 14:18:39 -080065// byte to the pipe, causing the pollServer's poll system call to
66// return. In response to the pipe being readable, the pollServer
Russ Coxe4a61c62008-09-29 13:37:00 -070067// re-polls its request channels.
68//
69// Note that the ordering is "send request" and then "wake up server".
70// If the operations were reversed, there would be a race: the poll
71// server might wake up and look at the request channel, see that it
72// was empty, and go back to sleep, all before the requester managed
73// to send the request. Because the send must complete before the wakeup,
74// the request channel must be buffered. A buffer of size 1 is sufficient
75// for any request load. If many processes are trying to submit requests,
Russ Coxd8921c52009-02-15 14:18:39 -080076// one will succeed, the pollServer will read the request, and then the
Russ Coxe4a61c62008-09-29 13:37:00 -070077// channel will be empty for the next process's request. A larger buffer
78// might help batch requests.
Adam Langleyef8f4832009-11-18 13:18:34 -080079//
Devon H. O'Delleb163462009-12-01 23:28:57 -080080// To avoid races in closing, all fd operations are locked and
81// refcounted. when netFD.Close() is called, it calls syscall.Shutdown
82// and sets a closing flag. Only when the last reference is removed
83// will the fd be closed.
Russ Coxe4a61c62008-09-29 13:37:00 -070084
Russ Coxd8921c52009-02-15 14:18:39 -080085type pollServer struct {
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -070086 cr, cw chan *netFD // buffered >= 1
87 pr, pw *os.File
88 poll *pollster // low-level OS hooks
89 sync.Mutex // controls pending and deadline
90 pending map[int]*netFD
91 deadline int64 // next deadline (nsec since 1970)
Russ Coxe4a61c62008-09-29 13:37:00 -070092}
Russ Coxe4a61c62008-09-29 13:37:00 -070093
Russ Coxd8921c52009-02-15 14:18:39 -080094func (s *pollServer) AddFD(fd *netFD, mode int) {
Robert Griesemera3d10452009-12-15 15:35:38 -080095 intfd := fd.sysfd
Russ Cox37a53742009-04-15 19:01:48 -070096 if intfd < 0 {
97 // fd closed underfoot
98 if mode == 'r' {
Russ Coxcaa149f2010-04-06 16:50:27 -070099 fd.cr <- true
Russ Cox37a53742009-04-15 19:01:48 -0700100 } else {
Russ Coxcaa149f2010-04-06 16:50:27 -0700101 fd.cw <- true
Russ Cox37a53742009-04-15 19:01:48 -0700102 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800103 return
Russ Cox37a53742009-04-15 19:01:48 -0700104 }
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -0700105
106 s.Lock()
Russ Coxe4a61c62008-09-29 13:37:00 -0700107
Robert Griesemera3d10452009-12-15 15:35:38 -0800108 var t int64
109 key := intfd << 1
Russ Coxe4a61c62008-09-29 13:37:00 -0700110 if mode == 'r' {
Robert Griesemera3d10452009-12-15 15:35:38 -0800111 fd.ncr++
112 t = fd.rdeadline
Russ Coxe4a61c62008-09-29 13:37:00 -0700113 } else {
Robert Griesemera3d10452009-12-15 15:35:38 -0800114 fd.ncw++
115 key++
116 t = fd.wdeadline
Russ Coxe4a61c62008-09-29 13:37:00 -0700117 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800118 s.pending[key] = fd
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -0700119 doWakeup := false
Russ Cox1e37e8a2009-03-06 17:51:31 -0800120 if t > 0 && (s.deadline == 0 || t < s.deadline) {
Robert Griesemer40621d52009-11-09 12:07:39 -0800121 s.deadline = t
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -0700122 doWakeup = true
123 }
124
Ian Lance Taylor0caa0c02011-03-28 12:39:09 -0700125 wake, err := s.poll.AddFD(intfd, mode, false)
126 if err != nil {
Russ Coxeb692922011-11-01 22:05:34 -0400127 panic("pollServer AddFD " + err.Error())
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -0700128 }
Ian Lance Taylor0caa0c02011-03-28 12:39:09 -0700129 if wake {
130 doWakeup = true
131 }
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -0700132
133 s.Unlock()
134
135 if doWakeup {
136 s.Wakeup()
Russ Cox1e37e8a2009-03-06 17:51:31 -0800137 }
Russ Coxe4a61c62008-09-29 13:37:00 -0700138}
139
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -0700140var wakeupbuf [1]byte
141
142func (s *pollServer) Wakeup() { s.pw.Write(wakeupbuf[0:]) }
143
Russ Cox9e0fec92009-06-01 22:14:39 -0700144func (s *pollServer) LookupFD(fd int, mode int) *netFD {
Robert Griesemera3d10452009-12-15 15:35:38 -0800145 key := fd << 1
Russ Coxe4a61c62008-09-29 13:37:00 -0700146 if mode == 'w' {
Robert Griesemer40621d52009-11-09 12:07:39 -0800147 key++
Russ Coxe4a61c62008-09-29 13:37:00 -0700148 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800149 netfd, ok := s.pending[key]
Russ Coxe4a61c62008-09-29 13:37:00 -0700150 if !ok {
Robert Griesemer40621d52009-11-09 12:07:39 -0800151 return nil
Russ Coxe4a61c62008-09-29 13:37:00 -0700152 }
Russ Cox313c8222011-10-18 09:56:34 -0400153 delete(s.pending, key)
Robert Griesemera3d10452009-12-15 15:35:38 -0800154 return netfd
Russ Coxe4a61c62008-09-29 13:37:00 -0700155}
156
Russ Cox1e37e8a2009-03-06 17:51:31 -0800157func (s *pollServer) WakeFD(fd *netFD, mode int) {
158 if mode == 'r' {
159 for fd.ncr > 0 {
Robert Griesemera3d10452009-12-15 15:35:38 -0800160 fd.ncr--
Russ Coxcaa149f2010-04-06 16:50:27 -0700161 fd.cr <- true
Russ Cox1e37e8a2009-03-06 17:51:31 -0800162 }
163 } else {
164 for fd.ncw > 0 {
Robert Griesemera3d10452009-12-15 15:35:38 -0800165 fd.ncw--
Russ Coxcaa149f2010-04-06 16:50:27 -0700166 fd.cw <- true
Russ Cox1e37e8a2009-03-06 17:51:31 -0800167 }
168 }
169}
170
171func (s *pollServer) Now() int64 {
Russ Cox03823b82011-11-30 12:01:46 -0500172 return time.Now().UnixNano()
Russ Cox1e37e8a2009-03-06 17:51:31 -0800173}
174
175func (s *pollServer) CheckDeadlines() {
Robert Griesemera3d10452009-12-15 15:35:38 -0800176 now := s.Now()
Russ Cox1e37e8a2009-03-06 17:51:31 -0800177 // TODO(rsc): This will need to be handled more efficiently,
178 // probably with a heap indexed by wakeup time.
179
Robert Griesemera3d10452009-12-15 15:35:38 -0800180 var next_deadline int64
Russ Cox1e37e8a2009-03-06 17:51:31 -0800181 for key, fd := range s.pending {
Robert Griesemera3d10452009-12-15 15:35:38 -0800182 var t int64
183 var mode int
Russ Cox1e37e8a2009-03-06 17:51:31 -0800184 if key&1 == 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800185 mode = 'r'
Russ Cox1e37e8a2009-03-06 17:51:31 -0800186 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800187 mode = 'w'
Russ Cox1e37e8a2009-03-06 17:51:31 -0800188 }
189 if mode == 'r' {
Robert Griesemer40621d52009-11-09 12:07:39 -0800190 t = fd.rdeadline
Russ Cox1e37e8a2009-03-06 17:51:31 -0800191 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800192 t = fd.wdeadline
Russ Cox1e37e8a2009-03-06 17:51:31 -0800193 }
194 if t > 0 {
195 if t <= now {
Russ Cox313c8222011-10-18 09:56:34 -0400196 delete(s.pending, key)
Russ Cox1e37e8a2009-03-06 17:51:31 -0800197 if mode == 'r' {
Robert Griesemera3d10452009-12-15 15:35:38 -0800198 s.poll.DelFD(fd.sysfd, mode)
199 fd.rdeadline = -1
Russ Cox1e37e8a2009-03-06 17:51:31 -0800200 } else {
Robert Griesemera3d10452009-12-15 15:35:38 -0800201 s.poll.DelFD(fd.sysfd, mode)
202 fd.wdeadline = -1
Russ Cox1e37e8a2009-03-06 17:51:31 -0800203 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800204 s.WakeFD(fd, mode)
Russ Cox1e37e8a2009-03-06 17:51:31 -0800205 } else if next_deadline == 0 || t < next_deadline {
Robert Griesemer40621d52009-11-09 12:07:39 -0800206 next_deadline = t
Russ Cox1e37e8a2009-03-06 17:51:31 -0800207 }
208 }
209 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800210 s.deadline = next_deadline
Russ Cox1e37e8a2009-03-06 17:51:31 -0800211}
212
Vinu Rajashekhar00ad47f2010-06-29 12:04:04 -0700213func (s *pollServer) Run() {
214 var scratch [100]byte
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -0700215 s.Lock()
216 defer s.Unlock()
Vinu Rajashekhar00ad47f2010-06-29 12:04:04 -0700217 for {
218 var t = s.deadline
219 if t > 0 {
220 t = t - s.Now()
221 if t <= 0 {
222 s.CheckDeadlines()
223 continue
224 }
225 }
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -0700226 fd, mode, err := s.poll.WaitFD(s, t)
Vinu Rajashekhar00ad47f2010-06-29 12:04:04 -0700227 if err != nil {
Russ Coxeb692922011-11-01 22:05:34 -0400228 print("pollServer WaitFD: ", err.Error(), "\n")
Vinu Rajashekhar00ad47f2010-06-29 12:04:04 -0700229 return
230 }
231 if fd < 0 {
232 // Timeout happened.
233 s.CheckDeadlines()
234 continue
235 }
236 if fd == s.pr.Fd() {
Ian Lance Taylorc01238a2011-03-11 18:01:28 -0800237 // Drain our wakeup pipe (we could loop here,
238 // but it's unlikely that there are more than
239 // len(scratch) wakeup calls).
240 s.pr.Read(scratch[0:])
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -0700241 s.CheckDeadlines()
Vinu Rajashekhar00ad47f2010-06-29 12:04:04 -0700242 } else {
243 netfd := s.LookupFD(fd, mode)
244 if netfd == nil {
Vinu Rajashekhara9a24d42010-07-10 14:40:48 -0700245 print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n")
Vinu Rajashekhar00ad47f2010-06-29 12:04:04 -0700246 continue
247 }
248 s.WakeFD(netfd, mode)
249 }
250 }
251}
252
Russ Coxd8921c52009-02-15 14:18:39 -0800253func (s *pollServer) WaitRead(fd *netFD) {
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -0700254 s.AddFD(fd, 'r')
Robert Griesemera3d10452009-12-15 15:35:38 -0800255 <-fd.cr
Russ Coxe4a61c62008-09-29 13:37:00 -0700256}
257
Russ Coxd8921c52009-02-15 14:18:39 -0800258func (s *pollServer) WaitWrite(fd *netFD) {
Ian Lance Taylor42bc7fc2011-03-17 13:42:40 -0700259 s.AddFD(fd, 'w')
Robert Griesemera3d10452009-12-15 15:35:38 -0800260 <-fd.cw
Russ Coxe4a61c62008-09-29 13:37:00 -0700261}
262
Russ Coxe4a61c62008-09-29 13:37:00 -0700263// Network FD methods.
Russ Coxd8921c52009-02-15 14:18:39 -0800264// All the network FDs use a single pollServer.
Russ Coxe4a61c62008-09-29 13:37:00 -0700265
Russ Coxd8921c52009-02-15 14:18:39 -0800266var pollserver *pollServer
Rob Pikec78be462010-08-06 06:14:41 +1000267var onceStartServer sync.Once
Russ Coxe4a61c62008-09-29 13:37:00 -0700268
Russ Coxc83b8382009-11-02 18:37:30 -0800269func startServer() {
Robert Griesemera3d10452009-12-15 15:35:38 -0800270 p, err := newPollServer()
Russ Coxe4a61c62008-09-29 13:37:00 -0700271 if err != nil {
Russ Coxeb692922011-11-01 22:05:34 -0400272 print("Start pollServer: ", err.Error(), "\n")
Russ Coxe4a61c62008-09-29 13:37:00 -0700273 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800274 pollserver = p
Russ Coxe4a61c62008-09-29 13:37:00 -0700275}
276
Mikio Hara743c2d02012-01-20 07:31:13 +0900277func newFD(fd, family, sotype int, net string) (f *netFD, err error) {
Rob Pikec78be462010-08-06 06:14:41 +1000278 onceStartServer.Do(startServer)
Russ Coxc017a822011-11-13 22:44:52 -0500279 if e := syscall.SetNonblock(fd, true); e != nil {
280 return nil, e
Russ Coxe4a61c62008-09-29 13:37:00 -0700281 }
Russ Coxc83b8382009-11-02 18:37:30 -0800282 f = &netFD{
Robert Griesemerf44fa9b2010-03-02 13:46:51 -0800283 sysfd: fd,
Russ Coxc83b8382009-11-02 18:37:30 -0800284 family: family,
Mikio Hara743c2d02012-01-20 07:31:13 +0900285 sotype: sotype,
Robert Griesemerf44fa9b2010-03-02 13:46:51 -0800286 net: net,
Robert Griesemera3d10452009-12-15 15:35:38 -0800287 }
Alexey Borzenkov2f45f722011-03-28 23:40:01 -0400288 f.cr = make(chan bool, 1)
289 f.cw = make(chan bool, 1)
290 return f, nil
291}
292
293func (fd *netFD) setAddr(laddr, raddr Addr) {
294 fd.laddr = laddr
295 fd.raddr = raddr
Robert Griesemera3d10452009-12-15 15:35:38 -0800296 var ls, rs string
Russ Coxc83b8382009-11-02 18:37:30 -0800297 if laddr != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800298 ls = laddr.String()
Russ Coxc83b8382009-11-02 18:37:30 -0800299 }
300 if raddr != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800301 rs = raddr.String()
Russ Coxc83b8382009-11-02 18:37:30 -0800302 }
Alexey Borzenkov2f45f722011-03-28 23:40:01 -0400303 fd.sysfile = os.NewFile(fd.sysfd, fd.net+":"+ls+"->"+rs)
304}
305
Russ Coxeb692922011-11-01 22:05:34 -0400306func (fd *netFD) connect(ra syscall.Sockaddr) (err error) {
Russ Coxc017a822011-11-13 22:44:52 -0500307 err = syscall.Connect(fd.sysfd, ra)
308 if err == syscall.EINPROGRESS {
Alexey Borzenkov07931762011-03-29 14:23:42 -0400309 pollserver.WaitWrite(fd)
Russ Coxc017a822011-11-13 22:44:52 -0500310 var e int
311 e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
312 if err != nil {
313 return os.NewSyscallError("getsockopt", err)
314 }
315 if e != 0 {
316 err = syscall.Errno(e)
Alexey Borzenkov2f45f722011-03-28 23:40:01 -0400317 }
318 }
Russ Coxc017a822011-11-13 22:44:52 -0500319 return err
Russ Coxe4a61c62008-09-29 13:37:00 -0700320}
321
Devon H. O'Delleb163462009-12-01 23:28:57 -0800322// Add a reference to this fd.
323func (fd *netFD) incref() {
Robert Griesemera3d10452009-12-15 15:35:38 -0800324 fd.sysmu.Lock()
325 fd.sysref++
326 fd.sysmu.Unlock()
Devon H. O'Delleb163462009-12-01 23:28:57 -0800327}
328
329// Remove a reference to this FD and close if we've been asked to do so (and
330// there are no references left.
331func (fd *netFD) decref() {
Robert Griesemera3d10452009-12-15 15:35:38 -0800332 fd.sysmu.Lock()
333 fd.sysref--
Devon H. O'Delleb163462009-12-01 23:28:57 -0800334 if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
335 // In case the user has set linger, switch to blocking mode so
336 // the close blocks. As long as this doesn't happen often, we
337 // can handle the extra OS processes. Otherwise we'll need to
338 // use the pollserver for Close too. Sigh.
Robert Griesemera3d10452009-12-15 15:35:38 -0800339 syscall.SetNonblock(fd.sysfd, false)
340 fd.sysfile.Close()
341 fd.sysfile = nil
342 fd.sysfd = -1
Devon H. O'Delleb163462009-12-01 23:28:57 -0800343 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800344 fd.sysmu.Unlock()
Devon H. O'Delleb163462009-12-01 23:28:57 -0800345}
346
Russ Coxeb692922011-11-01 22:05:34 -0400347func (fd *netFD) Close() error {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800348 if fd == nil || fd.sysfile == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800349 return os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700350 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800351
Robert Griesemera3d10452009-12-15 15:35:38 -0800352 fd.incref()
353 syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
354 fd.closing = true
355 fd.decref()
356 return nil
Russ Coxe4a61c62008-09-29 13:37:00 -0700357}
358
Russ Coxeb692922011-11-01 22:05:34 -0400359func (fd *netFD) shutdown(how int) error {
Brad Fitzpatrick394842e2011-09-28 08:12:38 -0700360 if fd == nil || fd.sysfile == nil {
361 return os.EINVAL
362 }
Russ Coxc017a822011-11-13 22:44:52 -0500363 err := syscall.Shutdown(fd.sysfd, how)
364 if err != nil {
365 return &OpError{"shutdown", fd.net, fd.laddr, err}
Albert Strasheim791b2a42011-10-12 13:45:25 -0400366 }
Brad Fitzpatrick394842e2011-09-28 08:12:38 -0700367 return nil
368}
369
Russ Coxeb692922011-11-01 22:05:34 -0400370func (fd *netFD) CloseRead() error {
Albert Strasheim791b2a42011-10-12 13:45:25 -0400371 return fd.shutdown(syscall.SHUT_RD)
372}
373
Russ Coxeb692922011-11-01 22:05:34 -0400374func (fd *netFD) CloseWrite() error {
Albert Strasheim791b2a42011-10-12 13:45:25 -0400375 return fd.shutdown(syscall.SHUT_WR)
Brad Fitzpatrick394842e2011-09-28 08:12:38 -0700376}
377
Russ Coxeb692922011-11-01 22:05:34 -0400378func (fd *netFD) Read(p []byte) (n int, err error) {
Michael Hoisie9192ec22010-05-20 17:13:50 -0700379 if fd == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800380 return 0, os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700381 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800382 fd.rio.Lock()
383 defer fd.rio.Unlock()
384 fd.incref()
385 defer fd.decref()
Michael Hoisie9192ec22010-05-20 17:13:50 -0700386 if fd.sysfile == nil {
387 return 0, os.EINVAL
388 }
Russ Coxa0bcaf42009-06-25 20:24:55 -0700389 for {
Russ Coxc017a822011-11-13 22:44:52 -0500390 n, err = syscall.Read(fd.sysfile.Fd(), p)
391 if err == syscall.EAGAIN {
392 if fd.rdeadline >= 0 {
393 pollserver.WaitRead(fd)
394 continue
395 }
396 err = errTimeout
Russ Coxa0bcaf42009-06-25 20:24:55 -0700397 }
Russ Coxc017a822011-11-13 22:44:52 -0500398 if err != nil {
Russ Cox47a05332010-04-26 22:15:25 -0700399 n = 0
Mikio Hara743c2d02012-01-20 07:31:13 +0900400 } else if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM {
Russ Coxeb692922011-11-01 22:05:34 -0400401 err = io.EOF
Russ Cox47a05332010-04-26 22:15:25 -0700402 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800403 break
Russ Coxe4a61c62008-09-29 13:37:00 -0700404 }
Russ Coxc017a822011-11-13 22:44:52 -0500405 if err != nil && err != io.EOF {
406 err = &OpError{"read", fd.net, fd.raddr, err}
Russ Coxe89441b2009-12-02 15:17:49 -0800407 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800408 return
Russ Coxe4a61c62008-09-29 13:37:00 -0700409}
410
Russ Coxeb692922011-11-01 22:05:34 -0400411func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800412 if fd == nil || fd.sysfile == nil {
Russ Cox6e788e02009-11-17 08:39:17 -0800413 return 0, nil, os.EINVAL
414 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800415 fd.rio.Lock()
416 defer fd.rio.Unlock()
417 fd.incref()
418 defer fd.decref()
Russ Cox6e788e02009-11-17 08:39:17 -0800419 for {
Russ Coxc017a822011-11-13 22:44:52 -0500420 n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
421 if err == syscall.EAGAIN {
422 if fd.rdeadline >= 0 {
423 pollserver.WaitRead(fd)
424 continue
425 }
426 err = errTimeout
Russ Cox6e788e02009-11-17 08:39:17 -0800427 }
Russ Coxc017a822011-11-13 22:44:52 -0500428 if err != nil {
Robert Griesemera3d10452009-12-15 15:35:38 -0800429 n = 0
Russ Cox6e788e02009-11-17 08:39:17 -0800430 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800431 break
Russ Cox6e788e02009-11-17 08:39:17 -0800432 }
Russ Coxc017a822011-11-13 22:44:52 -0500433 if err != nil {
434 err = &OpError{"read", fd.net, fd.laddr, err}
Russ Cox47a05332010-04-26 22:15:25 -0700435 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800436 return
Russ Cox6e788e02009-11-17 08:39:17 -0800437}
438
Russ Coxeb692922011-11-01 22:05:34 -0400439func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500440 if fd == nil || fd.sysfile == nil {
441 return 0, 0, 0, nil, os.EINVAL
442 }
443 fd.rio.Lock()
444 defer fd.rio.Unlock()
445 fd.incref()
446 defer fd.decref()
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500447 for {
Russ Coxc017a822011-11-13 22:44:52 -0500448 n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
449 if err == syscall.EAGAIN {
450 if fd.rdeadline >= 0 {
451 pollserver.WaitRead(fd)
452 continue
453 }
454 err = errTimeout
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500455 }
Russ Coxc017a822011-11-13 22:44:52 -0500456 if err == nil && n == 0 {
457 err = io.EOF
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500458 }
459 break
460 }
Russ Coxc017a822011-11-13 22:44:52 -0500461 if err != nil && err != io.EOF {
462 err = &OpError{"read", fd.net, fd.laddr, err}
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500463 return
464 }
465 return
466}
467
Russ Coxeb692922011-11-01 22:05:34 -0400468func (fd *netFD) Write(p []byte) (n int, err error) {
Michael Hoisie9192ec22010-05-20 17:13:50 -0700469 if fd == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800470 return 0, os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700471 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800472 fd.wio.Lock()
473 defer fd.wio.Unlock()
474 fd.incref()
475 defer fd.decref()
Michael Hoisie9192ec22010-05-20 17:13:50 -0700476 if fd.sysfile == nil {
477 return 0, os.EINVAL
478 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800479 nn := 0
Michael Hoisie9192ec22010-05-20 17:13:50 -0700480
Russ Cox47a05332010-04-26 22:15:25 -0700481 for {
Russ Coxc017a822011-11-13 22:44:52 -0500482 var n int
483 n, err = syscall.Write(fd.sysfile.Fd(), p[nn:])
Russ Coxe4a61c62008-09-29 13:37:00 -0700484 if n > 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800485 nn += n
Russ Coxe4a61c62008-09-29 13:37:00 -0700486 }
Russ Cox1e37e8a2009-03-06 17:51:31 -0800487 if nn == len(p) {
Robert Griesemer40621d52009-11-09 12:07:39 -0800488 break
Russ Cox1e37e8a2009-03-06 17:51:31 -0800489 }
Russ Coxc017a822011-11-13 22:44:52 -0500490 if err == syscall.EAGAIN {
491 if fd.wdeadline >= 0 {
492 pollserver.WaitWrite(fd)
493 continue
494 }
495 err = errTimeout
Russ Cox1e37e8a2009-03-06 17:51:31 -0800496 }
Russ Coxc017a822011-11-13 22:44:52 -0500497 if err != nil {
Russ Cox47a05332010-04-26 22:15:25 -0700498 n = 0
Robert Griesemer40621d52009-11-09 12:07:39 -0800499 break
Russ Coxe4a61c62008-09-29 13:37:00 -0700500 }
Russ Cox47a05332010-04-26 22:15:25 -0700501 if n == 0 {
Russ Coxc017a822011-11-13 22:44:52 -0500502 err = io.ErrUnexpectedEOF
Russ Cox47a05332010-04-26 22:15:25 -0700503 break
504 }
505 }
Russ Coxc017a822011-11-13 22:44:52 -0500506 if err != nil {
507 err = &OpError{"write", fd.net, fd.raddr, err}
Russ Coxe4a61c62008-09-29 13:37:00 -0700508 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800509 return nn, err
Russ Coxe4a61c62008-09-29 13:37:00 -0700510}
511
Russ Coxeb692922011-11-01 22:05:34 -0400512func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800513 if fd == nil || fd.sysfile == nil {
Russ Cox6e788e02009-11-17 08:39:17 -0800514 return 0, os.EINVAL
515 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800516 fd.wio.Lock()
517 defer fd.wio.Unlock()
518 fd.incref()
519 defer fd.decref()
Russ Cox6e788e02009-11-17 08:39:17 -0800520 for {
Russ Coxc017a822011-11-13 22:44:52 -0500521 err = syscall.Sendto(fd.sysfd, p, 0, sa)
522 if err == syscall.EAGAIN {
523 if fd.wdeadline >= 0 {
524 pollserver.WaitWrite(fd)
525 continue
526 }
527 err = errTimeout
Russ Cox6e788e02009-11-17 08:39:17 -0800528 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800529 break
Russ Cox6e788e02009-11-17 08:39:17 -0800530 }
Russ Coxc017a822011-11-13 22:44:52 -0500531 if err == nil {
Russ Cox6e788e02009-11-17 08:39:17 -0800532 n = len(p)
Russ Cox47a05332010-04-26 22:15:25 -0700533 } else {
Russ Coxc017a822011-11-13 22:44:52 -0500534 err = &OpError{"write", fd.net, fd.raddr, err}
Russ Cox6e788e02009-11-17 08:39:17 -0800535 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800536 return
Russ Cox6e788e02009-11-17 08:39:17 -0800537}
538
Russ Coxeb692922011-11-01 22:05:34 -0400539func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500540 if fd == nil || fd.sysfile == nil {
541 return 0, 0, os.EINVAL
542 }
543 fd.wio.Lock()
544 defer fd.wio.Unlock()
545 fd.incref()
546 defer fd.decref()
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500547 for {
Russ Coxc017a822011-11-13 22:44:52 -0500548 err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
549 if err == syscall.EAGAIN {
550 if fd.wdeadline >= 0 {
551 pollserver.WaitWrite(fd)
552 continue
553 }
554 err = errTimeout
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500555 }
556 break
557 }
Russ Coxc017a822011-11-13 22:44:52 -0500558 if err == nil {
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500559 n = len(p)
560 oobn = len(oob)
561 } else {
Russ Coxc017a822011-11-13 22:44:52 -0500562 err = &OpError{"write", fd.net, fd.raddr, err}
Albert Strasheimcf6c2122010-12-07 13:40:14 -0500563 }
564 return
565}
566
Russ Coxeb692922011-11-01 22:05:34 -0400567func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err error) {
Devon H. O'Delleb163462009-12-01 23:28:57 -0800568 if fd == nil || fd.sysfile == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800569 return nil, os.EINVAL
Russ Coxe4a61c62008-09-29 13:37:00 -0700570 }
Russ Coxd8921c52009-02-15 14:18:39 -0800571
Robert Griesemera3d10452009-12-15 15:35:38 -0800572 fd.incref()
573 defer fd.decref()
Devon H. O'Delleb163462009-12-01 23:28:57 -0800574
Russ Cox91ceda52009-02-15 19:35:52 -0800575 // See ../syscall/exec.go for description of ForkLock.
576 // It is okay to hold the lock across syscall.Accept
Devon H. O'Delleb163462009-12-01 23:28:57 -0800577 // because we have put fd.sysfd into non-blocking mode.
Russ Coxc017a822011-11-13 22:44:52 -0500578 var s int
Mikio Harac20ced92011-08-16 16:53:09 -0400579 var rsa syscall.Sockaddr
Russ Coxd8921c52009-02-15 14:18:39 -0800580 for {
Michael Hoisieed1cbca2011-01-04 11:55:13 -0500581 if fd.closing {
Michael Hoisieed1cbca2011-01-04 11:55:13 -0500582 return nil, os.EINVAL
583 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800584 syscall.ForkLock.RLock()
Russ Coxc017a822011-11-13 22:44:52 -0500585 s, rsa, err = syscall.Accept(fd.sysfd)
586 if err != nil {
587 syscall.ForkLock.RUnlock()
588 if err == syscall.EAGAIN {
589 if fd.rdeadline >= 0 {
590 pollserver.WaitRead(fd)
591 continue
592 }
593 err = errTimeout
594 }
595 return nil, &OpError{"accept", fd.net, fd.laddr, err}
596 }
597 break
Russ Coxe4a61c62008-09-29 13:37:00 -0700598 }
Robert Griesemera3d10452009-12-15 15:35:38 -0800599 syscall.CloseOnExec(s)
600 syscall.ForkLock.RUnlock()
Russ Coxd8921c52009-02-15 14:18:39 -0800601
Mikio Hara743c2d02012-01-20 07:31:13 +0900602 if nfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil {
Robert Griesemera3d10452009-12-15 15:35:38 -0800603 syscall.Close(s)
604 return nil, err
Russ Coxe4a61c62008-09-29 13:37:00 -0700605 }
Mikio Harac20ced92011-08-16 16:53:09 -0400606 lsa, _ := syscall.Getsockname(nfd.sysfd)
607 nfd.setAddr(toAddr(lsa), toAddr(rsa))
Robert Griesemera3d10452009-12-15 15:35:38 -0800608 return nfd, nil
Russ Coxe4a61c62008-09-29 13:37:00 -0700609}
Keith Raricka144e3e2010-11-05 14:02:03 -0400610
Russ Coxeb692922011-11-01 22:05:34 -0400611func (fd *netFD) dup() (f *os.File, err error) {
Russ Coxc017a822011-11-13 22:44:52 -0500612 ns, err := syscall.Dup(fd.sysfd)
613 if err != nil {
614 return nil, &OpError{"dup", fd.net, fd.laddr, err}
Keith Raricka144e3e2010-11-05 14:02:03 -0400615 }
616
617 // We want blocking mode for the new fd, hence the double negative.
Russ Coxc017a822011-11-13 22:44:52 -0500618 if err = syscall.SetNonblock(ns, false); err != nil {
619 return nil, &OpError{"setnonblock", fd.net, fd.laddr, err}
Keith Raricka144e3e2010-11-05 14:02:03 -0400620 }
621
622 return os.NewFile(ns, fd.sysfile.Name()), nil
623}
Alex Brainman3a052b52011-01-12 15:55:17 +1100624
Russ Coxc017a822011-11-13 22:44:52 -0500625func closesocket(s int) error {
Alex Brainman3a052b52011-01-12 15:55:17 +1100626 return syscall.Close(s)
627}