diff options
Diffstat (limited to 'src/pkg/net/fd_windows.go')
-rw-r--r-- | src/pkg/net/fd_windows.go | 176 |
1 files changed, 99 insertions, 77 deletions
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go index b025bddea..f00459f0b 100644 --- a/src/pkg/net/fd_windows.go +++ b/src/pkg/net/fd_windows.go @@ -5,6 +5,7 @@ package net import ( + "io" "os" "runtime" "sync" @@ -15,21 +16,21 @@ import ( type InvalidConnError struct{} -func (e *InvalidConnError) String() string { return "invalid net.Conn" } +func (e *InvalidConnError) Error() string { return "invalid net.Conn" } func (e *InvalidConnError) Temporary() bool { return false } func (e *InvalidConnError) Timeout() bool { return false } -var initErr os.Error +var initErr error func init() { var d syscall.WSAData e := syscall.WSAStartup(uint32(0x202), &d) - if e != 0 { + if e != nil { initErr = os.NewSyscallError("WSAStartup", e) } } -func closesocket(s syscall.Handle) (errno int) { +func closesocket(s syscall.Handle) (err error) { return syscall.Closesocket(s) } @@ -37,13 +38,13 @@ func closesocket(s syscall.Handle) (errno int) { type anOpIface interface { Op() *anOp Name() string - Submit() (errno int) + Submit() (err error) } // IO completion result parameters. type ioResult struct { qty uint32 - err int + err error } // anOp implements functionality common to all io operations. @@ -53,7 +54,7 @@ type anOp struct { o syscall.Overlapped resultc chan ioResult - errnoc chan int + errnoc chan error fd *netFD } @@ -70,7 +71,7 @@ func (o *anOp) Init(fd *netFD, mode int) { } o.resultc = fd.resultc[i] if fd.errnoc[i] == nil { - fd.errnoc[i] = make(chan int) + fd.errnoc[i] = make(chan error) } o.errnoc = fd.errnoc[i] } @@ -110,14 +111,14 @@ func (s *resultSrv) Run() { for { r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE) switch { - case r.err == 0: + case r.err == nil: // Dequeued successfully completed io packet. - case r.err == syscall.WAIT_TIMEOUT && o == nil: + case r.err == syscall.Errno(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)) + panic("GetQueuedCompletionStatus failed " + r.err.Error()) default: // Dequeued failed io packet. } @@ -149,12 +150,13 @@ func (s *ioSrv) ProcessRemoteIO() { } // ExecIO executes a single io operation. It either executes it -// inline, or, if timeouts are employed, passes the request onto +// inline, or, if a deadline is 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 +// deadline is unix nanos. +func (s *ioSrv) ExecIO(oi anOpIface, deadline int64) (n int, err error) { + var e error o := oi.Op() - if deadline_delta > 0 { + if deadline != 0 { // Send request to a special dedicated thread, // so it can stop the io with CancelIO later. s.submchan <- oi @@ -163,19 +165,25 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err os.Error) e = oi.Submit() } switch e { - case 0: + case nil: // 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 its completion. default: - return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(e)} + return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, e} } // Wait for our request to complete. var r ioResult - if deadline_delta > 0 { + if deadline != 0 { + dt := deadline - time.Now().UnixNano() + if dt < 1 { + dt = 1 + } + timer := time.NewTimer(time.Duration(dt) * time.Nanosecond) + defer timer.Stop() select { case r = <-o.resultc: - case <-time.After(deadline_delta): + case <-timer.C: s.canchan <- oi <-o.errnoc r = <-o.resultc @@ -186,8 +194,8 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err os.Error) } else { r = <-o.resultc } - if r.err != 0 { - err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(r.err)} + if r.err != nil { + err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, r.err} } return int(r.qty), err } @@ -199,10 +207,10 @@ 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)) + var err error + resultsrv.iocp, err = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1) + if err != nil { + panic("CreateIoCompletionPort: " + err.Error()) } go resultsrv.Run() @@ -220,43 +228,42 @@ type netFD struct { closing bool // immutable until Close - sysfd syscall.Handle - family int - proto int - net string - laddr Addr - raddr Addr - resultc [2]chan ioResult // read/write completion results - errnoc [2]chan int // read/write submit or cancel operation errors + sysfd syscall.Handle + family int + sotype int + isConnected bool + net string + laddr Addr + raddr Addr + resultc [2]chan ioResult // read/write completion results + errnoc [2]chan error // read/write submit or cancel operation errors // owned by client - rdeadline_delta int64 - rdeadline int64 - rio sync.Mutex - wdeadline_delta int64 - wdeadline int64 - wio sync.Mutex + rdeadline int64 + rio sync.Mutex + wdeadline int64 + wio sync.Mutex } -func allocFD(fd syscall.Handle, family, proto int, net string) (f *netFD) { +func allocFD(fd syscall.Handle, family, sotype int, net string) (f *netFD) { f = &netFD{ sysfd: fd, family: family, - proto: proto, + sotype: sotype, net: net, } runtime.SetFinalizer(f, (*netFD).Close) return f } -func newFD(fd syscall.Handle, family, proto int, net string) (f *netFD, err os.Error) { +func newFD(fd syscall.Handle, family, proto int, net string) (f *netFD, err 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) + if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != nil { + return nil, e } return allocFD(fd, family, proto, net), nil } @@ -266,12 +273,8 @@ func (fd *netFD) setAddr(laddr, raddr Addr) { 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 +func (fd *netFD) connect(ra syscall.Sockaddr) (err error) { + return syscall.Connect(fd.sysfd, ra) } // Add a reference to this fd. @@ -300,7 +303,7 @@ func (fd *netFD) decref() { fd.sysmu.Unlock() } -func (fd *netFD) Close() os.Error { +func (fd *netFD) Close() error { if fd == nil || fd.sysfd == syscall.InvalidHandle { return os.EINVAL } @@ -312,13 +315,32 @@ func (fd *netFD) Close() os.Error { return nil } +func (fd *netFD) shutdown(how int) error { + if fd == nil || fd.sysfd == syscall.InvalidHandle { + return os.EINVAL + } + err := syscall.Shutdown(fd.sysfd, how) + if err != nil { + return &OpError{"shutdown", fd.net, fd.laddr, err} + } + return nil +} + +func (fd *netFD) CloseRead() error { + return fd.shutdown(syscall.SHUT_RD) +} + +func (fd *netFD) CloseWrite() error { + return fd.shutdown(syscall.SHUT_WR) +} + // Read from network. type readOp struct { bufOp } -func (o *readOp) Submit() (errno int) { +func (o *readOp) Submit() (err error) { var d, f uint32 return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil) } @@ -327,7 +349,7 @@ func (o *readOp) Name() string { return "WSARecv" } -func (fd *netFD) Read(buf []byte) (n int, err os.Error) { +func (fd *netFD) Read(buf []byte) (n int, err error) { if fd == nil { return 0, os.EINVAL } @@ -340,9 +362,9 @@ func (fd *netFD) Read(buf []byte) (n int, err os.Error) { } var o readOp o.Init(fd, buf, 'r') - n, err = iosrv.ExecIO(&o, fd.rdeadline_delta) + n, err = iosrv.ExecIO(&o, fd.rdeadline) if err == nil && n == 0 { - err = os.EOF + err = io.EOF } return } @@ -355,7 +377,7 @@ type readFromOp struct { rsan int32 } -func (o *readFromOp) Submit() (errno int) { +func (o *readFromOp) Submit() (err error) { var d, f uint32 return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil) } @@ -364,7 +386,7 @@ func (o *readFromOp) Name() string { return "WSARecvFrom" } -func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err os.Error) { +func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) { if fd == nil { return 0, nil, os.EINVAL } @@ -381,7 +403,7 @@ func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err os.Error) var o readFromOp o.Init(fd, buf, 'r') o.rsan = int32(unsafe.Sizeof(o.rsa)) - n, err = iosrv.ExecIO(&o, fd.rdeadline_delta) + n, err = iosrv.ExecIO(&o, fd.rdeadline) if err != nil { return 0, nil, err } @@ -395,7 +417,7 @@ type writeOp struct { bufOp } -func (o *writeOp) Submit() (errno int) { +func (o *writeOp) Submit() (err error) { var d uint32 return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil) } @@ -404,7 +426,7 @@ func (o *writeOp) Name() string { return "WSASend" } -func (fd *netFD) Write(buf []byte) (n int, err os.Error) { +func (fd *netFD) Write(buf []byte) (n int, err error) { if fd == nil { return 0, os.EINVAL } @@ -417,7 +439,7 @@ func (fd *netFD) Write(buf []byte) (n int, err os.Error) { } var o writeOp o.Init(fd, buf, 'w') - return iosrv.ExecIO(&o, fd.wdeadline_delta) + return iosrv.ExecIO(&o, fd.wdeadline) } // WriteTo to network. @@ -427,7 +449,7 @@ type writeToOp struct { sa syscall.Sockaddr } -func (o *writeToOp) Submit() (errno int) { +func (o *writeToOp) Submit() (err error) { var d uint32 return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil) } @@ -436,7 +458,7 @@ func (o *writeToOp) Name() string { return "WSASendto" } -func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error) { +func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err error) { if fd == nil { return 0, os.EINVAL } @@ -453,7 +475,7 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error) var o writeToOp o.Init(fd, buf, 'w') o.sa = sa - return iosrv.ExecIO(&o, fd.wdeadline_delta) + return iosrv.ExecIO(&o, fd.wdeadline) } // Accept new network connections. @@ -464,7 +486,7 @@ type acceptOp struct { attrs [2]syscall.RawSockaddrAny // space for local and remote address only } -func (o *acceptOp) Submit() (errno int) { +func (o *acceptOp) Submit() (err error) { var d uint32 l := uint32(unsafe.Sizeof(o.attrs[0])) return syscall.AcceptEx(o.fd.sysfd, o.newsock, @@ -475,7 +497,7 @@ func (o *acceptOp) Name() string { return "AcceptEx" } -func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) { +func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err error) { if fd == nil || fd.sysfd == syscall.InvalidHandle { return nil, os.EINVAL } @@ -485,18 +507,18 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. // 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 { + s, e := syscall.Socket(fd.family, fd.sotype, 0) + if e != nil { syscall.ForkLock.RUnlock() - return nil, os.Errno(e) + return nil, 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)} + if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != nil { + return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, e} } // Submit accept request. @@ -511,9 +533,9 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. // Inherit properties of the listening socket. e = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))) - if e != 0 { + if e != nil { closesocket(s) - return nil, err + return nil, e } // Get local and peer addr out of AcceptEx buffer. @@ -525,22 +547,22 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. lsa, _ := lrsa.Sockaddr() rsa, _ := rrsa.Sockaddr() - nfd = allocFD(s, fd.family, fd.proto, fd.net) + nfd = allocFD(s, fd.family, fd.sotype, fd.net) nfd.setAddr(toAddr(lsa), toAddr(rsa)) return nfd, nil } // Unimplemented functions. -func (fd *netFD) dup() (f *os.File, err os.Error) { +func (fd *netFD) dup() (f *os.File, err 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) { +func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err 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) { +func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { return 0, 0, os.EAFNOSUPPORT } |