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