| Index: src/net/file_windows.go |
| =================================================================== |
| --- a/src/net/file_windows.go |
| +++ b/src/net/file_windows.go |
| @@ -9,13 +9,106 @@ |
| "syscall" |
| ) |
| +func dupCloseOnExec(fd int) (syscall.Handle, error) { |
| + var h syscall.Handle |
| + p, _ := syscall.GetCurrentProcess() |
| + err := syscall.DuplicateHandle(p, syscall.Handle(fd), p, &h, 0, false, syscall.DUPLICATE_SAME_ACCESS) |
| + if err != nil { |
| + return 0, err |
| + } |
| + return h, nil |
| +} |
| + |
| +func newFileFD(f *os.File) (*netFD, error) { |
| + fd, err := dupCloseOnExec(int(f.Fd())) |
| + if err != nil { |
| + return nil, os.NewSyscallError("dup", err) |
| + } |
| + |
| + if err = syscall.SetNonblock(fd, true); err != nil { |
| + closesocket(fd) |
| + return nil, err |
| + } |
| + |
| + sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE) |
| + if err != nil { |
| + closesocket(fd) |
| + return nil, os.NewSyscallError("getsockopt", err) |
| + } |
| + lsa, err := syscall.Getsockname(fd) |
| + if err != nil { |
| + return nil, os.NewSyscallError("getsockname", err) |
| + } |
| + |
| + family := syscall.AF_UNSPEC |
| + toAddr := sockaddrToTCP |
| + switch lsa.(type) { |
| + default: |
| + closesocket(fd) |
| + return nil, syscall.EINVAL |
| + case *syscall.SockaddrInet4: |
| + family = syscall.AF_INET |
| + if sotype == syscall.SOCK_DGRAM { |
| + toAddr = sockaddrToUDP |
| + } else if sotype == syscall.SOCK_RAW { |
| + toAddr = sockaddrToIP |
| + } |
| + case *syscall.SockaddrInet6: |
| + family = syscall.AF_INET6 |
| + if sotype == syscall.SOCK_DGRAM { |
| + toAddr = sockaddrToUDP |
| + } else if sotype == syscall.SOCK_RAW { |
| + toAddr = sockaddrToIP |
| + } |
| + case *syscall.SockaddrUnix: |
| + return nil, os.NewSyscallError("UnixListener", syscall.EWINDOWS) |
| + } |
| + laddr := toAddr(lsa) |
| + rsa, _ := syscall.Getpeername(fd) |
| + raddr := toAddr(rsa) |
| + |
| + netfd, err := newFD(fd, family, sotype, laddr.Network()) |
| + if err != nil { |
| + closesocket(fd) |
| + return nil, err |
| + } |
| + // fd is not handled yet |
| + if err := netfd.init(); err != nil { |
| + // handle invalid parameter. When passing same handle to |
| + // CreateIoCompletionPort twice, it returns ERROR_INVALID_PARAMETER(87). |
| + // Ignoring this here because when passing handle into this function |
| + // from external process, Or create socket manually and pass to here, |
| + // this init() should work gracefully. |
| + if errno, ok := err.(syscall.Errno); ok && int(errno) != -87 { |
| + netfd.Close() |
| + return nil, err |
| + } |
| + } |
| + netfd.setAddr(laddr, raddr) |
| + return netfd, nil |
| +} |
| + |
| // FileConn returns a copy of the network connection corresponding to |
| // the open file f. It is the caller's responsibility to close f when |
| // finished. Closing c does not affect f, and closing f does not |
| // affect c. |
| func FileConn(f *os.File) (c Conn, err error) { |
| - // TODO: Implement this |
| - return nil, os.NewSyscallError("FileConn", syscall.EWINDOWS) |
| + fd, err := newFileFD(f) |
| + if err != nil { |
| + return nil, err |
| + } |
| + switch fd.laddr.(type) { |
| + case *TCPAddr: |
| + return newTCPConn(fd), nil |
| + case *UDPAddr: |
| + return newUDPConn(fd), nil |
| + case *IPAddr: |
| + return newIPConn(fd), nil |
| + case *UnixAddr: |
| + return nil, os.NewSyscallError("FileConn", syscall.EWINDOWS) |
| + } |
| + fd.Close() |
| + return nil, syscall.EINVAL |
| } |
| // FileListener returns a copy of the network listener corresponding |
| @@ -23,8 +116,18 @@ |
| // when finished. Closing l does not affect f, and closing f does not |
| // affect l. |
| func FileListener(f *os.File) (l Listener, err error) { |
| - // TODO: Implement this |
| - return nil, os.NewSyscallError("FileListener", syscall.EWINDOWS) |
| + fd, err := newFileFD(f) |
| + if err != nil { |
| + return nil, err |
| + } |
| + switch fd.laddr.(type) { |
| + case *TCPAddr: |
| + return &TCPListener{fd}, nil |
| + case *UnixAddr: |
| + return nil, os.NewSyscallError("UnixListener", syscall.EWINDOWS) |
| + } |
| + fd.Close() |
| + return nil, syscall.EINVAL |
| } |
| // FilePacketConn returns a copy of the packet network connection |