udpsock_plan9.mx raw

   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  	"context"
   9  	"errors"
  10  	"net/netip"
  11  	"os"
  12  	"syscall"
  13  )
  14  
  15  func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
  16  	buf := []byte{:udpHeaderSize+len(b)}
  17  	m, err := c.fd.Read(buf)
  18  	if err != nil {
  19  		return 0, nil, err
  20  	}
  21  	if m < udpHeaderSize {
  22  		return 0, nil, errors.New("short read reading UDP header")
  23  	}
  24  	buf = buf[:m]
  25  
  26  	h, buf := unmarshalUDPHeader(buf)
  27  	n := copy(b, buf)
  28  	*addr = UDPAddr{IP: h.raddr, Port: int(h.rport)}
  29  	return n, addr, nil
  30  }
  31  
  32  func (c *UDPConn) readFromAddrPort(b []byte) (int, netip.AddrPort, error) {
  33  	// TODO: optimize. The equivalent code on posix is alloc-free.
  34  	buf := []byte{:udpHeaderSize+len(b)}
  35  	m, err := c.fd.Read(buf)
  36  	if err != nil {
  37  		return 0, netip.AddrPort{}, err
  38  	}
  39  	if m < udpHeaderSize {
  40  		return 0, netip.AddrPort{}, errors.New("short read reading UDP header")
  41  	}
  42  	buf = buf[:m]
  43  
  44  	h, buf := unmarshalUDPHeader(buf)
  45  	n := copy(b, buf)
  46  	ip, _ := netip.AddrFromSlice(h.raddr)
  47  	addr := netip.AddrPortFrom(ip, h.rport)
  48  	return n, addr, nil
  49  }
  50  
  51  func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr netip.AddrPort, err error) {
  52  	return 0, 0, 0, netip.AddrPort{}, syscall.EPLAN9
  53  }
  54  
  55  func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
  56  	if addr == nil {
  57  		return 0, errMissingAddress
  58  	}
  59  	h := &udpHeader{}
  60  	h.raddr = addr.IP.To16()
  61  	h.laddr = c.fd.laddr.(*UDPAddr).IP.To16()
  62  	h.ifcaddr = IPv6zero // ignored (receive only)
  63  	h.rport = uint16(addr.Port)
  64  	h.lport = uint16(c.fd.laddr.(*UDPAddr).Port)
  65  
  66  	buf := []byte{:udpHeaderSize+len(b)}
  67  	i := copy(buf, h.Bytes())
  68  	copy(buf[i:], b)
  69  	if _, err := c.fd.Write(buf); err != nil {
  70  		return 0, err
  71  	}
  72  	return len(b), nil
  73  }
  74  
  75  func (c *UDPConn) writeToAddrPort(b []byte, addr netip.AddrPort) (int, error) {
  76  	return c.writeTo(b, UDPAddrFromAddrPort(addr)) // TODO: optimize instead of allocating
  77  }
  78  
  79  func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
  80  	return 0, 0, syscall.EPLAN9
  81  }
  82  
  83  func (c *UDPConn) writeMsgAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn int, err error) {
  84  	return 0, 0, syscall.EPLAN9
  85  }
  86  
  87  func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPConn, error) {
  88  	fd, err := dialPlan9(ctx, sd.network, laddr, raddr)
  89  	if err != nil {
  90  		return nil, err
  91  	}
  92  	return newUDPConn(fd), nil
  93  }
  94  
  95  const udpHeaderSize = 16*3 + 2*2
  96  
  97  type udpHeader struct {
  98  	raddr, laddr, ifcaddr IP
  99  	rport, lport          uint16
 100  }
 101  
 102  func (h *udpHeader) Bytes() []byte {
 103  	b := []byte{:udpHeaderSize}
 104  	i := 0
 105  	i += copy(b[i:i+16], h.raddr)
 106  	i += copy(b[i:i+16], h.laddr)
 107  	i += copy(b[i:i+16], h.ifcaddr)
 108  	b[i], b[i+1], i = byte(h.rport>>8), byte(h.rport), i+2
 109  	b[i], b[i+1], i = byte(h.lport>>8), byte(h.lport), i+2
 110  	return b
 111  }
 112  
 113  func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
 114  	h := &udpHeader{}
 115  	h.raddr, b = IP(b[:16]), b[16:]
 116  	h.laddr, b = IP(b[:16]), b[16:]
 117  	h.ifcaddr, b = IP(b[:16]), b[16:]
 118  	h.rport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
 119  	h.lport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
 120  	return h, b
 121  }
 122  
 123  func (sl *sysListener) listenUDP(ctx context.Context, laddr *UDPAddr) (*UDPConn, error) {
 124  	l, err := listenPlan9(ctx, sl.network, laddr)
 125  	if err != nil {
 126  		return nil, err
 127  	}
 128  	_, err = l.ctl.WriteString("headers")
 129  	if err != nil {
 130  		return nil, err
 131  	}
 132  	l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
 133  	if err != nil {
 134  		return nil, err
 135  	}
 136  	fd, err := l.netFD()
 137  	return newUDPConn(fd), err
 138  }
 139  
 140  func (sl *sysListener) listenMulticastUDP(ctx context.Context, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
 141  	// Plan 9 does not like announce command with a multicast address,
 142  	// so do not specify an IP address when listening.
 143  	l, err := listenPlan9(ctx, sl.network, &UDPAddr{IP: nil, Port: gaddr.Port, Zone: gaddr.Zone})
 144  	if err != nil {
 145  		return nil, err
 146  	}
 147  	_, err = l.ctl.WriteString("headers")
 148  	if err != nil {
 149  		return nil, err
 150  	}
 151  	var addrs []Addr
 152  	if ifi != nil {
 153  		addrs, err = ifi.Addrs()
 154  		if err != nil {
 155  			return nil, err
 156  		}
 157  	} else {
 158  		addrs, err = InterfaceAddrs()
 159  		if err != nil {
 160  			return nil, err
 161  		}
 162  	}
 163  
 164  	have4 := gaddr.IP.To4() != nil
 165  	for _, addr := range addrs {
 166  		if ipnet, ok := addr.(*IPNet); ok && (ipnet.IP.To4() != nil) == have4 {
 167  			_, err = l.ctl.WriteString("addmulti " + ipnet.IP.String() + " " + gaddr.IP.String())
 168  			if err != nil {
 169  				return nil, &OpError{Op: "addmulti", Net: "", Source: nil, Addr: ipnet, Err: err}
 170  			}
 171  		}
 172  	}
 173  	l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
 174  	if err != nil {
 175  		return nil, err
 176  	}
 177  	fd, err := l.netFD()
 178  	if err != nil {
 179  		return nil, err
 180  	}
 181  	return newUDPConn(fd), nil
 182  }
 183