iprawsock_posix.go 6.77 KB
Newer Older
Fazlul Shahriar's avatar
Fazlul Shahriar committed
1 2 3 4
// Copyright 2010 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 freebsd linux netbsd openbsd windows
6

Fazlul Shahriar's avatar
Fazlul Shahriar committed
7 8 9 10 11
// (Raw) IP sockets

package net

import (
12
	"errors"
Fazlul Shahriar's avatar
Fazlul Shahriar committed
13 14
	"os"
	"syscall"
15
	"time"
Fazlul Shahriar's avatar
Fazlul Shahriar committed
16 17 18 19 20 21 22 23 24 25 26 27 28
)

func sockaddrToIP(sa syscall.Sockaddr) Addr {
	switch sa := sa.(type) {
	case *syscall.SockaddrInet4:
		return &IPAddr{sa.Addr[0:]}
	case *syscall.SockaddrInet6:
		return &IPAddr{sa.Addr[0:]}
	}
	return nil
}

func (a *IPAddr) family() int {
29
	if a == nil || len(a.IP) <= IPv4len {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
30 31 32 33 34 35 36 37
		return syscall.AF_INET
	}
	if a.IP.To4() != nil {
		return syscall.AF_INET
	}
	return syscall.AF_INET6
}

38
func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
	return ipToSockaddr(family, a.IP, 0)
}

func (a *IPAddr) toAddr() sockaddr {
	if a == nil { // nil *IPAddr
		return nil // nil interface
	}
	return a
}

// IPConn is the implementation of the Conn and PacketConn
// interfaces for IP network connections.
type IPConn struct {
	fd *netFD
}

func newIPConn(fd *netFD) *IPConn { return &IPConn{fd} }

func (c *IPConn) ok() bool { return c != nil && c.fd != nil }

// Implementation of the Conn interface - see Conn for documentation.

// Read implements the net.Conn Read method.
62
func (c *IPConn) Read(b []byte) (n int, err error) {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
63 64 65 66 67
	n, _, err = c.ReadFrom(b)
	return
}

// Write implements the net.Conn Write method.
68
func (c *IPConn) Write(b []byte) (n int, err error) {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
69 70 71 72 73 74 75
	if !c.ok() {
		return 0, os.EINVAL
	}
	return c.fd.Write(b)
}

// Close closes the IP connection.
76
func (c *IPConn) Close() error {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	if !c.ok() {
		return os.EINVAL
	}
	err := c.fd.Close()
	c.fd = nil
	return err
}

// LocalAddr returns the local network address.
func (c *IPConn) LocalAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.laddr
}

// RemoteAddr returns the remote network address, a *IPAddr.
func (c *IPConn) RemoteAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.raddr
}

101 102
// SetDeadline implements the net.Conn SetDeadline method.
func (c *IPConn) SetDeadline(t time.Time) error {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
103 104 105
	if !c.ok() {
		return os.EINVAL
	}
106
	return setDeadline(c.fd, t)
Fazlul Shahriar's avatar
Fazlul Shahriar committed
107 108
}

109 110
// SetReadDeadline implements the net.Conn SetReadDeadline method.
func (c *IPConn) SetReadDeadline(t time.Time) error {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
111 112 113
	if !c.ok() {
		return os.EINVAL
	}
114
	return setReadDeadline(c.fd, t)
Fazlul Shahriar's avatar
Fazlul Shahriar committed
115 116
}

117 118
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
func (c *IPConn) SetWriteDeadline(t time.Time) error {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
119 120 121
	if !c.ok() {
		return os.EINVAL
	}
122
	return setWriteDeadline(c.fd, t)
Fazlul Shahriar's avatar
Fazlul Shahriar committed
123 124 125 126
}

// SetReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
127
func (c *IPConn) SetReadBuffer(bytes int) error {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
128 129 130 131 132 133 134 135
	if !c.ok() {
		return os.EINVAL
	}
	return setReadBuffer(c.fd, bytes)
}

// SetWriteBuffer sets the size of the operating system's
// transmit buffer associated with the connection.
136
func (c *IPConn) SetWriteBuffer(bytes int) error {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
137 138 139 140 141 142 143 144 145 146 147 148 149
	if !c.ok() {
		return os.EINVAL
	}
	return setWriteBuffer(c.fd, bytes)
}

// IP-specific methods.

