diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-03-16 23:05:44 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-03-16 23:05:44 +0000 |
commit | 31c6ec422702226aabab7d082da16663e6c3e72c (patch) | |
tree | 44176975832a3faf1626836e70c97d5edd674122 /libgo/go/net/fd_windows.go | |
parent | b3145af52cfb7c84d62a8e4ceeb165a7369718da (diff) | |
download | gcc-31c6ec422702226aabab7d082da16663e6c3e72c.tar.gz |
Update to current version of Go library (revision 94d654be2064).
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@171076 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/net/fd_windows.go')
-rw-r--r-- | libgo/go/net/fd_windows.go | 655 |
1 files changed, 308 insertions, 347 deletions
diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go index 9b91eb398cb..63a8fbc4489 100644 --- a/libgo/go/net/fd_windows.go +++ b/libgo/go/net/fd_windows.go @@ -13,147 +13,241 @@ import ( "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 int) (errno int) { + return syscall.Closesocket(int32(s)) +} + +// Interface for all io operations. +type anOpIface interface { + Op() *anOp + Name() string + Submit() (errno int) +} + // IO completion result parameters. type ioResult struct { - key uint32 - qty uint32 - errno int + qty uint32 + err int } -// Network file descriptor. -type netFD struct { - // locking/lifetime of sysfd - sysmu sync.Mutex - sysref int - closing bool +// 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 - // immutable until Close - sysfd int - family int - proto int - cr chan *ioResult - cw chan *ioResult - net string - laddr Addr - raddr Addr + resultc chan ioResult // io completion results + errnoc chan int // io submit / cancel operation errors + fd *netFD +} - // owned by client - rdeadline_delta int64 - rdeadline int64 - rio sync.Mutex - wdeadline_delta int64 - wdeadline int64 - wio sync.Mutex +func (o *anOp) Init(fd *netFD) { + o.fd = fd + o.resultc = make(chan ioResult, 1) + o.errnoc = make(chan int) } -type InvalidConnError struct{} +func (o *anOp) Op() *anOp { + return o +} -func (e *InvalidConnError) String() string { return "invalid net.Conn" } -func (e *InvalidConnError) Temporary() bool { return false } -func (e *InvalidConnError) Timeout() bool { return false } +// bufOp is used by io operations that read / write +// data from / to client buffer. +type bufOp struct { + anOp + buf syscall.WSABuf +} -// pollServer will run around waiting for io completion request -// to arrive. Every request received will contain channel to signal -// io owner about the completion. +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])) + } +} -type pollServer struct { +// resultSrv will retreive 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 int32 } -func newPollServer() (s *pollServer, err os.Error) { - s = new(pollServer) - var e int - if s.iocp, e = syscall.CreateIoCompletionPort(-1, 0, 0, 1); e != 0 { - return nil, os.NewSyscallError("CreateIoCompletionPort", e) +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 } - go s.Run() - return s, nil } -type ioPacket struct { - // Used by IOCP interface, - // it must be first field of the struct, - // as our code rely on it. - o syscall.Overlapped - // Link to the io owner. - c chan *ioResult - - w *syscall.WSABuf +// ioSrv executes net io requests. +type ioSrv struct { + submchan chan anOpIface // submit io requests + canchan chan anOpIface // cancel io requests } -func (s *pollServer) getCompletedIO() (ov *syscall.Overlapped, result *ioResult, err os.Error) { - var r ioResult - var o *syscall.Overlapped - _, e := syscall.GetQueuedCompletionStatus(s.iocp, &r.qty, &r.key, &o, syscall.INFINITE) - switch { - case e == 0: - // Dequeued successfully completed io packet. - return o, &r, nil - case e == syscall.WAIT_TIMEOUT && o == nil: - // Wait has timed out (should not happen now, but might be used in the future). - return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e) - case o == nil: - // Failed to dequeue anything -> report the error. - return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e) - default: - // Dequeued failed io packet. - r.errno = e - return o, &r, nil +// 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(uint32(o.Op().fd.sysfd)) + } } - return } -func (s *pollServer) Run() { - for { - o, r, err := s.getCompletedIO() - if err != nil { - panic("Run pollServer: " + err.String() + "\n") +// 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 + } } - p := (*ioPacket)(unsafe.Pointer(o)) - p.c <- r + } 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 } -// Network FD methods. -// All the network FDs use a single pollServer. - -var pollserver *pollServer +// Start helper goroutines. +var resultsrv *resultSrv +var iosrv *ioSrv var onceStartServer sync.Once func startServer() { - p, err := newPollServer() - if err != nil { - panic("Start pollServer: " + err.String() + "\n") - } - pollserver = p - - go timeoutIO() + resultsrv = new(resultSrv) + var errno int + resultsrv.iocp, errno = syscall.CreateIoCompletionPort(-1, 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() } -var initErr os.Error +// Network file descriptor. +type netFD struct { + // locking/lifetime of sysfd + sysmu sync.Mutex + sysref int + closing bool -func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) { - if initErr != nil { - return nil, initErr - } - 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)} - } + // immutable until Close + sysfd int + 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, family, proto int, net string, laddr, raddr Addr) (f *netFD) { f = &netFD{ sysfd: fd, family: family, proto: proto, - cr: make(chan *ioResult, 1), - cw: make(chan *ioResult, 1), net: net, laddr: laddr, raddr: raddr, } runtime.SetFinalizer(f, (*netFD).Close) - return f, nil + return f +} + +func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) { + if initErr != nil { + return nil, initErr + } + onceStartServer.Do(startServer) + // Associate our socket with resultsrv.iocp. + if _, e := syscall.CreateIoCompletionPort(int32(fd), resultsrv.iocp, 0, 0); e != 0 { + return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)} + } + return allocFD(fd, family, proto, net, laddr, raddr), nil } // Add a reference to this fd. @@ -172,7 +266,7 @@ func (fd *netFD) decref() { // 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 pollserver for Close too. Sigh. + // use the resultsrv for Close too. Sigh. syscall.SetNonblock(fd.sysfd, false) closesocket(fd.sysfd) fd.sysfd = -1 @@ -194,89 +288,22 @@ func (fd *netFD) Close() os.Error { return nil } -func newWSABuf(p []byte) *syscall.WSABuf { - var p0 *byte - if len(p) > 0 { - p0 = (*byte)(unsafe.Pointer(&p[0])) - } - return &syscall.WSABuf{uint32(len(p)), p0} -} - -func waitPacket(fd *netFD, pckt *ioPacket, mode int) (r *ioResult) { - var delta int64 - if mode == 'r' { - delta = fd.rdeadline_delta - } - if mode == 'w' { - delta = fd.wdeadline_delta - } - if delta <= 0 { - return <-pckt.c - } +// Read from network. - select { - case r = <-pckt.c: - case <-time.After(delta): - a := &arg{f: cancel, fd: fd, pckt: pckt, c: make(chan int)} - ioChan <- a - <-a.c - r = <-pckt.c - if r.errno == 995 { // IO Canceled - r.errno = syscall.EWOULDBLOCK - } - } - return r +type readOp struct { + bufOp } -const ( - read = iota - readfrom - write - writeto - cancel -) +func (o *readOp) Submit() (errno int) { + var d, f uint32 + return syscall.WSARecv(uint32(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil) +} -type arg struct { - f int - fd *netFD - pckt *ioPacket - done *uint32 - flags *uint32 - rsa *syscall.RawSockaddrAny - size *int32 - sa *syscall.Sockaddr - c chan int -} - -var ioChan chan *arg = make(chan *arg) - -func timeoutIO() { - // CancelIO only cancels all pending input and output (I/O) operations that are - // issued by the calling thread for the specified file, does not cancel I/O - // operations that other threads issue for a file handle. So we need do all timeout - // I/O in single OS thread. - runtime.LockOSThread() - defer runtime.UnlockOSThread() - for { - o := <-ioChan - var e int - switch o.f { - case read: - e = syscall.WSARecv(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, o.flags, &o.pckt.o, nil) - case readfrom: - e = syscall.WSARecvFrom(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, o.flags, o.rsa, o.size, &o.pckt.o, nil) - case write: - e = syscall.WSASend(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, uint32(0), &o.pckt.o, nil) - case writeto: - e = syscall.WSASendto(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, 0, *o.sa, &o.pckt.o, nil) - case cancel: - _, e = syscall.CancelIo(uint32(o.fd.sysfd)) - } - o.c <- e - } +func (o *readOp) Name() string { + return "WSARecv" } -func (fd *netFD) Read(p []byte) (n int, err os.Error) { +func (fd *netFD) Read(buf []byte) (n int, err os.Error) { if fd == nil { return 0, os.EINVAL } @@ -287,45 +314,37 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) { if fd.sysfd == -1 { return 0, os.EINVAL } - // Submit receive request. - var pckt ioPacket - pckt.c = fd.cr - pckt.w = newWSABuf(p) - var done uint32 - flags := uint32(0) - var e int - if fd.rdeadline_delta > 0 { - a := &arg{f: read, fd: fd, pckt: &pckt, done: &done, flags: &flags, c: make(chan int)} - ioChan <- a - e = <-a.c - } else { - e = syscall.WSARecv(uint32(fd.sysfd), pckt.w, 1, &done, &flags, &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{"WSARecv", fd.net, fd.laddr, os.Errno(e)} - } - // Wait for our request to complete. - r := waitPacket(fd, &pckt, 'r') - if r.errno != 0 { - err = &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(r.errno)} - } - n = int(r.qty) + var o readOp + o.Init(fd, buf) + n, err = iosrv.ExecIO(&o, fd.rdeadline_delta) if err == nil && n == 0 { err = os.EOF } return } -func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) { +// 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(uint32(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(p) == 0 { + if len(buf) == 0 { return 0, nil, nil } fd.rio.Lock() @@ -335,41 +354,29 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) { if fd.sysfd == -1 { return 0, nil, os.EINVAL } - // Submit receive request. - var pckt ioPacket - pckt.c = fd.cr - pckt.w = newWSABuf(p) - var done uint32 - flags := uint32(0) - var rsa syscall.RawSockaddrAny - l := int32(unsafe.Sizeof(rsa)) - var e int - if fd.rdeadline_delta > 0 { - a := &arg{f: readfrom, fd: fd, pckt: &pckt, done: &done, flags: &flags, rsa: &rsa, size: &l, c: make(chan int)} - ioChan <- a - e = <-a.c - } else { - e = syscall.WSARecvFrom(uint32(fd.sysfd), pckt.w, 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 := waitPacket(fd, &pckt, 'r') - if r.errno != 0 { - err = &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(r.errno)} - } - n = int(r.qty) - sa, _ = rsa.Sockaddr() + var o readFromOp + o.Init(fd, buf) + n, err = iosrv.ExecIO(&o, fd.rdeadline_delta) + sa, _ = o.rsa.Sockaddr() return } -func (fd *netFD) Write(p []byte) (n int, err os.Error) { +// Write to network. + +type writeOp struct { + bufOp +} + +func (o *writeOp) Submit() (errno int) { + var d uint32 + return syscall.WSASend(uint32(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 } @@ -380,41 +387,32 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) { if fd.sysfd == -1 { return 0, os.EINVAL } - // Submit send request. - var pckt ioPacket - pckt.c = fd.cw - pckt.w = newWSABuf(p) - var done uint32 - var e int - if fd.wdeadline_delta > 0 { - a := &arg{f: write, fd: fd, pckt: &pckt, done: &done, c: make(chan int)} - ioChan <- a - e = <-a.c - } else { - e = syscall.WSASend(uint32(fd.sysfd), pckt.w, 1, &done, uint32(0), &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{"WSASend", fd.net, fd.laddr, os.Errno(e)} - } - // Wait for our request to complete. - r := waitPacket(fd, &pckt, 'w') - if r.errno != 0 { - err = &OpError{"WSASend", fd.net, fd.laddr, os.Errno(r.errno)} - } - n = int(r.qty) - return + 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(uint32(o.fd.sysfd), &o.buf, 1, &d, 0, o.sa, &o.o, nil) +} + +func (o *writeToOp) Name() string { + return "WSASendto" } -func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) { +func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error) { if fd == nil { return 0, os.EINVAL } - if len(p) == 0 { + if len(buf) == 0 { return 0, nil } fd.wio.Lock() @@ -424,34 +422,29 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) { if fd.sysfd == -1 { return 0, os.EINVAL } - // Submit send request. - var pckt ioPacket - pckt.c = fd.cw - pckt.w = newWSABuf(p) - var done uint32 - var e int - if fd.wdeadline_delta > 0 { - a := &arg{f: writeto, fd: fd, pckt: &pckt, done: &done, sa: &sa, c: make(chan int)} - ioChan <- a - e = <-a.c - } else { - e = syscall.WSASendto(uint32(fd.sysfd), pckt.w, 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 := waitPacket(fd, &pckt, 'w') - if r.errno != 0 { - err = &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(r.errno)} - } - n = int(r.qty) - return + 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 int + 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(uint32(o.fd.sysfd), uint32(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) { @@ -474,72 +467,40 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. // Associate our new socket with IOCP. onceStartServer.Do(startServer) - if _, e = syscall.CreateIoCompletionPort(int32(s), pollserver.iocp, 0, 0); e != 0 { + if _, e = syscall.CreateIoCompletionPort(int32(s), resultsrv.iocp, 0, 0); e != 0 { return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)} } // Submit accept request. - // Will use new unique channel here, because, unlike Read or Write, - // Accept is expected to be executed by many goroutines simultaniously. - var pckt ioPacket - pckt.c = make(chan *ioResult) - attrs, e := syscall.AcceptIOCP(fd.sysfd, s, &pckt.o) - 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: - closesocket(s) - return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(e)} - } - - // Wait for peer connection. - r := <-pckt.c - if r.errno != 0 { + var o acceptOp + o.Init(fd) + o.newsock = s + _, err = iosrv.ExecIO(&o, 0) + if err != nil { closesocket(s) - return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(r.errno)} + return nil, err } // Inherit properties of the listening socket. e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd) if e != 0 { closesocket(s) - return nil, &OpError{"Setsockopt", fd.net, fd.laddr, os.Errno(r.errno)} + return nil, err } // Get local and peer addr out of AcceptEx buffer. - lsa, rsa := syscall.GetAcceptIOCPSockaddrs(attrs) - - // Create our netFD and return it for further use. - laddr := toAddr(lsa) - raddr := toAddr(rsa) - - f := &netFD{ - sysfd: s, - family: fd.family, - proto: fd.proto, - cr: make(chan *ioResult, 1), - cw: make(chan *ioResult, 1), - net: fd.net, - laddr: laddr, - raddr: raddr, - } - runtime.SetFinalizer(f, (*netFD).Close) - return f, nil -} - -func closesocket(s int) (errno int) { - return syscall.Closesocket(int32(s)) + 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() + + return allocFD(s, fd.family, fd.proto, fd.net, toAddr(lsa), toAddr(rsa)), nil } -func init() { - var d syscall.WSAData - e := syscall.WSAStartup(uint32(0x101), &d) - if e != 0 { - initErr = os.NewSyscallError("WSAStartup", e) - } -} +// Not implemeted functions. func (fd *netFD) dup() (f *os.File, err os.Error) { // TODO: Implement this |