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 solaris 6 7 package net 8 9 import ( 10 "os" 11 "syscall" 12 ) 13 14 func dupSocket(f *os.File) (int, error) { 15 s, err := dupCloseOnExec(int(f.Fd())) 16 if err != nil { 17 return -1, err 18 } 19 if err := syscall.SetNonblock(s, true); err != nil { 20 closeFunc(s) 21 return -1, os.NewSyscallError("setnonblock", err) 22 } 23 return s, nil 24 } 25 26 func newFileFD(f *os.File) (*netFD, error) { 27 s, err := dupSocket(f) 28 if err != nil { 29 return nil, err 30 } 31 family := syscall.AF_UNSPEC 32 sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE) 33 if err != nil { 34 closeFunc(s) 35 return nil, os.NewSyscallError("getsockopt", err) 36 } 37 lsa, _ := syscall.Getsockname(s) 38 rsa, _ := syscall.Getpeername(s) 39 switch lsa.(type) { 40 case *syscall.SockaddrInet4: 41 family = syscall.AF_INET 42 case *syscall.SockaddrInet6: 43 family = syscall.AF_INET6 44 case *syscall.SockaddrUnix: 45 family = syscall.AF_UNIX 46 default: 47 closeFunc(s) 48 return nil, syscall.EPROTONOSUPPORT 49 } 50 fd, err := newFD(s, family, sotype, "") 51 if err != nil { 52 closeFunc(s) 53 return nil, err 54 } 55 laddr := fd.addrFunc()(lsa) 56 raddr := fd.addrFunc()(rsa) 57 fd.net = laddr.Network() 58 if err := fd.init(); err != nil { 59 fd.Close() 60 return nil, err 61 } 62 fd.setAddr(laddr, raddr) 63 return fd, nil 64 } 65 66 func fileConn(f *os.File) (Conn, error) { 67 fd, err := newFileFD(f) 68 if err != nil { 69 return nil, err 70 } 71 switch fd.laddr.(type) { 72 case *TCPAddr: 73 return newTCPConn(fd), nil 74 case *UDPAddr: 75 return newUDPConn(fd), nil 76 case *IPAddr: 77 return newIPConn(fd), nil 78 case *UnixAddr: 79 return newUnixConn(fd), nil 80 } 81 fd.Close() 82 return nil, syscall.EINVAL 83 } 84 85 func fileListener(f *os.File) (Listener, error) { 86 fd, err := newFileFD(f) 87 if err != nil { 88 return nil, err 89 } 90 switch laddr := fd.laddr.(type) { 91 case *TCPAddr: 92 return &TCPListener{fd}, nil 93 case *UnixAddr: 94 return &UnixListener{fd, laddr.Name}, nil 95 } 96 fd.Close() 97 return nil, syscall.EINVAL 98 } 99 100 func filePacketConn(f *os.File) (PacketConn, error) { 101 fd, err := newFileFD(f) 102 if err != nil { 103 return nil, err 104 } 105 switch fd.laddr.(type) { 106 case *UDPAddr: 107 return newUDPConn(fd), nil 108 case *IPAddr: 109 return newIPConn(fd), nil 110 case *UnixAddr: 111 return newUnixConn(fd), nil 112 } 113 fd.Close() 114 return nil, syscall.EINVAL 115 } 116