diff options
Diffstat (limited to 'src/pkg/net/fd_windows.go')
-rw-r--r-- | src/pkg/net/fd_windows.go | 160 |
1 files changed, 119 insertions, 41 deletions
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go index 90887b0a9..72685d612 100644 --- a/src/pkg/net/fd_windows.go +++ b/src/pkg/net/fd_windows.go @@ -5,11 +5,11 @@ package net import ( - "once" "os" "sync" "syscall" "unsafe" + "runtime" ) // BUG(brainman): The Windows implementation does not implement SetTimeout. @@ -29,15 +29,14 @@ type netFD struct { closing bool // immutable until Close - sysfd int - family int - proto int - sysfile *os.File - cr chan *ioResult - cw chan *ioResult - net string - laddr Addr - raddr Addr + sysfd int + family int + proto int + cr chan *ioResult + cw chan *ioResult + net string + laddr Addr + raddr Addr // owned by client rdeadline_delta int64 @@ -119,6 +118,7 @@ func (s *pollServer) Run() { // All the network FDs use a single pollServer. var pollserver *pollServer +var onceStartServer sync.Once func startServer() { p, err := newPollServer() @@ -134,7 +134,7 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err if initErr != nil { return nil, initErr } - once.Do(startServer) + onceStartServer.Do(startServer) // Associate our socket with pollserver.iocp. if _, e := syscall.CreateIoCompletionPort(int32(fd), pollserver.iocp, 0, 0); e != 0 { return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)} @@ -149,14 +149,7 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err laddr: laddr, raddr: raddr, } - var ls, rs string - if laddr != nil { - ls = laddr.String() - } - if raddr != nil { - rs = raddr.String() - } - f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs) + runtime.SetFinalizer(f, (*netFD).Close) return f, nil } @@ -178,15 +171,16 @@ func (fd *netFD) decref() { // can handle the extra OS processes. Otherwise we'll need to // use the pollserver for Close too. Sigh. syscall.SetNonblock(fd.sysfd, false) - fd.sysfile.Close() - fd.sysfile = nil + closesocket(fd.sysfd) fd.sysfd = -1 + // no need for a finalizer anymore + runtime.SetFinalizer(fd, nil) } fd.sysmu.Unlock() } func (fd *netFD) Close() os.Error { - if fd == nil || fd.sysfile == nil { + if fd == nil || fd.sysfd == -1 { return os.EINVAL } @@ -198,7 +192,11 @@ func (fd *netFD) Close() os.Error { } func newWSABuf(p []byte) *syscall.WSABuf { - return &syscall.WSABuf{uint32(len(p)), (*byte)(unsafe.Pointer(&p[0]))} + var p0 *byte + if len(p) > 0 { + p0 = (*byte)(unsafe.Pointer(&p[0])) + } + return &syscall.WSABuf{uint32(len(p)), p0} } func (fd *netFD) Read(p []byte) (n int, err os.Error) { @@ -209,7 +207,7 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) { defer fd.rio.Unlock() fd.incref() defer fd.decref() - if fd.sysfile == nil { + if fd.sysfd == -1 { return 0, os.EINVAL } // Submit receive request. @@ -232,12 +230,50 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) { err = &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(r.errno)} } n = int(r.qty) + if err == nil && n == 0 { + err = os.EOF + } return } func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) { - var r syscall.Sockaddr - return 0, r, nil + if fd == nil { + return 0, nil, os.EINVAL + } + if len(p) == 0 { + return 0, nil, nil + } + fd.rio.Lock() + defer fd.rio.Unlock() + fd.incref() + defer fd.decref() + if fd.sysfd == -1 { + return 0, nil, os.EINVAL + } + // Submit receive request. + var pckt ioPacket + pckt.c = fd.cr + var done uint32 + flags := uint32(0) + var rsa syscall.RawSockaddrAny + l := int32(unsafe.Sizeof(rsa)) + e := syscall.WSARecvFrom(uint32(fd.sysfd), newWSABuf(p), 1, &done, &flags, &rsa, &l, &pckt.o, nil) + 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, nil, &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(e)} + } + // Wait for our request to complete. + r := <-pckt.c + if r.errno != 0 { + err = &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(r.errno)} + } + n = int(r.qty) + sa, _ = rsa.Sockaddr() + return } func (fd *netFD) Write(p []byte) (n int, err os.Error) { @@ -248,7 +284,7 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) { defer fd.wio.Unlock() fd.incref() defer fd.decref() - if fd.sysfile == nil { + if fd.sysfd == -1 { return 0, os.EINVAL } // Submit send request. @@ -274,11 +310,43 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) { } func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) { - return 0, nil + if fd == nil { + return 0, os.EINVAL + } + if len(p) == 0 { + return 0, nil + } + fd.wio.Lock() + defer fd.wio.Unlock() + fd.incref() + defer fd.decref() + if fd.sysfd == -1 { + return 0, os.EINVAL + } + // Submit send request. + var pckt ioPacket + pckt.c = fd.cw + var done uint32 + e := syscall.WSASendto(uint32(fd.sysfd), newWSABuf(p), 1, &done, 0, sa, &pckt.o, nil) + 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{"WSASendTo", fd.net, fd.laddr, os.Errno(e)} + } + // Wait for our request to complete. + r := <-pckt.c + if r.errno != 0 { + err = &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(r.errno)} + } + n = int(r.qty) + return } func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) { - if fd == nil || fd.sysfile == nil { + if fd == nil || fd.sysfd == -1 { return nil, os.EINVAL } fd.incref() @@ -296,7 +364,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. syscall.ForkLock.RUnlock() // Associate our new socket with IOCP. - once.Do(startServer) + onceStartServer.Do(startServer) if _, e = syscall.CreateIoCompletionPort(int32(s), pollserver.iocp, 0, 0); e != 0 { return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)} } @@ -313,21 +381,21 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. case syscall.ERROR_IO_PENDING: // IO started, and we have to wait for it's completion. default: - syscall.Close(s) + closesocket(s) return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(e)} } // Wait for peer connection. r := <-pckt.c if r.errno != 0 { - syscall.Close(s) + closesocket(s) return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(r.errno)} } // Inherit properties of the listening socket. e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd) if e != 0 { - syscall.Close(s) + closesocket(s) return nil, &OpError{"Setsockopt", fd.net, fd.laddr, os.Errno(r.errno)} } @@ -348,17 +416,14 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. laddr: laddr, raddr: raddr, } - var ls, rs string - if laddr != nil { - ls = laddr.String() - } - if raddr != nil { - rs = raddr.String() - } - f.sysfile = os.NewFile(s, fd.net+":"+ls+"->"+rs) + runtime.SetFinalizer(f, (*netFD).Close) return f, nil } +func closesocket(s int) (errno int) { + return syscall.Closesocket(int32(s)) +} + func init() { var d syscall.WSAData e := syscall.WSAStartup(uint32(0x101), &d) @@ -366,3 +431,16 @@ func init() { initErr = os.NewSyscallError("WSAStartup", e) } } + +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 +} |