file_unix.go 3.38 KB
Newer Older
1 2 3 4
// 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.

5
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
6

7 8 9 10 11 12 13
package net

import (
	"os"
	"syscall"
)

14
func newFileFD(f *os.File) (*netFD, error) {
15
	fd, err := dupCloseOnExec(int(f.Fd()))
16 17
	if err != nil {
		return nil, os.NewSyscallError("dup", err)
18
	}
19

20 21 22 23
	if err = syscall.SetNonblock(fd, true); err != nil {
		closesocket(fd)
		return nil, err
	}
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 34
	lsa, _ := syscall.Getsockname(fd)
	switch lsa.(type) {
35 36
	default:
		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 44 45
			toAddr = sockaddrToIP
		}
	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 51 52
			toAddr = sockaddrToIP
		}
	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 59 60
			toAddr = sockaddrToUnixpacket
		}
	}
61 62 63
	laddr := toAddr(lsa)
	rsa, _ := syscall.Getpeername(fd)
	raddr := toAddr(rsa)
64

65
	netfd, err := newFD(fd, family, sotype, laddr.Network())
66
	if err != nil {
67
		closesocket(fd)
68 69
		return nil, err
	}
70 71 72 73
	if err := netfd.init(); err != nil {
		netfd.Close()
		return nil, err
	}
74 75
	netfd.setAddr(laddr, raddr)
	return netfd, nil
76 77 78 79 80 81
}

// 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.
82
func FileConn(f *os.File) (c Conn, err error) {
83 84 85 86 87 88 89 90 91 92 93
	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
94 95
	case *UnixAddr:
		return newUnixConn(fd), nil
96 97
	}
	fd.Close()
98
	return nil, syscall.EINVAL
99 100 101 102
}

// FileListener returns a copy of the network listener corresponding
// to the open file f.  It is the caller's responsibility to close l
103 104
// when finished.  Closing l does not affect f, and closing f does not
// affect l.
105
func FileListener(f *os.File) (l Listener, err error) {
106 107 108 109 110 111 112 113 114 115 116
	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()
117
	return nil, syscall.EINVAL
118 119 120 121 122 123
}

// 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.
124
func FilePacketConn(f *os.File) (c PacketConn, err error) {
125 126 127 128 129 130 131
	fd, err := newFileFD(f)
	if err != nil {
		return nil, err
	}
	switch fd.laddr.(type) {
	case *UDPAddr:
		return newUDPConn(fd), nil
132 133
	case *IPAddr:
		return newIPConn(fd), nil
134 135 136 137
	case *UnixAddr:
		return newUnixConn(fd), nil
	}
	fd.Close()
138
	return nil, syscall.EINVAL
139
}