diff options
Diffstat (limited to 'src/pkg/net/fd_windows.go')
-rw-r--r-- | src/pkg/net/fd_windows.go | 529 |
1 files changed, 0 insertions, 529 deletions
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go deleted file mode 100644 index 41d06120a..000000000 --- a/src/pkg/net/fd_windows.go +++ /dev/null @@ -1,529 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "os" - "runtime" - "sync" - "syscall" - "time" - "unsafe" -) - -type InvalidConnError struct{} - -func (e *InvalidConnError) String() string { return "invalid net.Conn" } -func (e *InvalidConnError) Temporary() bool { return false } -func (e *InvalidConnError) Timeout() bool { return false } - -var initErr os.Error - -func init() { - var d syscall.WSAData - e := syscall.WSAStartup(uint32(0x101), &d) - if e != 0 { - initErr = os.NewSyscallError("WSAStartup", e) - } -} - -func closesocket(s syscall.Handle) (errno int) { - return syscall.Closesocket(s) -} - -// Interface for all io operations. -type anOpIface interface { - Op() *anOp - Name() string - Submit() (errno int) -} - -// IO completion result parameters. -type ioResult struct { - qty uint32 - err int -} - -// anOp implements functionality common to all io operations. -type anOp struct { - // Used by IOCP interface, it must be first field - // of the struct, as our code rely on it. - o syscall.Overlapped - - resultc chan ioResult // io completion results - errnoc chan int // io submit / cancel operation errors - fd *netFD -} - -func (o *anOp) Init(fd *netFD) { - o.fd = fd - o.resultc = make(chan ioResult, 1) - o.errnoc = make(chan int) -} - -func (o *anOp) Op() *anOp { - return o -} - -// bufOp is used by io operations that read / write -// data from / to client buffer. -type bufOp struct { - anOp - buf syscall.WSABuf -} - -func (o *bufOp) Init(fd *netFD, buf []byte) { - o.anOp.Init(fd) - o.buf.Len = uint32(len(buf)) - if len(buf) == 0 { - o.buf.Buf = nil - } else { - o.buf.Buf = (*byte)(unsafe.Pointer(&buf[0])) - } -} - -// resultSrv will retrieve all io completion results from -// iocp and send them to the correspondent waiting client -// goroutine via channel supplied in the request. -type resultSrv struct { - iocp syscall.Handle -} - -func (s *resultSrv) Run() { - var o *syscall.Overlapped - var key uint32 - var r ioResult - for { - r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE) - switch { - case r.err == 0: - // Dequeued successfully completed io packet. - case r.err == syscall.WAIT_TIMEOUT && o == nil: - // Wait has timed out (should not happen now, but might be used in the future). - panic("GetQueuedCompletionStatus timed out") - case o == nil: - // Failed to dequeue anything -> report the error. - panic("GetQueuedCompletionStatus failed " + syscall.Errstr(r.err)) - default: - // Dequeued failed io packet. - } - (*anOp)(unsafe.Pointer(o)).resultc <- r - } -} - - -// ioSrv executes net io requests. -type ioSrv struct { - submchan chan anOpIface // submit io requests - canchan chan anOpIface // cancel io requests -} - -// ProcessRemoteIO will execute submit io requests on behalf -// of other goroutines, all on a single os thread, so it can -// cancel them later. Results of all operations will be sent -// back to their requesters via channel supplied in request. -func (s *ioSrv) ProcessRemoteIO() { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - for { - select { - case o := <-s.submchan: - o.Op().errnoc <- o.Submit() - case o := <-s.canchan: - o.Op().errnoc <- syscall.CancelIo(syscall.Handle(o.Op().fd.sysfd)) - } - } -} - -// ExecIO executes a single io operation. It either executes it -// inline, or, if timeouts are employed, passes the request onto -// a special goroutine and waits for completion or cancels request. -func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err os.Error) { - var e int - o := oi.Op() - if deadline_delta > 0 { - // Send request to a special dedicated thread, - // so it can stop the io with CancelIO later. - s.submchan <- oi - e = <-o.errnoc - } else { - e = oi.Submit() - } - switch e { - case 0: - // IO completed immediately, but we need to get our completion message anyway. - case syscall.ERROR_IO_PENDING: - // IO started, and we have to wait for it's completion. - default: - return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(e)} - } - // Wait for our request to complete. - var r ioResult - if deadline_delta > 0 { - select { - case r = <-o.resultc: - case <-time.After(deadline_delta): - s.canchan <- oi - <-o.errnoc - r = <-o.resultc - if r.err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled - r.err = syscall.EWOULDBLOCK - } - } - } else { - r = <-o.resultc - } - if r.err != 0 { - err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(r.err)} - } - return int(r.qty), err -} - -// Start helper goroutines. -var resultsrv *resultSrv -var iosrv *ioSrv -var onceStartServer sync.Once - -func startServer() { - resultsrv = new(resultSrv) - var errno int - resultsrv.iocp, errno = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1) - if errno != 0 { - panic("CreateIoCompletionPort failed " + syscall.Errstr(errno)) - } - go resultsrv.Run() - - iosrv = new(ioSrv) - iosrv.submchan = make(chan anOpIface) - iosrv.canchan = make(chan anOpIface) - go iosrv.ProcessRemoteIO() -} - -// Network file descriptor. -type netFD struct { - // locking/lifetime of sysfd - sysmu sync.Mutex - sysref int - closing bool - - // immutable until Close - sysfd syscall.Handle - family int - proto int - net string - laddr Addr - raddr Addr - - // owned by client - rdeadline_delta int64 - rdeadline int64 - rio sync.Mutex - wdeadline_delta int64 - wdeadline int64 - wio sync.Mutex -} - -func allocFD(fd syscall.Handle, family, proto int, net string) (f *netFD) { - f = &netFD{ - sysfd: fd, - family: family, - proto: proto, - net: net, - } - runtime.SetFinalizer(f, (*netFD).Close) - return f -} - -func newFD(fd syscall.Handle, family, proto int, net string) (f *netFD, err os.Error) { - if initErr != nil { - return nil, initErr - } - onceStartServer.Do(startServer) - // Associate our socket with resultsrv.iocp. - if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != 0 { - return nil, os.Errno(e) - } - return allocFD(fd, family, proto, net), nil -} - -func (fd *netFD) setAddr(laddr, raddr Addr) { - fd.laddr = laddr - fd.raddr = raddr -} - -func (fd *netFD) connect(ra syscall.Sockaddr) (err os.Error) { - e := syscall.Connect(fd.sysfd, ra) - if e != 0 { - return os.Errno(e) - } - return nil -} - -// Add a reference to this fd. -func (fd *netFD) incref() { - fd.sysmu.Lock() - fd.sysref++ - fd.sysmu.Unlock() -} - -// Remove a reference to this FD and close if we've been asked to do so (and -// there are no references left. -func (fd *netFD) decref() { - fd.sysmu.Lock() - fd.sysref-- - if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 { - // In case the user has set linger, switch to blocking mode so - // the close blocks. As long as this doesn't happen often, we - // can handle the extra OS processes. Otherwise we'll need to - // use the resultsrv for Close too. Sigh. - syscall.SetNonblock(fd.sysfd, false) - closesocket(fd.sysfd) - fd.sysfd = syscall.InvalidHandle - // no need for a finalizer anymore - runtime.SetFinalizer(fd, nil) - } - fd.sysmu.Unlock() -} - -func (fd *netFD) Close() os.Error { - if fd == nil || fd.sysfd == syscall.InvalidHandle { - return os.EINVAL - } - - fd.incref() - syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR) - fd.closing = true - fd.decref() - return nil -} - -// Read from network. - -type readOp struct { - bufOp -} - -func (o *readOp) Submit() (errno int) { - var d, f uint32 - return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil) -} - -func (o *readOp) Name() string { - return "WSARecv" -} - -func (fd *netFD) Read(buf []byte) (n int, err os.Error) { - if fd == nil { - return 0, os.EINVAL - } - fd.rio.Lock() - defer fd.rio.Unlock() - fd.incref() - defer fd.decref() - if fd.sysfd == syscall.InvalidHandle { - return 0, os.EINVAL - } - var o readOp - o.Init(fd, buf) - n, err = iosrv.ExecIO(&o, fd.rdeadline_delta) - if err == nil && n == 0 { - err = os.EOF - } - return -} - -// ReadFrom from network. - -type readFromOp struct { - bufOp - rsa syscall.RawSockaddrAny -} - -func (o *readFromOp) Submit() (errno int) { - var d, f uint32 - l := int32(unsafe.Sizeof(o.rsa)) - return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &l, &o.o, nil) -} - -func (o *readFromOp) Name() string { - return "WSARecvFrom" -} - -func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err os.Error) { - if fd == nil { - return 0, nil, os.EINVAL - } - if len(buf) == 0 { - return 0, nil, nil - } - fd.rio.Lock() - defer fd.rio.Unlock() - fd.incref() - defer fd.decref() - if fd.sysfd == syscall.InvalidHandle { - return 0, nil, os.EINVAL - } - var o readFromOp - o.Init(fd, buf) - n, err = iosrv.ExecIO(&o, fd.rdeadline_delta) - sa, _ = o.rsa.Sockaddr() - return -} - -// Write to network. - -type writeOp struct { - bufOp -} - -func (o *writeOp) Submit() (errno int) { - var d uint32 - return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil) -} - -func (o *writeOp) Name() string { - return "WSASend" -} - -func (fd *netFD) Write(buf []byte) (n int, err os.Error) { - if fd == nil { - return 0, os.EINVAL - } - fd.wio.Lock() - defer fd.wio.Unlock() - fd.incref() - defer fd.decref() - if fd.sysfd == syscall.InvalidHandle { - return 0, os.EINVAL - } - var o writeOp - o.Init(fd, buf) - return iosrv.ExecIO(&o, fd.wdeadline_delta) -} - -// WriteTo to network. - -type writeToOp struct { - bufOp - sa syscall.Sockaddr -} - -func (o *writeToOp) Submit() (errno int) { - var d uint32 - return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil) -} - -func (o *writeToOp) Name() string { - return "WSASendto" -} - -func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error) { - if fd == nil { - return 0, os.EINVAL - } - if len(buf) == 0 { - return 0, nil - } - fd.wio.Lock() - defer fd.wio.Unlock() - fd.incref() - defer fd.decref() - if fd.sysfd == syscall.InvalidHandle { - return 0, os.EINVAL - } - var o writeToOp - o.Init(fd, buf) - o.sa = sa - return iosrv.ExecIO(&o, fd.wdeadline_delta) -} - -// Accept new network connections. - -type acceptOp struct { - anOp - newsock syscall.Handle - attrs [2]syscall.RawSockaddrAny // space for local and remote address only -} - -func (o *acceptOp) Submit() (errno int) { - var d uint32 - l := uint32(unsafe.Sizeof(o.attrs[0])) - return syscall.AcceptEx(o.fd.sysfd, o.newsock, - (*byte)(unsafe.Pointer(&o.attrs[0])), 0, l, l, &d, &o.o) -} - -func (o *acceptOp) Name() string { - return "AcceptEx" -} - -func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) { - if fd == nil || fd.sysfd == syscall.InvalidHandle { - return nil, os.EINVAL - } - fd.incref() - defer fd.decref() - - // Get new socket. - // See ../syscall/exec.go for description of ForkLock. - syscall.ForkLock.RLock() - s, e := syscall.Socket(fd.family, fd.proto, 0) - if e != 0 { - syscall.ForkLock.RUnlock() - return nil, os.Errno(e) - } - syscall.CloseOnExec(s) - syscall.ForkLock.RUnlock() - - // Associate our new socket with IOCP. - onceStartServer.Do(startServer) - if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != 0 { - return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)} - } - - // Submit accept request. - var o acceptOp - o.Init(fd) - o.newsock = s - _, err = iosrv.ExecIO(&o, 0) - if err != nil { - closesocket(s) - return nil, err - } - - // Inherit properties of the listening socket. - e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, int(fd.sysfd)) - if e != 0 { - closesocket(s) - return nil, err - } - - // Get local and peer addr out of AcceptEx buffer. - var lrsa, rrsa *syscall.RawSockaddrAny - var llen, rlen int32 - l := uint32(unsafe.Sizeof(*lrsa)) - syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&o.attrs[0])), - 0, l, l, &lrsa, &llen, &rrsa, &rlen) - lsa, _ := lrsa.Sockaddr() - rsa, _ := rrsa.Sockaddr() - - nfd = allocFD(s, fd.family, fd.proto, fd.net) - nfd.setAddr(toAddr(lsa), toAddr(rsa)) - return nfd, nil -} - -// Unimplemented functions. - -func (fd *netFD) dup() (f *os.File, err os.Error) { - // TODO: Implement this - return nil, os.NewSyscallError("dup", syscall.EWINDOWS) -} - -func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) { - return 0, 0, 0, nil, os.EAFNOSUPPORT -} - -func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) { - return 0, 0, os.EAFNOSUPPORT -} |