Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 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 | |
Mikio Hara | 484cc67 | 2014-09-18 19:17:55 +0900 | [diff] [blame] | 5 | // +build darwin dragonfly freebsd linux netbsd openbsd solaris |
Russ Cox | 2715956 | 2011-09-15 16:48:57 -0400 | [diff] [blame] | 6 | |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 7 | package net |
| 8 | |
| 9 | import ( |
| 10 | "os" |
| 11 | "syscall" |
| 12 | ) |
| 13 | |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 14 | func newFileFD(f *os.File) (*netFD, error) { |
Brad Fitzpatrick | 37feacf | 2013-08-05 15:43:45 -0700 | [diff] [blame] | 15 | fd, err := dupCloseOnExec(int(f.Fd())) |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 16 | if err != nil { |
| 17 | return nil, os.NewSyscallError("dup", err) |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 18 | } |
Brad Fitzpatrick | 37feacf | 2013-08-05 15:43:45 -0700 | [diff] [blame] | 19 | |
Ian Lance Taylor | 31f58dc | 2013-01-28 08:54:15 -0800 | [diff] [blame] | 20 | if err = syscall.SetNonblock(fd, true); err != nil { |
| 21 | closesocket(fd) |
| 22 | return nil, err |
| 23 | } |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 24 | |
Mikio Hara | d380a97 | 2012-07-22 01:48:15 +0900 | [diff] [blame] | 25 | sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE) |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 26 | if err != nil { |
Mikio Hara | d380a97 | 2012-07-22 01:48:15 +0900 | [diff] [blame] | 27 | closesocket(fd) |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 28 | return nil, os.NewSyscallError("getsockopt", err) |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 29 | } |
| 30 | |
Albert Strasheim | 51057bda3 | 2011-10-12 13:36:45 -0400 | [diff] [blame] | 31 | family := syscall.AF_UNSPEC |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 32 | toAddr := sockaddrToTCP |
Mikio Hara | 6cf77f2 | 2012-08-23 20:54:00 +0900 | [diff] [blame] | 33 | lsa, _ := syscall.Getsockname(fd) |
| 34 | switch lsa.(type) { |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 35 | default: |
| 36 | closesocket(fd) |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 37 | return nil, syscall.EINVAL |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 38 | case *syscall.SockaddrInet4: |
Albert Strasheim | 51057bda3 | 2011-10-12 13:36:45 -0400 | [diff] [blame] | 39 | family = syscall.AF_INET |
Mikio Hara | d380a97 | 2012-07-22 01:48:15 +0900 | [diff] [blame] | 40 | if sotype == syscall.SOCK_DGRAM { |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 41 | toAddr = sockaddrToUDP |
Mikio Hara | d380a97 | 2012-07-22 01:48:15 +0900 | [diff] [blame] | 42 | } else if sotype == syscall.SOCK_RAW { |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 43 | toAddr = sockaddrToIP |
| 44 | } |
| 45 | case *syscall.SockaddrInet6: |
Albert Strasheim | 51057bda3 | 2011-10-12 13:36:45 -0400 | [diff] [blame] | 46 | family = syscall.AF_INET6 |
Mikio Hara | d380a97 | 2012-07-22 01:48:15 +0900 | [diff] [blame] | 47 | if sotype == syscall.SOCK_DGRAM { |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 48 | toAddr = sockaddrToUDP |
Mikio Hara | d380a97 | 2012-07-22 01:48:15 +0900 | [diff] [blame] | 49 | } else if sotype == syscall.SOCK_RAW { |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 50 | toAddr = sockaddrToIP |
| 51 | } |
| 52 | case *syscall.SockaddrUnix: |
Albert Strasheim | 51057bda3 | 2011-10-12 13:36:45 -0400 | [diff] [blame] | 53 | family = syscall.AF_UNIX |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 54 | toAddr = sockaddrToUnix |
Mikio Hara | d380a97 | 2012-07-22 01:48:15 +0900 | [diff] [blame] | 55 | if sotype == syscall.SOCK_DGRAM { |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 56 | toAddr = sockaddrToUnixgram |
Mikio Hara | d380a97 | 2012-07-22 01:48:15 +0900 | [diff] [blame] | 57 | } else if sotype == syscall.SOCK_SEQPACKET { |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 58 | toAddr = sockaddrToUnixpacket |
| 59 | } |
| 60 | } |
Mikio Hara | 6cf77f2 | 2012-08-23 20:54:00 +0900 | [diff] [blame] | 61 | laddr := toAddr(lsa) |
Mikio Hara | e4389c0 | 2012-09-19 01:33:03 +0900 | [diff] [blame] | 62 | rsa, _ := syscall.Getpeername(fd) |
| 63 | raddr := toAddr(rsa) |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 64 | |
Mikio Hara | d380a97 | 2012-07-22 01:48:15 +0900 | [diff] [blame] | 65 | netfd, err := newFD(fd, family, sotype, laddr.Network()) |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 66 | if err != nil { |
Mikio Hara | d380a97 | 2012-07-22 01:48:15 +0900 | [diff] [blame] | 67 | closesocket(fd) |
Alexey Borzenkov | 2f45f72 | 2011-03-28 23:40:01 -0400 | [diff] [blame] | 68 | return nil, err |
| 69 | } |
Mikio Hara | 6a76bca36 | 2013-08-06 23:42:33 +0900 | [diff] [blame] | 70 | if err := netfd.init(); err != nil { |
| 71 | netfd.Close() |
| 72 | return nil, err |
| 73 | } |
Mikio Hara | e4389c0 | 2012-09-19 01:33:03 +0900 | [diff] [blame] | 74 | netfd.setAddr(laddr, raddr) |
Mikio Hara | 28397be | 2012-02-01 00:36:45 +0900 | [diff] [blame] | 75 | return netfd, nil |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | // FileConn returns a copy of the network connection corresponding to |
| 79 | // the open file f. It is the caller's responsibility to close f when |
| 80 | // finished. Closing c does not affect f, and closing f does not |
| 81 | // affect c. |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 82 | func FileConn(f *os.File) (c Conn, err error) { |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 83 | fd, err := newFileFD(f) |
| 84 | if err != nil { |
| 85 | return nil, err |
| 86 | } |
| 87 | switch fd.laddr.(type) { |
| 88 | case *TCPAddr: |
| 89 | return newTCPConn(fd), nil |
| 90 | case *UDPAddr: |
| 91 | return newUDPConn(fd), nil |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 92 | case *IPAddr: |
| 93 | return newIPConn(fd), nil |
Mikio Hara | 6cf77f2 | 2012-08-23 20:54:00 +0900 | [diff] [blame] | 94 | case *UnixAddr: |
| 95 | return newUnixConn(fd), nil |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 96 | } |
| 97 | fd.Close() |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 98 | return nil, syscall.EINVAL |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 99 | } |
| 100 | |
| 101 | // FileListener returns a copy of the network listener corresponding |
Mikio Hara | 14ad411 | 2012-05-30 01:42:36 +0900 | [diff] [blame] | 102 | // to the open file f. It is the caller's responsibility to close l |
Mikio Hara | 8c8ab05 | 2012-05-30 01:52:50 +0900 | [diff] [blame] | 103 | // when finished. Closing l does not affect f, and closing f does not |
| 104 | // affect l. |
Mikio Hara | 14ad411 | 2012-05-30 01:42:36 +0900 | [diff] [blame] | 105 | func FileListener(f *os.File) (l Listener, err error) { |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 106 | fd, err := newFileFD(f) |
| 107 | if err != nil { |
| 108 | return nil, err |
| 109 | } |
| 110 | switch laddr := fd.laddr.(type) { |
| 111 | case *TCPAddr: |
| 112 | return &TCPListener{fd}, nil |
| 113 | case *UnixAddr: |
| 114 | return &UnixListener{fd, laddr.Name}, nil |
| 115 | } |
| 116 | fd.Close() |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 117 | return nil, syscall.EINVAL |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | // FilePacketConn returns a copy of the packet network connection |
| 121 | // corresponding to the open file f. It is the caller's |
| 122 | // responsibility to close f when finished. Closing c does not affect |
| 123 | // f, and closing f does not affect c. |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 124 | func FilePacketConn(f *os.File) (c PacketConn, err error) { |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 125 | fd, err := newFileFD(f) |
| 126 | if err != nil { |
| 127 | return nil, err |
| 128 | } |
| 129 | switch fd.laddr.(type) { |
| 130 | case *UDPAddr: |
| 131 | return newUDPConn(fd), nil |
Mikio Hara | c88a671 | 2014-01-28 03:18:27 -0800 | [diff] [blame] | 132 | case *IPAddr: |
| 133 | return newIPConn(fd), nil |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 134 | case *UnixAddr: |
| 135 | return newUnixConn(fd), nil |
| 136 | } |
| 137 | fd.Close() |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 138 | return nil, syscall.EINVAL |
Albert Strasheim | e480b81 | 2011-03-25 14:42:25 -0400 | [diff] [blame] | 139 | } |