github.com/akaros/go-akaros@v0.0.0-20181004170632-85005d477eab/src/net/udpsock_akaros.go (about)

     1  // Copyright 2009 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  	"errors"
     9  	"os"
    10  	"syscall"
    11  	"time"
    12  )
    13  
    14  // UDPConn is the implementation of the Conn and PacketConn interfaces
    15  // for UDP network connections.
    16  type UDPConn struct {
    17  	conn
    18  }
    19  
    20  func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
    21  
    22  // ReadFromUDP reads a UDP packet from c, copying the payload into b.
    23  // It returns the number of bytes copied into b and the return address
    24  // that was on the packet.
    25  //
    26  // ReadFromUDP can be made to time out and return an error with
    27  // Timeout() == true after a fixed time limit; see SetDeadline and
    28  // SetReadDeadline.
    29  func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
    30  	if !c.ok() || c.fd.data == nil {
    31  		return 0, nil, syscall.EINVAL
    32  	}
    33  	buf := make([]byte, udpHeaderSize+len(b))
    34  	// Akaros reads on the netFD directly, unlike Plan 9 which does a raw
    35  	// read on the data FD.  This might be due to our timeout code.
    36  	m, err := c.fd.Read(buf)
    37  	if err != nil {
    38  		return
    39  	}
    40  	if m < udpHeaderSize {
    41  		return 0, nil, errors.New("short read reading UDP header")
    42  	}
    43  	buf = buf[:m]
    44  
    45  	h, buf := unmarshalUDPHeader(buf)
    46  	n = copy(b, buf)
    47  	return n, &UDPAddr{IP: h.raddr, Port: int(h.rport)}, nil
    48  }
    49  
    50  // ReadFrom implements the PacketConn ReadFrom method.
    51  func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
    52  	if !c.ok() {
    53  		return 0, nil, syscall.EINVAL
    54  	}
    55  	return c.ReadFromUDP(b)
    56  }
    57  
    58  // ReadMsgUDP reads a packet from c, copying the payload into b and
    59  // the associated out-of-band data into oob.  It returns the number
    60  // of bytes copied into b, the number of bytes copied into oob, the
    61  // flags that were set on the packet and the source address of the
    62  // packet.
    63  func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
    64  	return 0, 0, 0, nil, syscall.EPLAN9
    65  }
    66  
    67  // WriteToUDP writes a UDP packet to addr via c, copying the payload
    68  // from b.
    69  //
    70  // WriteToUDP can be made to time out and return an error with
    71  // Timeout() == true after a fixed time limit; see SetDeadline and
    72  // SetWriteDeadline.  On packet-oriented connections, write timeouts
    73  // are rare.
    74  func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
    75  	if !c.ok() || c.fd.data == nil {
    76  		return 0, syscall.EINVAL
    77  	}
    78  	if addr == nil {
    79  		return 0, &OpError{Op: "write", Net: c.fd.dir, Addr: nil, Err: errMissingAddress}
    80  	}
    81  	h := new(udpHeader)
    82  	h.raddr = addr.IP.To16()
    83  	h.laddr = c.fd.laddr.(*UDPAddr).IP.To16()
    84  	h.ifcaddr = IPv6zero // ignored (receive only)
    85  	h.rport = uint16(addr.Port)
    86  	h.lport = uint16(c.fd.laddr.(*UDPAddr).Port)
    87  
    88  	buf := make([]byte, udpHeaderSize+len(b))
    89  	i := copy(buf, h.Bytes())
    90  	copy(buf[i:], b)
    91  	return c.fd.data.Write(buf)
    92  }
    93  
    94  // WriteTo implements the PacketConn WriteTo method.
    95  func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
    96  	if !c.ok() {
    97  		return 0, syscall.EINVAL
    98  	}
    99  	a, ok := addr.(*UDPAddr)
   100  	if !ok {
   101  		return 0, &OpError{"write", c.fd.dir, addr, syscall.EINVAL}
   102  	}
   103  	return c.WriteToUDP(b, a)
   104  }
   105  
   106  // WriteMsgUDP writes a packet to addr via c, copying the payload from
   107  // b and the associated out-of-band data from oob.  It returns the
   108  // number of payload and out-of-band bytes written.
   109  func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
   110  	return 0, 0, syscall.EPLAN9
   111  }
   112  
   113  // DialUDP connects to the remote address raddr on the network net,
   114  // which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is
   115  // used as the local address for the connection.
   116  func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
   117  	return dialUDP(net, laddr, raddr, noDeadline)
   118  }
   119  
   120  func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
   121  	if !deadline.IsZero() {
   122  		panic("net.dialUDP: deadline not implemented on Plan 9")
   123  	}
   124  	switch net {
   125  	case "udp", "udp4", "udp6":
   126  	default:
   127  		return nil, UnknownNetworkError(net)
   128  	}
   129  	if raddr == nil {
   130  		return nil, &OpError{"dial", net, nil, errMissingAddress}
   131  	}
   132  	fd, err := dialPlan9(net, laddr, raddr)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  	return newUDPConn(fd), nil
   137  }
   138  
   139  const udpHeaderSize = 16*3 + 2*2
   140  
   141  type udpHeader struct {
   142  	raddr, laddr, ifcaddr IP
   143  	rport, lport          uint16
   144  }
   145  
   146  func (h *udpHeader) Bytes() []byte {
   147  	b := make([]byte, udpHeaderSize)
   148  	i := 0
   149  	i += copy(b[i:i+16], h.raddr)
   150  	i += copy(b[i:i+16], h.laddr)
   151  	i += copy(b[i:i+16], h.ifcaddr)
   152  	b[i], b[i+1], i = byte(h.rport>>8), byte(h.rport), i+2
   153  	b[i], b[i+1], i = byte(h.lport>>8), byte(h.lport), i+2
   154  	return b
   155  }
   156  
   157  func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
   158  	h := new(udpHeader)
   159  	h.raddr, b = IP(b[:16]), b[16:]
   160  	h.laddr, b = IP(b[:16]), b[16:]
   161  	h.ifcaddr, b = IP(b[:16]), b[16:]
   162  	h.rport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
   163  	h.lport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
   164  	return h, b
   165  }
   166  
   167  // ListenUDP listens for incoming UDP packets addressed to the local
   168  // address laddr.  Net must be "udp", "udp4", or "udp6".  If laddr has
   169  // a port of 0, ListenUDP will choose an available port.
   170  // The LocalAddr method of the returned UDPConn can be used to
   171  // discover the port.  The returned connection's ReadFrom and WriteTo
   172  // methods can be used to receive and send UDP packets with per-packet
   173  // addressing.
   174  func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
   175  	switch net {
   176  	case "udp", "udp4", "udp6":
   177  	default:
   178  		return nil, UnknownNetworkError(net)
   179  	}
   180  	if laddr == nil {
   181  		laddr = &UDPAddr{}
   182  	}
   183  	l, err := listenPlan9(net, laddr)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	_, err = l.ctl.WriteString("headers")
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  	fd, err := l.netFD()
   196  	return newUDPConn(fd), err
   197  }
   198  
   199  // ListenMulticastUDP listens for incoming multicast UDP packets
   200  // addressed to the group address gaddr on ifi, which specifies the
   201  // interface to join.  ListenMulticastUDP uses default multicast
   202  // interface if ifi is nil.
   203  func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
   204  	return nil, syscall.EPLAN9
   205  }