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