// ReadFromIP reads a IP packet from c, copying the payload into b.
// It returns the number of bytes copied into b and the return address
// that was on the packet.
//
// ReadFromIP can be made to time out and return an error with
150 151
// Timeout() == true after a fixed time limit; see SetDeadline and
// SetReadDeadline.
152
func (c *IPConn) ReadFromIP(b []byte) (n int, addr *IPAddr, err error) {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
153 154 155 156 157 158 159 160 161
	if !c.ok() {
		return 0, nil, os.EINVAL
	}
	// TODO(cw,rsc): consider using readv if we know the family
	// type to avoid the header trim/copy
	n, sa, err := c.fd.ReadFrom(b)
	switch sa := sa.(type) {
	case *syscall.SockaddrInet4:
		addr = &IPAddr{sa.Addr[0:]}
162
		if len(b) >= IPv4len { // discard ipv4 header
Fazlul Shahriar's avatar
Fazlul Shahriar committed
163 164 165 166 167 168 169 170 171 172 173
			hsize := (int(b[0]) & 0xf) * 4
			copy(b, b[hsize:])
			n -= hsize
		}
	case *syscall.SockaddrInet6:
		addr = &IPAddr{sa.Addr[0:]}
	}
	return
}

// ReadFrom implements the net.PacketConn ReadFrom method.
174
func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
175 176 177 178 179 180 181 182 183 184 185
	if !c.ok() {
		return 0, nil, os.EINVAL
	}
	n, uaddr, err := c.ReadFromIP(b)
	return n, uaddr.toAddr(), err
}

// WriteToIP writes a IP packet to addr via c, copying the payload from b.
//
// WriteToIP can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
186
// see SetDeadline and SetWriteDeadline.
Fazlul Shahriar's avatar
Fazlul Shahriar committed
187
// On packet-oriented connections, write timeouts are rare.
188
func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err error) {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
189 190 191 192 193
	if !c.ok() {
		return 0, os.EINVAL
	}
	sa, err1 := addr.sockaddr(c.fd.family)
	if err1 != nil {
194
		return 0, &OpError{Op: "write", Net: "ip", Addr: addr, Err: err1}
Fazlul Shahriar's avatar
Fazlul Shahriar committed
195 196 197 198 199
	}
	return c.fd.WriteTo(b, sa)
}

// WriteTo implements the net.PacketConn WriteTo method.
200
func (c *IPConn) WriteTo(b []byte, addr Addr) (n int, err error) {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
201 202 203 204 205 206 207 208 209 210
	if !c.ok() {
		return 0, os.EINVAL
	}
	a, ok := addr.(*IPAddr)
	if !ok {
		return 0, &OpError{"writeto", "ip", addr, os.EINVAL}
	}
	return c.WriteToIP(b, a)
}

211
func splitNetProto(netProto string) (net string, proto int, err error) {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
212 213
	i := last(netProto, ':')
	if i < 0 { // no colon
214
		return "", 0, errors.New("no IP protocol specified")
Fazlul Shahriar's avatar
Fazlul Shahriar committed
215 216 217 218 219
	}
	net = netProto[0:i]
	protostr := netProto[i+1:]
	proto, i, ok := dtoi(protostr, 0)
	if !ok || i != len(protostr) {
220 221 222
		proto, err = lookupProtocol(protostr)
		if err != nil {
			return "", 0, err
Fazlul Shahriar's avatar
Fazlul Shahriar committed
223 224
		}
	}
225
	return net, proto, nil
Fazlul Shahriar's avatar
Fazlul Shahriar committed
226 227
}

228 229
// DialIP connects to the remote address raddr on the network protocol netProto,
// which must be "ip", "ip4", or "ip6" followed by a colon and a protocol number or name.
230
func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err error) {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
	net, proto, err := splitNetProto(netProto)
	if err != nil {
		return
	}
	switch net {
	case "ip", "ip4", "ip6":
	default:
		return nil, UnknownNetworkError(net)
	}
	if raddr == nil {
		return nil, &OpError{"dial", "ip", nil, errMissingAddress}
	}
	fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
	if e != nil {
		return nil, e
	}
	return newIPConn(fd), nil
}

// ListenIP listens for incoming IP packets addressed to the
// local address laddr.  The returned connection c's ReadFrom
// and WriteTo methods can be used to receive and send IP
// packets with per-packet addressing.
254
func ListenIP(netProto string, laddr *IPAddr) (c *IPConn, err error) {
Fazlul Shahriar's avatar
Fazlul Shahriar committed
255 256 257 258 259 260 261 262 263
	net, proto, err := splitNetProto(netProto)
	if err != nil {
		return
	}
	switch net {
	case "ip", "ip4", "ip6":
	default:
		return nil, UnknownNetworkError(net)
	}
264
	fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "listen", sockaddrToIP)
Fazlul Shahriar's avatar
Fazlul Shahriar committed
265 266 267 268 269 270
	if e != nil {
		return nil, e
	}
	return newIPConn(fd), nil
}

Mikio Hara's avatar
Mikio Hara committed
271 272 273
// File returns a copy of the underlying os.File, set to blocking mode.
// It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c.
274
func (c *IPConn) File() (f *os.File, err error) { return c.fd.dup() }