1 // Copyright 2010 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.
22 e := syscall.WSAStartup(uint32(0x202), &d)
24 initErr = os.NewSyscallError("WSAStartup", e)
28 func closesocket(s syscall.Handle) error {
29 return syscall.Closesocket(s)
32 // Interface for all io operations.
33 type anOpIface interface {
39 // IO completion result parameters.
40 type ioResult struct {
45 // anOp implements functionality common to all io operations.
47 // Used by IOCP interface, it must be first field
48 // of the struct, as our code rely on it.
56 func (o *anOp) Init(fd *netFD, mode int) {
64 if fd.resultc[i] == nil {
65 fd.resultc[i] = make(chan ioResult, 1)
67 o.resultc = fd.resultc[i]
68 if fd.errnoc[i] == nil {
69 fd.errnoc[i] = make(chan error)
71 o.errnoc = fd.errnoc[i]
74 func (o *anOp) Op() *anOp {
78 // bufOp is used by io operations that read / write
79 // data from / to client buffer.
85 func (o *bufOp) Init(fd *netFD, buf []byte, mode int) {
87 o.buf.Len = uint32(len(buf))
91 o.buf.Buf = (*byte)(unsafe.Pointer(&buf[0]))
95 // resultSrv will retrieve all io completion results from
96 // iocp and send them to the correspondent waiting client
97 // goroutine via channel supplied in the request.
98 type resultSrv struct {
102 func (s *resultSrv) Run() {
103 var o *syscall.Overlapped
107 r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE)
110 // Dequeued successfully completed io packet.
111 case r.err == syscall.Errno(syscall.WAIT_TIMEOUT) && o == nil:
112 // Wait has timed out (should not happen now, but might be used in the future).
113 panic("GetQueuedCompletionStatus timed out")
115 // Failed to dequeue anything -> report the error.
116 panic("GetQueuedCompletionStatus failed " + r.err.Error())
118 // Dequeued failed io packet.
120 (*anOp)(unsafe.Pointer(o)).resultc <- r
124 // ioSrv executes net io requests.
126 submchan chan anOpIface // submit io requests
127 canchan chan anOpIface // cancel io requests
130 // ProcessRemoteIO will execute submit io requests on behalf
131 // of other goroutines, all on a single os thread, so it can
132 // cancel them later. Results of all operations will be sent
133 // back to their requesters via channel supplied in request.
134 func (s *ioSrv) ProcessRemoteIO() {
135 runtime.LockOSThread()
136 defer runtime.UnlockOSThread()
139 case o := <-s.submchan:
140 o.Op().errnoc <- o.Submit()
141 case o := <-s.canchan:
142 o.Op().errnoc <- syscall.CancelIo(syscall.Handle(o.Op().fd.sysfd))
147 // ExecIO executes a single io operation. It either executes it
148 // inline, or, if a deadline is employed, passes the request onto
149 // a special goroutine and waits for completion or cancels request.
150 // deadline is unix nanos.
151 func (s *ioSrv) ExecIO(oi anOpIface, deadline int64) (int, error) {
155 // Send request to a special dedicated thread,
156 // so it can stop the io with CancelIO later.
164 // IO completed immediately, but we need to get our completion message anyway.
165 case syscall.ERROR_IO_PENDING:
166 // IO started, and we have to wait for its completion.
169 return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, err}
171 // Wait for our request to complete.
174 dt := deadline - time.Now().UnixNano()
178 timer := time.NewTimer(time.Duration(dt) * time.Nanosecond)
181 case r = <-o.resultc:
186 if r.err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
187 r.err = syscall.EWOULDBLOCK
194 err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, r.err}
196 return int(r.qty), err
199 // Start helper goroutines.
200 var resultsrv *resultSrv
202 var onceStartServer sync.Once
205 resultsrv = new(resultSrv)
207 resultsrv.iocp, err = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1)
209 panic("CreateIoCompletionPort: " + err.Error())
214 iosrv.submchan = make(chan anOpIface)
215 iosrv.canchan = make(chan anOpIface)
216 go iosrv.ProcessRemoteIO()
219 // Network file descriptor.
221 // locking/lifetime of sysfd
226 // immutable until Close
234 resultc [2]chan ioResult // read/write completion results
235 errnoc [2]chan error // read/write submit or cancel operation errors
244 func allocFD(fd syscall.Handle, family, sotype int, net string) *netFD {
251 runtime.SetFinalizer(netfd, (*netFD).Close)
255 func newFD(fd syscall.Handle, family, proto int, net string) (*netFD, error) {
259 onceStartServer.Do(startServer)
260 // Associate our socket with resultsrv.iocp.
261 if _, err := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); err != nil {
264 return allocFD(fd, family, proto, net), nil
267 func (fd *netFD) setAddr(laddr, raddr Addr) {
272 func (fd *netFD) connect(ra syscall.Sockaddr) error {
273 return syscall.Connect(fd.sysfd, ra)
276 var errClosing = errors.New("use of closed network connection")
278 // Add a reference to this fd.
279 // If closing==true, mark the fd as closing.
280 // Returns an error if the fd cannot be used.
281 func (fd *netFD) incref(closing bool) error {
299 // Remove a reference to this FD and close if we've been asked to do so (and
300 // there are no references left.
301 func (fd *netFD) decref() {
304 // NOTE(rsc): On Unix we check fd.sysref == 0 here before closing,
305 // but on Windows we have no way to wake up the blocked I/O other
306 // than closing the socket (or calling Shutdown, which breaks other
307 // programs that might have a reference to the socket). So there is
308 // a small race here that we might close fd.sysfd and then some other
309 // goroutine might start a read of fd.sysfd (having read it before we
310 // write InvalidHandle to it), which might refer to some other file
311 // if the specific handle value gets reused. I think handle values on
312 // Windows are not reused as aggressively as file descriptors on Unix,
313 // so this might be tolerable.
314 if fd.closing && fd.sysfd != syscall.InvalidHandle {
315 // In case the user has set linger, switch to blocking mode so
316 // the close blocks. As long as this doesn't happen often, we
317 // can handle the extra OS processes. Otherwise we'll need to
318 // use the resultsrv for Close too. Sigh.
319 syscall.SetNonblock(fd.sysfd, false)
320 closesocket(fd.sysfd)
321 fd.sysfd = syscall.InvalidHandle
322 // no need for a finalizer anymore
323 runtime.SetFinalizer(fd, nil)
328 func (fd *netFD) Close() error {
329 if err := fd.incref(true); err != nil {
336 func (fd *netFD) shutdown(how int) error {
337 if fd == nil || fd.sysfd == syscall.InvalidHandle {
338 return syscall.EINVAL
340 err := syscall.Shutdown(fd.sysfd, how)
342 return &OpError{"shutdown", fd.net, fd.laddr, err}
347 func (fd *netFD) CloseRead() error {
348 return fd.shutdown(syscall.SHUT_RD)
351 func (fd *netFD) CloseWrite() error {
352 return fd.shutdown(syscall.SHUT_WR)
355 // Read from network.
361 func (o *readOp) Submit() error {
363 return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
366 func (o *readOp) Name() string {
370 func (fd *netFD) Read(buf []byte) (int, error) {
372 return 0, syscall.EINVAL
375 defer fd.rio.Unlock()
376 if err := fd.incref(false); err != nil {
380 if fd.sysfd == syscall.InvalidHandle {
381 return 0, syscall.EINVAL
385 n, err := iosrv.ExecIO(&o, fd.rdeadline)
386 if err == nil && n == 0 {
392 // ReadFrom from network.
394 type readFromOp struct {
396 rsa syscall.RawSockaddrAny
400 func (o *readFromOp) Submit() error {
402 return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil)
405 func (o *readFromOp) Name() string {
409 func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
411 return 0, nil, syscall.EINVAL
417 defer fd.rio.Unlock()
418 if err := fd.incref(false); err != nil {
424 o.rsan = int32(unsafe.Sizeof(o.rsa))
425 n, err = iosrv.ExecIO(&o, fd.rdeadline)
429 sa, _ = o.rsa.Sockaddr()
435 type writeOp struct {
439 func (o *writeOp) Submit() error {
441 return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil)
444 func (o *writeOp) Name() string {
448 func (fd *netFD) Write(buf []byte) (int, error) {
450 return 0, syscall.EINVAL
453 defer fd.wio.Unlock()
454 if err := fd.incref(false); err != nil {
460 return iosrv.ExecIO(&o, fd.wdeadline)
463 // WriteTo to network.
465 type writeToOp struct {
470 func (o *writeToOp) Submit() error {
472 return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil)
475 func (o *writeToOp) Name() string {
479 func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
481 return 0, syscall.EINVAL
487 defer fd.wio.Unlock()
488 if err := fd.incref(false); err != nil {
492 if fd.sysfd == syscall.InvalidHandle {
493 return 0, syscall.EINVAL
498 return iosrv.ExecIO(&o, fd.wdeadline)
501 // Accept new network connections.
503 type acceptOp struct {
505 newsock syscall.Handle
506 attrs [2]syscall.RawSockaddrAny // space for local and remote address only
509 func (o *acceptOp) Submit() error {
511 l := uint32(unsafe.Sizeof(o.attrs[0]))
512 return syscall.AcceptEx(o.fd.sysfd, o.newsock,
513 (*byte)(unsafe.Pointer(&o.attrs[0])), 0, l, l, &d, &o.o)
516 func (o *acceptOp) Name() string {
520 func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
521 if err := fd.incref(false); err != nil {
527 // See ../syscall/exec.go for description of ForkLock.
528 syscall.ForkLock.RLock()
529 s, err := syscall.Socket(fd.family, fd.sotype, 0)
531 syscall.ForkLock.RUnlock()
534 syscall.CloseOnExec(s)
535 syscall.ForkLock.RUnlock()
537 // Associate our new socket with IOCP.
538 onceStartServer.Do(startServer)
539 if _, err := syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); err != nil {
540 return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, err}
543 // Submit accept request.
547 _, err = iosrv.ExecIO(&o, 0)
553 // Inherit properties of the listening socket.
554 err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
560 // Get local and peer addr out of AcceptEx buffer.
561 var lrsa, rrsa *syscall.RawSockaddrAny
563 l := uint32(unsafe.Sizeof(*lrsa))
564 syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&o.attrs[0])),
565 0, l, l, &lrsa, &llen, &rrsa, &rlen)
566 lsa, _ := lrsa.Sockaddr()
567 rsa, _ := rrsa.Sockaddr()
569 netfd := allocFD(s, fd.family, fd.sotype, fd.net)
570 netfd.setAddr(toAddr(lsa), toAddr(rsa))
574 // Unimplemented functions.
576 func (fd *netFD) dup() (*os.File, error) {
577 // TODO: Implement this
578 return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
581 var errNoSupport = errors.New("address family not supported")
583 func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
584 return 0, 0, 0, nil, errNoSupport
587 func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
588 return 0, 0, errNoSupport