github.com/ActiveState/go@v0.0.0-20170614201249-0b81c023a722/src/net/iprawsock.go (about)

     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  package net
     6  
     7  import (
     8  	"context"
     9  	"syscall"
    10  )
    11  
    12  // BUG(mikio): On every POSIX platform, reads from the "ip4" network
    13  // using the ReadFrom or ReadFromIP method might not return a complete
    14  // IPv4 packet, including its header, even if there is space
    15  // available. This can occur even in cases where Read or ReadMsgIP
    16  // could return a complete packet. For this reason, it is recommended
    17  // that you do not use these methods if it is important to receive a
    18  // full packet.
    19  //
    20  // The Go 1 compatibility guidelines make it impossible for us to
    21  // change the behavior of these methods; use Read or ReadMsgIP
    22  // instead.
    23  
    24  // BUG(mikio): On NaCl, Plan 9 and Windows, the ReadMsgIP and
    25  // WriteMsgIP methods of IPConn are not implemented.
    26  
    27  // BUG(mikio): On Windows, the File method of IPConn is not
    28  // implemented.
    29  
    30  // IPAddr represents the address of an IP end point.
    31  type IPAddr struct {
    32  	IP   IP
    33  	Zone string // IPv6 scoped addressing zone
    34  }
    35  
    36  // Network returns the address's network name, "ip".
    37  func (a *IPAddr) Network() string { return "ip" }
    38  
    39  func (a *IPAddr) String() string {
    40  	if a == nil {
    41  		return "<nil>"
    42  	}
    43  	ip := ipEmptyString(a.IP)
    44  	if a.Zone != "" {
    45  		return ip + "%" + a.Zone
    46  	}
    47  	return ip
    48  }
    49  
    50  func (a *IPAddr) isWildcard() bool {
    51  	if a == nil || a.IP == nil {
    52  		return true
    53  	}
    54  	return a.IP.IsUnspecified()
    55  }
    56  
    57  func (a *IPAddr) opAddr() Addr {
    58  	if a == nil {
    59  		return nil
    60  	}
    61  	return a
    62  }
    63  
    64  // ResolveIPAddr parses addr as an IP address of the form "host" or
    65  // "ipv6-host%zone" and resolves the domain name on the network net,
    66  // which must be "ip", "ip4" or "ip6".
    67  //
    68  // Resolving a hostname is not recommended because this returns at most
    69  // one of its IP addresses.
    70  func ResolveIPAddr(net, addr string) (*IPAddr, error) {
    71  	if net == "" { // a hint wildcard for Go 1.0 undocumented behavior
    72  		net = "ip"
    73  	}
    74  	afnet, _, err := parseNetwork(context.Background(), net, false)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	switch afnet {
    79  	case "ip", "ip4", "ip6":
    80  	default:
    81  		return nil, UnknownNetworkError(net)
    82  	}
    83  	addrs, err := DefaultResolver.internetAddrList(context.Background(), afnet, addr)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  	return addrs.first(isIPv4).(*IPAddr), nil
    88  }
    89  
    90  // IPConn is the implementation of the Conn and PacketConn interfaces
    91  // for IP network connections.
    92  type IPConn struct {
    93  	conn
    94  }
    95  
    96  // SyscallConn returns a raw network connection.
    97  // This implements the syscall.Conn interface.
    98  func (c *IPConn) SyscallConn() (syscall.RawConn, error) {
    99  	if !c.ok() {
   100  		return nil, syscall.EINVAL
   101  	}
   102  	return newRawConn(c.fd)
   103  }
   104  
   105  // ReadFromIP reads an IP packet from c, copying the payload into b.
   106  // It returns the number of bytes copied into b and the return address
   107  // that was on the packet.
   108  //
   109  // ReadFromIP can be made to time out and return an error with
   110  // Timeout() == true after a fixed time limit; see SetDeadline and
   111  // SetReadDeadline.
   112  func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
   113  	if !c.ok() {
   114  		return 0, nil, syscall.EINVAL
   115  	}
   116  	n, addr, err := c.readFrom(b)
   117  	if err != nil {
   118  		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   119  	}
   120  	return n, addr, err
   121  }
   122  
   123  // ReadFrom implements the PacketConn ReadFrom method.
   124  func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
   125  	if !c.ok() {
   126  		return 0, nil, syscall.EINVAL
   127  	}
   128  	n, addr, err := c.readFrom(b)
   129  	if err != nil {
   130  		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   131  	}
   132  	if addr == nil {
   133  		return n, nil, err
   134  	}
   135  	return n, addr, err
   136  }
   137  
   138  // ReadMsgIP reads a packet from c, copying the payload into b and the
   139  // associated out-of-band data into oob. It returns the number of
   140  // bytes copied into b, the number of bytes copied into oob, the flags
   141  // that were set on the packet and the source address of the packet.
   142  func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
   143  	if !c.ok() {
   144  		return 0, 0, 0, nil, syscall.EINVAL
   145  	}
   146  	n, oobn, flags, addr, err = c.readMsg(b, oob)
   147  	if err != nil {
   148  		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   149  	}
   150  	return
   151  }
   152  
   153  // WriteToIP writes an IP packet to addr via c, copying the payload
   154  // from b.
   155  //
   156  // WriteToIP can be made to time out and return an error with
   157  // Timeout() == true after a fixed time limit; see SetDeadline and
   158  // SetWriteDeadline. On packet-oriented connections, write timeouts
   159  // are rare.
   160  func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
   161  	if !c.ok() {
   162  		return 0, syscall.EINVAL
   163  	}
   164  	n, err := c.writeTo(b, addr)
   165  	if err != nil {
   166  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
   167  	}
   168  	return n, err
   169  }
   170  
   171  // WriteTo implements the PacketConn WriteTo method.
   172  func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
   173  	if !c.ok() {
   174  		return 0, syscall.EINVAL
   175  	}
   176  	a, ok := addr.(*IPAddr)
   177  	if !ok {
   178  		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
   179  	}
   180  	n, err := c.writeTo(b, a)
   181  	if err != nil {
   182  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
   183  	}
   184  	return n, err
   185  }
   186  
   187  // WriteMsgIP writes a packet to addr via c, copying the payload from
   188  // b and the associated out-of-band data from oob. It returns the
   189  // number of payload and out-of-band bytes written.
   190  func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
   191  	if !c.ok() {
   192  		return 0, 0, syscall.EINVAL
   193  	}
   194  	n, oobn, err = c.writeMsg(b, oob, addr)
   195  	if err != nil {
   196  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
   197  	}
   198  	return
   199  }
   200  
   201  func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} }
   202  
   203  // DialIP connects to the remote address raddr on the network protocol
   204  // netProto, which must be "ip", "ip4", or "ip6" followed by a colon
   205  // and a protocol number or name.
   206  func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
   207  	c, err := dialIP(context.Background(), netProto, laddr, raddr)
   208  	if err != nil {
   209  		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
   210  	}
   211  	return c, nil
   212  }
   213  
   214  // ListenIP listens for incoming IP packets addressed to the local
   215  // address laddr. The returned connection's ReadFrom and WriteTo
   216  // methods can be used to receive and send IP packets with per-packet
   217  // addressing.
   218  func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
   219  	c, err := listenIP(context.Background(), netProto, laddr)
   220  	if err != nil {
   221  		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
   222  	}
   223  	return c, nil
   224  }