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 5package net 6 7import ( 8 "context" 9 "errors" 10 "net/netip" 11 "os" 12 "syscall" 13) 14 15func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) { 16 buf := make([]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 32func (c *UDPConn) readFromAddrPort(b []byte) (int, netip.AddrPort, error) { 33 // TODO: optimize. The equivalent code on posix is alloc-free. 34 buf := make([]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 51func (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 55func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) { 56 if addr == nil { 57 return 0, errMissingAddress 58 } 59 h := new(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 := make([]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 75func (c *UDPConn) writeToAddrPort(b []byte, addr netip.AddrPort) (int, error) { 76 return c.writeTo(b, UDPAddrFromAddrPort(addr)) // TODO: optimize instead of allocating 77} 78 79func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) { 80 return 0, 0, syscall.EPLAN9 81} 82 83func (c *UDPConn) writeMsgAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn int, err error) { 84 return 0, 0, syscall.EPLAN9 85} 86 87func (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 95const udpHeaderSize = 16*3 + 2*2 96 97type udpHeader struct { 98 raddr, laddr, ifcaddr IP 99 rport, lport uint16 100} 101 102func (h *udpHeader) Bytes() []byte { 103 b := make([]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 113func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) { 114 h := new(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 123func (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 140func (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