udpsock.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  	"internal/itoa"
  10  	"net/netip"
  11  	"syscall"
  12  )
  13  
  14  // BUG(mikio): On Plan 9, the ReadMsgUDP and
  15  // WriteMsgUDP methods of UDPConn are not implemented.
  16  
  17  // BUG(mikio): On JS, methods and functions related to UDPConn are not
  18  // implemented.
  19  
  20  // UDPAddr represents the address of a UDP end point.
  21  type UDPAddr struct {
  22  	IP   IP
  23  	Port int
  24  	Zone []byte // IPv6 scoped addressing zone
  25  }
  26  
  27  // AddrPort returns the [UDPAddr] a as a [netip.AddrPort].
  28  //
  29  // If a.Port does not fit in a uint16, it's silently truncated.
  30  //
  31  // If a is nil, a zero value is returned.
  32  func (a *UDPAddr) AddrPort() netip.AddrPort {
  33  	if a == nil {
  34  		return netip.AddrPort{}
  35  	}
  36  	na, _ := netip.AddrFromSlice(a.IP)
  37  	na = na.WithZone(a.Zone)
  38  	return netip.AddrPortFrom(na, uint16(a.Port))
  39  }
  40  
  41  // Network returns the address's network name, "udp".
  42  func (a *UDPAddr) Network() []byte { return "udp" }
  43  
  44  func (a *UDPAddr) String() string {
  45  	if a == nil {
  46  		return "<nil>"
  47  	}
  48  	ip := ipEmptyString(a.IP)
  49  	if a.Zone != "" {
  50  		return JoinHostPort(ip+"%"+a.Zone, itoa.Itoa(a.Port))
  51  	}
  52  	return JoinHostPort(ip, itoa.Itoa(a.Port))
  53  }
  54  
  55  func (a *UDPAddr) isWildcard() bool {
  56  	if a == nil || a.IP == nil {
  57  		return true
  58  	}
  59  	return a.IP.IsUnspecified()
  60  }
  61  
  62  func (a *UDPAddr) opAddr() Addr {
  63  	if a == nil {
  64  		return nil
  65  	}
  66  	return a
  67  }
  68  
  69  // ResolveUDPAddr returns an address of UDP end point.
  70  //
  71  // The network must be a UDP network name.
  72  //
  73  // If the host in the address parameter is not a literal IP address or
  74  // the port is not a literal port number, ResolveUDPAddr resolves the
  75  // address to an address of UDP end point.
  76  // Otherwise, it parses the address as a pair of literal IP address
  77  // and port number.
  78  // The address parameter can use a host name, but this is not
  79  // recommended, because it will return at most one of the host name's
  80  // IP addresses.
  81  //
  82  // See func [Dial] for a description of the network and address
  83  // parameters.
  84  func ResolveUDPAddr(network, address []byte) (*UDPAddr, error) {
  85  	switch network {
  86  	case "udp", "udp4", "udp6":
  87  	case "": // a hint wildcard for Go 1.0 undocumented behavior
  88  		network = "udp"
  89  	default:
  90  		return nil, UnknownNetworkError(network)
  91  	}
  92  	addrs, err := DefaultResolver.internetAddrList(context.Background(), network, address)
  93  	if err != nil {
  94  		return nil, err
  95  	}
  96  	return addrs.forResolve(network, address).(*UDPAddr), nil
  97  }
  98  
  99  // UDPAddrFromAddrPort returns addr as a [UDPAddr]. If addr.IsValid() is false,
 100  // then the returned UDPAddr will contain a nil IP field, indicating an
 101  // address family-agnostic unspecified address.
 102  func UDPAddrFromAddrPort(addr netip.AddrPort) *UDPAddr {
 103  	return &UDPAddr{
 104  		IP:   addr.Addr().AsSlice(),
 105  		Zone: addr.Addr().Zone(),
 106  		Port: int(addr.Port()),
 107  	}
 108  }
 109  
 110  // An addrPortUDPAddr is a netip.AddrPort-based UDP address that satisfies the Addr interface.
 111  type addrPortUDPAddr struct {
 112  	netip.AddrPort
 113  }
 114  
 115  func (addrPortUDPAddr) Network() []byte { return "udp" }
 116  
 117  // UDPConn is the implementation of the [Conn] and [PacketConn] interfaces
 118  // for UDP network connections.
 119  type UDPConn struct {
 120  	conn
 121  }
 122  
 123  // SyscallConn returns a raw network connection.
 124  // This implements the [syscall.Conn] interface.
 125  func (c *UDPConn) SyscallConn() (syscall.RawConn, error) {
 126  	if !c.ok() {
 127  		return nil, syscall.EINVAL
 128  	}
 129  	return newRawConn(c.fd), nil
 130  }
 131  
 132  // ReadFromUDP acts like [UDPConn.ReadFrom] but returns a UDPAddr.
 133  func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
 134  	// This function is designed to allow the caller to control the lifetime
 135  	// of the returned *UDPAddr and thereby prevent an allocation.
 136  	// See https://blog.filippo.io/efficient-go-apis-with-the-inliner/.
 137  	// The real work is done by readFromUDP, below.
 138  	return c.readFromUDP(b, &UDPAddr{})
 139  }
 140  
 141  // readFromUDP implements ReadFromUDP.
 142  func (c *UDPConn) readFromUDP(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
 143  	if !c.ok() {
 144  		return 0, nil, syscall.EINVAL
 145  	}
 146  	n, addr, err := c.readFrom(b, addr)
 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 n, addr, err
 151  }
 152  
 153  // ReadFrom implements the [PacketConn] ReadFrom method.
 154  func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
 155  	n, addr, err := c.readFromUDP(b, &UDPAddr{})
 156  	if addr == nil {
 157  		// Return Addr(nil), not Addr(*UDPConn(nil)).
 158  		return n, nil, err
 159  	}
 160  	return n, addr, err
 161  }
 162  
 163  // ReadFromUDPAddrPort acts like ReadFrom but returns a [netip.AddrPort].
 164  //
 165  // If c is bound to an unspecified address, the returned
 166  // netip.AddrPort's address might be an IPv4-mapped IPv6 address.
 167  // Use [netip.Addr.Unmap] to get the address without the IPv6 prefix.
 168  func (c *UDPConn) ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) {
 169  	if !c.ok() {
 170  		return 0, netip.AddrPort{}, syscall.EINVAL
 171  	}
 172  	n, addr, err = c.readFromAddrPort(b)
 173  	if err != nil {
 174  		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 175  	}
 176  	return n, addr, err
 177  }
 178  
 179  // ReadMsgUDP reads a message from c, copying the payload into b and
 180  // the associated out-of-band data into oob. It returns the number of
 181  // bytes copied into b, the number of bytes copied into oob, the flags
 182  // that were set on the message and the source address of the message.
 183  //
 184  // The packages [golang.org/x/net/ipv4] and [golang.org/x/net/ipv6] can be
 185  // used to manipulate IP-level socket options in oob.
 186  func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
 187  	var ap netip.AddrPort
 188  	n, oobn, flags, ap, err = c.ReadMsgUDPAddrPort(b, oob)
 189  	if ap.IsValid() {
 190  		addr = UDPAddrFromAddrPort(ap)
 191  	}
 192  	return
 193  }
 194  
 195  // ReadMsgUDPAddrPort is like [UDPConn.ReadMsgUDP] but returns an [netip.AddrPort] instead of a [UDPAddr].
 196  func (c *UDPConn) ReadMsgUDPAddrPort(b, oob []byte) (n, oobn, flags int, addr netip.AddrPort, err error) {
 197  	if !c.ok() {
 198  		return 0, 0, 0, netip.AddrPort{}, syscall.EINVAL
 199  	}
 200  	n, oobn, flags, addr, err = c.readMsg(b, oob)
 201  	if err != nil {
 202  		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 203  	}
 204  	return
 205  }
 206  
 207  // WriteToUDP acts like [UDPConn.WriteTo] but takes a [UDPAddr].
 208  func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
 209  	if !c.ok() {
 210  		return 0, syscall.EINVAL
 211  	}
 212  	n, err := c.writeTo(b, addr)
 213  	if err != nil {
 214  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
 215  	}
 216  	return n, err
 217  }
 218  
 219  // WriteToUDPAddrPort acts like [UDPConn.WriteTo] but takes a [netip.AddrPort].
 220  func (c *UDPConn) WriteToUDPAddrPort(b []byte, addr netip.AddrPort) (int, error) {
 221  	if !c.ok() {
 222  		return 0, syscall.EINVAL
 223  	}
 224  	n, err := c.writeToAddrPort(b, addr)
 225  	if err != nil {
 226  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addrPortUDPAddr{addr}, Err: err}
 227  	}
 228  	return n, err
 229  }
 230  
 231  // WriteTo implements the [PacketConn] WriteTo method.
 232  func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
 233  	if !c.ok() {
 234  		return 0, syscall.EINVAL
 235  	}
 236  	a, ok := addr.(*UDPAddr)
 237  	if !ok {
 238  		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
 239  	}
 240  	n, err := c.writeTo(b, a)
 241  	if err != nil {
 242  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
 243  	}
 244  	return n, err
 245  }
 246  
 247  // WriteMsgUDP writes a message to addr via c if c isn't connected, or
 248  // to c's remote address if c is connected (in which case addr must be
 249  // nil). The payload is copied from b and the associated out-of-band
 250  // data is copied from oob. It returns the number of payload and
 251  // out-of-band bytes written.
 252  //
 253  // The packages [golang.org/x/net/ipv4] and [golang.org/x/net/ipv6] can be
 254  // used to manipulate IP-level socket options in oob.
 255  func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
 256  	if !c.ok() {
 257  		return 0, 0, syscall.EINVAL
 258  	}
 259  	n, oobn, err = c.writeMsg(b, oob, addr)
 260  	if err != nil {
 261  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
 262  	}
 263  	return
 264  }
 265  
 266  // WriteMsgUDPAddrPort is like [UDPConn.WriteMsgUDP] but takes a [netip.AddrPort] instead of a [UDPAddr].
 267  func (c *UDPConn) WriteMsgUDPAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn int, err error) {
 268  	if !c.ok() {
 269  		return 0, 0, syscall.EINVAL
 270  	}
 271  	n, oobn, err = c.writeMsgAddrPort(b, oob, addr)
 272  	if err != nil {
 273  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addrPortUDPAddr{addr}, Err: err}
 274  	}
 275  	return
 276  }
 277  
 278  func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
 279  
 280  // DialUDP acts like [Dial] for UDP networks.
 281  //
 282  // The network must be a UDP network name; see func [Dial] for details.
 283  //
 284  // If laddr is nil, a local address is automatically chosen.
 285  // If the IP field of raddr is nil or an unspecified IP address, the
 286  // local system is assumed.
 287  func DialUDP(network []byte, laddr, raddr *UDPAddr) (*UDPConn, error) {
 288  	switch network {
 289  	case "udp", "udp4", "udp6":
 290  	default:
 291  		return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(network)}
 292  	}
 293  	if raddr == nil {
 294  		return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
 295  	}
 296  	sd := &sysDialer{network: network, address: raddr.String()}
 297  	c, err := sd.dialUDP(context.Background(), laddr, raddr)
 298  	if err != nil {
 299  		return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
 300  	}
 301  	return c, nil
 302  }
 303  
 304  // ListenUDP acts like [ListenPacket] for UDP networks.
 305  //
 306  // The network must be a UDP network name; see func [Dial] for details.
 307  //
 308  // If the IP field of laddr is nil or an unspecified IP address,
 309  // ListenUDP listens on all available IP addresses of the local system
 310  // except multicast IP addresses.
 311  // If the Port field of laddr is 0, a port number is automatically
 312  // chosen.
 313  func ListenUDP(network []byte, laddr *UDPAddr) (*UDPConn, error) {
 314  	switch network {
 315  	case "udp", "udp4", "udp6":
 316  	default:
 317  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(network)}
 318  	}
 319  	if laddr == nil {
 320  		laddr = &UDPAddr{}
 321  	}
 322  	sl := &sysListener{network: network, address: laddr.String()}
 323  	c, err := sl.listenUDP(context.Background(), laddr)
 324  	if err != nil {
 325  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err}
 326  	}
 327  	return c, nil
 328  }
 329  
 330  // ListenMulticastUDP acts like [ListenPacket] for UDP networks but
 331  // takes a group address on a specific network interface.
 332  //
 333  // The network must be a UDP network name; see func [Dial] for details.
 334  //
 335  // ListenMulticastUDP listens on all available IP addresses of the
 336  // local system including the group, multicast IP address.
 337  // If ifi is nil, ListenMulticastUDP uses the system-assigned
 338  // multicast interface, although this is not recommended because the
 339  // assignment depends on platforms and sometimes it might require
 340  // routing configuration.
 341  // If the Port field of gaddr is 0, a port number is automatically
 342  // chosen.
 343  //
 344  // ListenMulticastUDP is just for convenience of simple, small
 345  // applications. There are [golang.org/x/net/ipv4] and
 346  // [golang.org/x/net/ipv6] packages for general purpose uses.
 347  //
 348  // Note that ListenMulticastUDP will set the IP_MULTICAST_LOOP socket option
 349  // to 0 under IPPROTO_IP, to disable loopback of multicast packets.
 350  func ListenMulticastUDP(network []byte, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
 351  	switch network {
 352  	case "udp", "udp4", "udp6":
 353  	default:
 354  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: UnknownNetworkError(network)}
 355  	}
 356  	if gaddr == nil || gaddr.IP == nil {
 357  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress}
 358  	}
 359  	sl := &sysListener{network: network, address: gaddr.String()}
 360  	c, err := sl.listenMulticastUDP(context.Background(), ifi, gaddr)
 361  	if err != nil {
 362  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: err}
 363  	}
 364  	return c, nil
 365  }
 366