|  | // Copyright 2011 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. | 
|  |  | 
|  | // +build darwin freebsd linux netbsd openbsd | 
|  |  | 
|  | package net | 
|  |  | 
|  | import ( | 
|  | "os" | 
|  | "syscall" | 
|  | ) | 
|  |  | 
|  | func newFileFD(f *os.File) (*netFD, error) { | 
|  | syscall.ForkLock.RLock() | 
|  | fd, err := syscall.Dup(int(f.Fd())) | 
|  | if err != nil { | 
|  | syscall.ForkLock.RUnlock() | 
|  | return nil, os.NewSyscallError("dup", err) | 
|  | } | 
|  | syscall.CloseOnExec(fd) | 
|  | syscall.ForkLock.RUnlock() | 
|  |  | 
|  | sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE) | 
|  | if err != nil { | 
|  | closesocket(fd) | 
|  | return nil, os.NewSyscallError("getsockopt", err) | 
|  | } | 
|  |  | 
|  | family := syscall.AF_UNSPEC | 
|  | toAddr := sockaddrToTCP | 
|  | sa, _ := syscall.Getsockname(fd) | 
|  | switch sa.(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: | 
|  | family = syscall.AF_UNIX | 
|  | toAddr = sockaddrToUnix | 
|  | if sotype == syscall.SOCK_DGRAM { | 
|  | toAddr = sockaddrToUnixgram | 
|  | } else if sotype == syscall.SOCK_SEQPACKET { | 
|  | toAddr = sockaddrToUnixpacket | 
|  | } | 
|  | } | 
|  | laddr := toAddr(sa) | 
|  | sa, _ = syscall.Getpeername(fd) | 
|  | raddr := toAddr(sa) | 
|  |  | 
|  | netfd, err := newFD(fd, family, sotype, laddr.Network()) | 
|  | if err != nil { | 
|  | closesocket(fd) | 
|  | 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) { | 
|  | 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 *UnixAddr: | 
|  | return newUnixConn(fd), nil | 
|  | case *IPAddr: | 
|  | return newIPConn(fd), nil | 
|  | } | 
|  | fd.Close() | 
|  | return nil, syscall.EINVAL | 
|  | } | 
|  |  | 
|  | // FileListener returns a copy of the network listener corresponding | 
|  | // to the open file f.  It is the caller's responsibility to close l | 
|  | // when finished.  Closing l does not affect f, and closing f does not | 
|  | // affect l. | 
|  | func FileListener(f *os.File) (l Listener, err error) { | 
|  | fd, err := newFileFD(f) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | switch laddr := fd.laddr.(type) { | 
|  | case *TCPAddr: | 
|  | return &TCPListener{fd}, nil | 
|  | case *UnixAddr: | 
|  | return &UnixListener{fd, laddr.Name}, nil | 
|  | } | 
|  | fd.Close() | 
|  | return nil, syscall.EINVAL | 
|  | } | 
|  |  | 
|  | // FilePacketConn returns a copy of the packet 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 FilePacketConn(f *os.File) (c PacketConn, err error) { | 
|  | fd, err := newFileFD(f) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | switch fd.laddr.(type) { | 
|  | case *UDPAddr: | 
|  | return newUDPConn(fd), nil | 
|  | case *UnixAddr: | 
|  | return newUnixConn(fd), nil | 
|  | } | 
|  | fd.Close() | 
|  | return nil, syscall.EINVAL | 
|  | } |