github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/net/file_unix.go (about) 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 dragonfly 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 := dupCloseOnExec(int(f.Fd())) 16 if err != nil { 17 return nil, os.NewSyscallError("dup", err) 18 } 19 20 if err = syscall.SetNonblock(fd, true); err != nil { 21 closesocket(fd) 22 return nil, err 23 } 24 25 sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE) 26 if err != nil { 27 closesocket(fd) 28 return nil, os.NewSyscallError("getsockopt", err) 29 } 30 31 family := syscall.AF_UNSPEC 32 toAddr := sockaddrToTCP 33 lsa, _ := syscall.Getsockname(fd) 34 switch lsa.(type) { 35 default: 36 closesocket(fd) 37 return nil, syscall.EINVAL 38 case *syscall.SockaddrInet4: 39 family = syscall.AF_INET 40 if sotype == syscall.SOCK_DGRAM { 41 toAddr = sockaddrToUDP 42 } else if sotype == syscall.SOCK_RAW { 43 toAddr = sockaddrToIP 44 } 45 case *syscall.SockaddrInet6: 46 family = syscall.AF_INET6 47 if sotype == syscall.SOCK_DGRAM { 48 toAddr = sockaddrToUDP 49 } else if sotype == syscall.SOCK_RAW { 50 toAddr = sockaddrToIP 51 } 52 case *syscall.SockaddrUnix: 53 family = syscall.AF_UNIX 54 toAddr = sockaddrToUnix 55 if sotype == syscall.SOCK_DGRAM { 56 toAddr = sockaddrToUnixgram 57 } else if sotype == syscall.SOCK_SEQPACKET { 58 toAddr = sockaddrToUnixpacket 59 } 60 } 61 laddr := toAddr(lsa) 62 rsa, _ := syscall.Getpeername(fd) 63 raddr := toAddr(rsa) 64 65 netfd, err := newFD(fd, family, sotype, laddr.Network()) 66 if err != nil { 67 closesocket(fd) 68 return nil, err 69 } 70 if err := netfd.init(); err != nil { 71 netfd.Close() 72 return nil, err 73 } 74 netfd.setAddr(laddr, raddr) 75 return netfd, nil 76 } 77 78 // FileConn returns a copy of the network connection corresponding to 79 // the open file f. It is the caller's responsibility to close f when 80 // finished. Closing c does not affect f, and closing f does not 81 // affect c. 82 func FileConn(f *os.File) (c Conn, err error) { 83 fd, err := newFileFD(f) 84 if err != nil { 85 return nil, err 86 } 87 switch fd.laddr.(type) { 88 case *TCPAddr: 89 return newTCPConn(fd), nil 90 case *UDPAddr: 91 return newUDPConn(fd), nil 92 case *IPAddr: 93 return newIPConn(fd), nil 94 case *UnixAddr: 95 return newUnixConn(fd), nil 96 } 97 fd.Close() 98 return nil, syscall.EINVAL 99 } 100 101 // FileListener returns a copy of the network listener corresponding 102 // to the open file f. It is the caller's responsibility to close l 103 // when finished. Closing l does not affect f, and closing f does not 104 // affect l. 105 func FileListener(f *os.File) (l Listener, err error) { 106 fd, err := newFileFD(f) 107 if err != nil { 108 return nil, err 109 } 110 switch laddr := fd.laddr.(type) { 111 case *TCPAddr: 112 return &TCPListener{fd}, nil 113 case *UnixAddr: 114 return &UnixListener{fd, laddr.Name}, nil 115 } 116 fd.Close() 117 return nil, syscall.EINVAL 118 } 119 120 // FilePacketConn returns a copy of the packet network connection 121 // corresponding to the open file f. It is the caller's 122 // responsibility to close f when finished. Closing c does not affect 123 // f, and closing f does not affect c. 124 func FilePacketConn(f *os.File) (c PacketConn, err error) { 125 fd, err := newFileFD(f) 126 if err != nil { 127 return nil, err 128 } 129 switch fd.laddr.(type) { 130 case *UDPAddr: 131 return newUDPConn(fd), nil 132 case *UnixAddr: 133 return newUnixConn(fd), nil 134 } 135 fd.Close() 136 return nil, syscall.EINVAL 137 }