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