Source file src/pkg/net/iprawsock_posix.go
1 // Copyright 2010 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 windows 6 7 // (Raw) IP sockets 8 9 package net 10 11 import ( 12 "os" 13 "syscall" 14 "time" 15 ) 16 17 func sockaddrToIP(sa syscall.Sockaddr) Addr { 18 switch sa := sa.(type) { 19 case *syscall.SockaddrInet4: 20 return &IPAddr{sa.Addr[0:]} 21 case *syscall.SockaddrInet6: 22 return &IPAddr{sa.Addr[0:]} 23 } 24 return nil 25 } 26 27 func (a *IPAddr) family() int { 28 if a == nil || len(a.IP) <= IPv4len { 29 return syscall.AF_INET 30 } 31 if a.IP.To4() != nil { 32 return syscall.AF_INET 33 } 34 return syscall.AF_INET6 35 } 36 37 func (a *IPAddr) isWildcard() bool { 38 if a == nil || a.IP == nil { 39 return true 40 } 41 return a.IP.IsUnspecified() 42 } 43 44 func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) { 45 return ipToSockaddr(family, a.IP, 0) 46 } 47 48 func (a *IPAddr) toAddr() sockaddr { 49 if a == nil { // nil *IPAddr 50 return nil // nil interface 51 } 52 return a 53 } 54 55 // IPConn is the implementation of the Conn and PacketConn 56 // interfaces for IP network connections. 57 type IPConn struct { 58 fd *netFD 59 } 60 61 func newIPConn(fd *netFD) *IPConn { return &IPConn{fd} } 62 63 func (c *IPConn) ok() bool { return c != nil && c.fd != nil } 64 65 // Implementation of the Conn interface - see Conn for documentation. 66 67 // Read implements the Conn Read method. 68 func (c *IPConn) Read(b []byte) (int, error) { 69 n, _, err := c.ReadFrom(b) 70 return n, err 71 } 72 73 // Write implements the Conn Write method. 74 func (c *IPConn) Write(b []byte) (int, error) { 75 if !c.ok() { 76 return 0, syscall.EINVAL 77 } 78 return c.fd.Write(b) 79 } 80 81 // Close closes the IP connection. 82 func (c *IPConn) Close() error { 83 if !c.ok() { 84 return syscall.EINVAL 85 } 86 return c.fd.Close() 87 } 88 89 // LocalAddr returns the local network address. 90 func (c *IPConn) LocalAddr() Addr { 91 if !c.ok() { 92 return nil 93 } 94 return c.fd.laddr 95 } 96 97 // RemoteAddr returns the remote network address, a *IPAddr. 98 func (c *IPConn) RemoteAddr() Addr { 99 if !c.ok() { 100 return nil 101 } 102 return c.fd.raddr 103 } 104 105 // SetDeadline implements the Conn SetDeadline method. 106 func (c *IPConn) SetDeadline(t time.Time) error { 107 if !c.ok() { 108 return syscall.EINVAL 109 } 110 return setDeadline(c.fd, t) 111 } 112 113 // SetReadDeadline implements the Conn SetReadDeadline method. 114 func (c *IPConn) SetReadDeadline(t time.Time) error { 115 if !c.ok() { 116 return syscall.EINVAL 117 } 118 return setReadDeadline(c.fd, t) 119 } 120 121 // SetWriteDeadline implements the Conn SetWriteDeadline method. 122 func (c *IPConn) SetWriteDeadline(t time.Time) error { 123 if !c.ok() { 124 return syscall.EINVAL 125 } 126 return setWriteDeadline(c.fd, t) 127 } 128 129 // SetReadBuffer sets the size of the operating system's 130 // receive buffer associated with the connection. 131 func (c *IPConn) SetReadBuffer(bytes int) error { 132 if !c.ok() { 133 return syscall.EINVAL 134 } 135 return setReadBuffer(c.fd, bytes) 136 } 137 138 // SetWriteBuffer sets the size of the operating system's 139 // transmit buffer associated with the connection. 140 func (c *IPConn) SetWriteBuffer(bytes int) error { 141 if !c.ok() { 142 return syscall.EINVAL 143 } 144 return setWriteBuffer(c.fd, bytes) 145 } 146 147 // IP-specific methods. 148 149 // ReadFromIP reads a IP packet from c, copying the payload into b. 150 // It returns the number of bytes copied into b and the return address 151 // that was on the packet. 152 // 153 // ReadFromIP can be made to time out and return an error with 154 // Timeout() == true after a fixed time limit; see SetDeadline and 155 // SetReadDeadline. 156 func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) { 157 if !c.ok() { 158 return 0, nil, syscall.EINVAL 159 } 160 // TODO(cw,rsc): consider using readv if we know the family 161 // type to avoid the header trim/copy 162 var addr *IPAddr 163 n, sa, err := c.fd.ReadFrom(b) 164 switch sa := sa.(type) { 165 case *syscall.SockaddrInet4: 166 addr = &IPAddr{sa.Addr[0:]} 167 if len(b) >= IPv4len { // discard ipv4 header 168 hsize := (int(b[0]) & 0xf) * 4 169 copy(b, b[hsize:]) 170 n -= hsize 171 } 172 case *syscall.SockaddrInet6: 173 addr = &IPAddr{sa.Addr[0:]} 174 } 175 return n, addr, err 176 } 177 178 // ReadFrom implements the PacketConn ReadFrom method. 179 func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) { 180 if !c.ok() { 181 return 0, nil, syscall.EINVAL 182 } 183 n, uaddr, err := c.ReadFromIP(b) 184 return n, uaddr.toAddr(), err 185 } 186 187 // WriteToIP writes a IP packet to addr via c, copying the payload from b. 188 // 189 // WriteToIP can be made to time out and return 190 // an error with Timeout() == true after a fixed time limit; 191 // see SetDeadline and SetWriteDeadline. 192 // On packet-oriented connections, write timeouts are rare. 193 func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) { 194 if !c.ok() { 195 return 0, syscall.EINVAL 196 } 197 sa, err := addr.sockaddr(c.fd.family) 198 if err != nil { 199 return 0, &OpError{"write", c.fd.net, addr, err} 200 } 201 return c.fd.WriteTo(b, sa) 202 } 203 204 // WriteTo implements the PacketConn WriteTo method. 205 func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) { 206 if !c.ok() { 207 return 0, syscall.EINVAL 208 } 209 a, ok := addr.(*IPAddr) 210 if !ok { 211 return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL} 212 } 213 return c.WriteToIP(b, a) 214 } 215 216 // DialIP connects to the remote address raddr on the network protocol netProto, 217 // which must be "ip", "ip4", or "ip6" followed by a colon and a protocol number or name. 218 func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) { 219 net, proto, err := parseDialNetwork(netProto) 220 if err != nil { 221 return nil, err 222 } 223 switch net { 224 case "ip", "ip4", "ip6": 225 default: 226 return nil, UnknownNetworkError(net) 227 } 228 if raddr == nil { 229 return nil, &OpError{"dial", netProto, nil, errMissingAddress} 230 } 231 fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_RAW, proto, "dial", sockaddrToIP) 232 if err != nil { 233 return nil, err 234 } 235 return newIPConn(fd), nil 236 } 237 238 // ListenIP listens for incoming IP packets addressed to the 239 // local address laddr. The returned connection c's ReadFrom 240 // and WriteTo methods can be used to receive and send IP 241 // packets with per-packet addressing. 242 func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) { 243 net, proto, err := parseDialNetwork(netProto) 244 if err != nil { 245 return nil, err 246 } 247 switch net { 248 case "ip", "ip4", "ip6": 249 default: 250 return nil, UnknownNetworkError(net) 251 } 252 fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "listen", sockaddrToIP) 253 if err != nil { 254 return nil, err 255 } 256 return newIPConn(fd), nil 257 } 258 259 // File returns a copy of the underlying os.File, set to blocking mode. 260 // It is the caller's responsibility to close f when finished. 261 // Closing c does not affect f, and closing f does not affect c. 262 func (c *IPConn) File() (f *os.File, err error) { return c.fd.dup() }