udpsock_posix.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  //go:build unix || js || wasip1 || windows
   6  
   7  package net
   8  
   9  import (
  10  	"context"
  11  	"net/netip"
  12  	"syscall"
  13  )
  14  
  15  func sockaddrToUDP(sa syscall.Sockaddr) Addr {
  16  	switch sa := sa.(type) {
  17  	case *syscall.SockaddrInet4:
  18  		return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
  19  	case *syscall.SockaddrInet6:
  20  		return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
  21  	}
  22  	return nil
  23  }
  24  
  25  func (a *UDPAddr) family() int {
  26  	if a == nil || len(a.IP) <= IPv4len {
  27  		return syscall.AF_INET
  28  	}
  29  	if a.IP.To4() != nil {
  30  		return syscall.AF_INET
  31  	}
  32  	return syscall.AF_INET6
  33  }
  34  
  35  func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
  36  	if a == nil {
  37  		return nil, nil
  38  	}
  39  	return ipToSockaddr(family, a.IP, a.Port, a.Zone)
  40  }
  41  
  42  func (a *UDPAddr) toLocal(net []byte) sockaddr {
  43  	return &UDPAddr{loopbackIP(net), a.Port, a.Zone}
  44  }
  45  
  46  func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
  47  	var n int
  48  	var err error
  49  	switch c.fd.family {
  50  	case syscall.AF_INET:
  51  		var from syscall.SockaddrInet4
  52  		n, err = c.fd.readFromInet4(b, &from)
  53  		if err == nil {
  54  			ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 4 bytes
  55  			*addr = UDPAddr{IP: ip[:], Port: from.Port}
  56  		}
  57  	case syscall.AF_INET6:
  58  		var from syscall.SockaddrInet6
  59  		n, err = c.fd.readFromInet6(b, &from)
  60  		if err == nil {
  61  			ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 16 bytes
  62  			*addr = UDPAddr{IP: ip[:], Port: from.Port, Zone: zoneCache.name(int(from.ZoneId))}
  63  		}
  64  	}
  65  	if err != nil {
  66  		// No sockaddr, so don't return UDPAddr.
  67  		addr = nil
  68  	}
  69  	return n, addr, err
  70  }
  71  
  72  func (c *UDPConn) readFromAddrPort(b []byte) (n int, addr netip.AddrPort, err error) {
  73  	var ip netip.Addr
  74  	var port int
  75  	switch c.fd.family {
  76  	case syscall.AF_INET:
  77  		var from syscall.SockaddrInet4
  78  		n, err = c.fd.readFromInet4(b, &from)
  79  		if err == nil {
  80  			ip = netip.AddrFrom4(from.Addr)
  81  			port = from.Port
  82  		}
  83  	case syscall.AF_INET6:
  84  		var from syscall.SockaddrInet6
  85  		n, err = c.fd.readFromInet6(b, &from)
  86  		if err == nil {
  87  			ip = netip.AddrFrom16(from.Addr).WithZone(zoneCache.name(int(from.ZoneId)))
  88  			port = from.Port
  89  		}
  90  	}
  91  	if err == nil {
  92  		addr = netip.AddrPortFrom(ip, uint16(port))
  93  	}
  94  	return n, addr, err
  95  }
  96  
  97  func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr netip.AddrPort, err error) {
  98  	switch c.fd.family {
  99  	case syscall.AF_INET:
 100  		var sa syscall.SockaddrInet4
 101  		n, oobn, flags, err = c.fd.readMsgInet4(b, oob, 0, &sa)
 102  		ip := netip.AddrFrom4(sa.Addr)
 103  		addr = netip.AddrPortFrom(ip, uint16(sa.Port))
 104  	case syscall.AF_INET6:
 105  		var sa syscall.SockaddrInet6
 106  		n, oobn, flags, err = c.fd.readMsgInet6(b, oob, 0, &sa)
 107  		ip := netip.AddrFrom16(sa.Addr).WithZone(zoneCache.name(int(sa.ZoneId)))
 108  		addr = netip.AddrPortFrom(ip, uint16(sa.Port))
 109  	}
 110  	return
 111  }
 112  
 113  func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
 114  	if c.fd.isConnected {
 115  		return 0, ErrWriteToConnected
 116  	}
 117  	if addr == nil {
 118  		return 0, errMissingAddress
 119  	}
 120  
 121  	switch c.fd.family {
 122  	case syscall.AF_INET:
 123  		sa, err := ipToSockaddrInet4(addr.IP, addr.Port)
 124  		if err != nil {
 125  			return 0, err
 126  		}
 127  		return c.fd.writeToInet4(b, &sa)
 128  	case syscall.AF_INET6:
 129  		sa, err := ipToSockaddrInet6(addr.IP, addr.Port, addr.Zone)
 130  		if err != nil {
 131  			return 0, err
 132  		}
 133  		return c.fd.writeToInet6(b, &sa)
 134  	default:
 135  		return 0, &AddrError{Err: "invalid address family", Addr: addr.IP.String()}
 136  	}
 137  }
 138  
 139  func (c *UDPConn) writeToAddrPort(b []byte, addr netip.AddrPort) (int, error) {
 140  	if c.fd.isConnected {
 141  		return 0, ErrWriteToConnected
 142  	}
 143  	if !addr.IsValid() {
 144  		return 0, errMissingAddress
 145  	}
 146  
 147  	switch c.fd.family {
 148  	case syscall.AF_INET:
 149  		sa, err := addrPortToSockaddrInet4(addr)
 150  		if err != nil {
 151  			return 0, err
 152  		}
 153  		return c.fd.writeToInet4(b, &sa)
 154  	case syscall.AF_INET6:
 155  		sa, err := addrPortToSockaddrInet6(addr)
 156  		if err != nil {
 157  			return 0, err
 158  		}
 159  		return c.fd.writeToInet6(b, &sa)
 160  	default:
 161  		return 0, &AddrError{Err: "invalid address family", Addr: addr.Addr().String()}
 162  	}
 163  }
 164  
 165  func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
 166  	if c.fd.isConnected && addr != nil {
 167  		return 0, 0, ErrWriteToConnected
 168  	}
 169  	if !c.fd.isConnected && addr == nil {
 170  		return 0, 0, errMissingAddress
 171  	}
 172  	sa, err := addr.sockaddr(c.fd.family)
 173  	if err != nil {
 174  		return 0, 0, err
 175  	}
 176  	return c.fd.writeMsg(b, oob, sa)
 177  }
 178  
 179  func (c *UDPConn) writeMsgAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn int, err error) {
 180  	if c.fd.isConnected && addr.IsValid() {
 181  		return 0, 0, ErrWriteToConnected
 182  	}
 183  	if !c.fd.isConnected && !addr.IsValid() {
 184  		return 0, 0, errMissingAddress
 185  	}
 186  
 187  	switch c.fd.family {
 188  	case syscall.AF_INET:
 189  		sa, err := addrPortToSockaddrInet4(addr)
 190  		if err != nil {
 191  			return 0, 0, err
 192  		}
 193  		return c.fd.writeMsgInet4(b, oob, &sa)
 194  	case syscall.AF_INET6:
 195  		sa, err := addrPortToSockaddrInet6(addr)
 196  		if err != nil {
 197  			return 0, 0, err
 198  		}
 199  		return c.fd.writeMsgInet6(b, oob, &sa)
 200  	default:
 201  		return 0, 0, &AddrError{Err: "invalid address family", Addr: addr.Addr().String()}
 202  	}
 203  }
 204  
 205  func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPConn, error) {
 206  	ctrlCtxFn := sd.Dialer.ControlContext
 207  	if ctrlCtxFn == nil && sd.Dialer.Control != nil {
 208  		ctrlCtxFn = func(ctx context.Context, network, address []byte, c syscall.RawConn) error {
 209  			return sd.Dialer.Control(network, address, c)
 210  		}
 211  	}
 212  	fd, err := internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_DGRAM, 0, "dial", ctrlCtxFn)
 213  	if err != nil {
 214  		return nil, err
 215  	}
 216  	return newUDPConn(fd), nil
 217  }
 218  
 219  func (sl *sysListener) listenUDP(ctx context.Context, laddr *UDPAddr) (*UDPConn, error) {
 220  	var ctrlCtxFn func(ctx context.Context, network, address []byte, c syscall.RawConn) error
 221  	if sl.ListenConfig.Control != nil {
 222  		ctrlCtxFn = func(ctx context.Context, network, address []byte, c syscall.RawConn) error {
 223  			return sl.ListenConfig.Control(network, address, c)
 224  		}
 225  	}
 226  	fd, err := internetSocket(ctx, sl.network, laddr, nil, syscall.SOCK_DGRAM, 0, "listen", ctrlCtxFn)
 227  	if err != nil {
 228  		return nil, err
 229  	}
 230  	return newUDPConn(fd), nil
 231  }
 232  
 233  func (sl *sysListener) listenMulticastUDP(ctx context.Context, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
 234  	var ctrlCtxFn func(ctx context.Context, network, address []byte, c syscall.RawConn) error
 235  	if sl.ListenConfig.Control != nil {
 236  		ctrlCtxFn = func(ctx context.Context, network, address []byte, c syscall.RawConn) error {
 237  			return sl.ListenConfig.Control(network, address, c)
 238  		}
 239  	}
 240  	fd, err := internetSocket(ctx, sl.network, gaddr, nil, syscall.SOCK_DGRAM, 0, "listen", ctrlCtxFn)
 241  	if err != nil {
 242  		return nil, err
 243  	}
 244  	c := newUDPConn(fd)
 245  	if ip4 := gaddr.IP.To4(); ip4 != nil {
 246  		if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil {
 247  			c.Close()
 248  			return nil, err
 249  		}
 250  	} else {
 251  		if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil {
 252  			c.Close()
 253  			return nil, err
 254  		}
 255  	}
 256  	return c, nil
 257  }
 258  
 259  func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
 260  	if ifi != nil {
 261  		if err := setIPv4MulticastInterface(c.fd, ifi); err != nil {
 262  			return err
 263  		}
 264  	}
 265  	if err := setIPv4MulticastLoopback(c.fd, false); err != nil {
 266  		return err
 267  	}
 268  	if err := joinIPv4Group(c.fd, ifi, ip); err != nil {
 269  		return err
 270  	}
 271  	return nil
 272  }
 273  
 274  func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
 275  	if ifi != nil {
 276  		if err := setIPv6MulticastInterface(c.fd, ifi); err != nil {
 277  			return err
 278  		}
 279  	}
 280  	if err := setIPv6MulticastLoopback(c.fd, false); err != nil {
 281  		return err
 282  	}
 283  	if err := joinIPv6Group(c.fd, ifi, ip); err != nil {
 284  		return err
 285  	}
 286  	return nil
 287  }
 288