src/pkg/net/iprawsock_posix.go - The Go Programming Language

Golang

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() }