Source file src/pkg/net/file.go
1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build darwin freebsd linux netbsd openbsd 6 7 package net 8 9 import ( 10 "os" 11 "syscall" 12 ) 13 14 func newFileFD(f *os.File) (*netFD, error) { 15 fd, err := syscall.Dup(int(f.Fd())) 16 if err != nil { 17 return nil, os.NewSyscallError("dup", err) 18 } 19 20 proto, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE) 21 if err != nil { 22 return nil, os.NewSyscallError("getsockopt", err) 23 } 24 25 family := syscall.AF_UNSPEC 26 toAddr := sockaddrToTCP 27 sa, _ := syscall.Getsockname(fd) 28 switch sa.(type) { 29 default: 30 closesocket(fd) 31 return nil, syscall.EINVAL 32 case *syscall.SockaddrInet4: 33 family = syscall.AF_INET 34 if proto == syscall.SOCK_DGRAM { 35 toAddr = sockaddrToUDP 36 } else if proto == syscall.SOCK_RAW { 37 toAddr = sockaddrToIP 38 } 39 case *syscall.SockaddrInet6: 40 family = syscall.AF_INET6 41 if proto == syscall.SOCK_DGRAM { 42 toAddr = sockaddrToUDP 43 } else if proto == syscall.SOCK_RAW { 44 toAddr = sockaddrToIP 45 } 46 case *syscall.SockaddrUnix: 47 family = syscall.AF_UNIX 48 toAddr = sockaddrToUnix 49 if proto == syscall.SOCK_DGRAM { 50 toAddr = sockaddrToUnixgram 51 } else if proto == syscall.SOCK_SEQPACKET { 52 toAddr = sockaddrToUnixpacket 53 } 54 } 55 laddr := toAddr(sa) 56 sa, _ = syscall.Getpeername(fd) 57 raddr := toAddr(sa) 58 59 netfd, err := newFD(fd, family, proto, laddr.Network()) 60 if err != nil { 61 return nil, err 62 } 63 netfd.setAddr(laddr, raddr) 64 return netfd, nil 65 } 66 67 // FileConn returns a copy of the network connection corresponding to 68 // the open file f. It is the caller's responsibility to close f when 69 // finished. Closing c does not affect f, and closing f does not 70 // affect c. 71 func FileConn(f *os.File) (c Conn, err error) { 72 fd, err := newFileFD(f) 73 if err != nil { 74 return nil, err 75 } 76 switch fd.laddr.(type) { 77 case *TCPAddr: 78 return newTCPConn(fd), nil 79 case *UDPAddr: 80 return newUDPConn(fd), nil 81 case *UnixAddr: 82 return newUnixConn(fd), nil 83 case *IPAddr: 84 return newIPConn(fd), nil 85 } 86 fd.Close() 87 return nil, syscall.EINVAL 88 } 89 90 // FileListener returns a copy of the network listener corresponding 91 // to the open file f. It is the caller's responsibility to close l 92 // when finished. Closing c does not affect l, and closing l does not 93 // affect c. 94 func FileListener(f *os.File) (l Listener, err error) { 95 fd, err := newFileFD(f) 96 if err != nil { 97 return nil, err 98 } 99 switch laddr := fd.laddr.(type) { 100 case *TCPAddr: 101 return &TCPListener{fd}, nil 102 case *UnixAddr: 103 return &UnixListener{fd, laddr.Name}, nil 104 } 105 fd.Close() 106 return nil, syscall.EINVAL 107 } 108 109 // FilePacketConn returns a copy of the packet network connection 110 // corresponding to the open file f. It is the caller's 111 // responsibility to close f when finished. Closing c does not affect 112 // f, and closing f does not affect c. 113 func FilePacketConn(f *os.File) (c PacketConn, err error) { 114 fd, err := newFileFD(f) 115 if err != nil { 116 return nil, err 117 } 118 switch fd.laddr.(type) { 119 case *UDPAddr: 120 return newUDPConn(fd), nil 121 case *UnixAddr: 122 return newUnixConn(fd), nil 123 } 124 fd.Close() 125 return nil, syscall.EINVAL 126 }