1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
// 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 dragonfly freebsd linux netbsd openbsd solaris
package net
import (
"os"
"syscall"
)
func newFileFD(f *os.File) (*netFD, error) {
fd, err := dupCloseOnExec(int(f.Fd()))
if err != nil {
return nil, os.NewSyscallError("dup", err)
}
if err = syscall.SetNonblock(fd, true); err != nil {
closesocket(fd)
return nil, err
}
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
lsa, _ := syscall.Getsockname(fd)
switch lsa.(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(lsa)
rsa, _ := syscall.Getpeername(fd)
raddr := toAddr(rsa)
netfd, err := newFD(fd, family, sotype, laddr.Network())
if err != nil {
closesocket(fd)
return nil, err
}
if err := netfd.init(); err != nil {
netfd.Close()
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 *IPAddr:
return newIPConn(fd), nil
case *UnixAddr:
return newUnixConn(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 *IPAddr:
return newIPConn(fd), nil
case *UnixAddr:
return newUnixConn(fd), nil
}
fd.Close()
return nil, syscall.EINVAL
}
|