diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2022-11-24 13:14:34 +0300 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2022-11-24 14:46:00 +0300 |
commit | 87f7fceed34bcafb8aaff351dd493a35c916986f (patch) | |
tree | 26809ec8f550aba8eb019e59adc3d48e51913eb2 /contrib/go/_std_1.18/src/net/udpsock.go | |
parent | 11bc4015b8010ae201bf3eb33db7dba425aca35e (diff) | |
download | ydb-87f7fceed34bcafb8aaff351dd493a35c916986f.tar.gz |
Ydb stable 22-4-4322.4.43
x-stable-origin-commit: 8d49d46cc834835bf3e50870516acd7376a63bcf
Diffstat (limited to 'contrib/go/_std_1.18/src/net/udpsock.go')
-rw-r--r-- | contrib/go/_std_1.18/src/net/udpsock.go | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/contrib/go/_std_1.18/src/net/udpsock.go b/contrib/go/_std_1.18/src/net/udpsock.go new file mode 100644 index 0000000000..6d29a39edf --- /dev/null +++ b/contrib/go/_std_1.18/src/net/udpsock.go @@ -0,0 +1,364 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "context" + "internal/itoa" + "net/netip" + "syscall" +) + +// BUG(mikio): On Plan 9, the ReadMsgUDP and +// WriteMsgUDP methods of UDPConn are not implemented. + +// BUG(mikio): On Windows, the File method of UDPConn is not +// implemented. + +// BUG(mikio): On JS, methods and functions related to UDPConn are not +// implemented. + +// UDPAddr represents the address of a UDP end point. +type UDPAddr struct { + IP IP + Port int + Zone string // IPv6 scoped addressing zone +} + +// AddrPort returns the UDPAddr a as a netip.AddrPort. +// +// If a.Port does not fit in a uint16, it's silently truncated. +// +// If a is nil, a zero value is returned. +func (a *UDPAddr) AddrPort() netip.AddrPort { + if a == nil { + return netip.AddrPort{} + } + na, _ := netip.AddrFromSlice(a.IP) + na = na.WithZone(a.Zone) + return netip.AddrPortFrom(na, uint16(a.Port)) +} + +// Network returns the address's network name, "udp". +func (a *UDPAddr) Network() string { return "udp" } + +func (a *UDPAddr) String() string { + if a == nil { + return "<nil>" + } + ip := ipEmptyString(a.IP) + if a.Zone != "" { + return JoinHostPort(ip+"%"+a.Zone, itoa.Itoa(a.Port)) + } + return JoinHostPort(ip, itoa.Itoa(a.Port)) +} + +func (a *UDPAddr) isWildcard() bool { + if a == nil || a.IP == nil { + return true + } + return a.IP.IsUnspecified() +} + +func (a *UDPAddr) opAddr() Addr { + if a == nil { + return nil + } + return a +} + +// ResolveUDPAddr returns an address of UDP end point. +// +// The network must be a UDP network name. +// +// If the host in the address parameter is not a literal IP address or +// the port is not a literal port number, ResolveUDPAddr resolves the +// address to an address of UDP end point. +// Otherwise, it parses the address as a pair of literal IP address +// and port number. +// The address parameter can use a host name, but this is not +// recommended, because it will return at most one of the host name's +// IP addresses. +// +// See func Dial for a description of the network and address +// parameters. +func ResolveUDPAddr(network, address string) (*UDPAddr, error) { + switch network { + case "udp", "udp4", "udp6": + case "": // a hint wildcard for Go 1.0 undocumented behavior + network = "udp" + default: + return nil, UnknownNetworkError(network) + } + addrs, err := DefaultResolver.internetAddrList(context.Background(), network, address) + if err != nil { + return nil, err + } + return addrs.forResolve(network, address).(*UDPAddr), nil +} + +// UDPAddrFromAddrPort returns addr as a UDPAddr. If addr.IsValid() is false, +// then the returned UDPAddr will contain a nil IP field, indicating an +// address family-agnostic unspecified address. +func UDPAddrFromAddrPort(addr netip.AddrPort) *UDPAddr { + return &UDPAddr{ + IP: addr.Addr().AsSlice(), + Zone: addr.Addr().Zone(), + Port: int(addr.Port()), + } +} + +// An addrPortUDPAddr is a netip.AddrPort-based UDP address that satisfies the Addr interface. +type addrPortUDPAddr struct { + netip.AddrPort +} + +func (addrPortUDPAddr) Network() string { return "udp" } + +// UDPConn is the implementation of the Conn and PacketConn interfaces +// for UDP network connections. +type UDPConn struct { + conn +} + +// SyscallConn returns a raw network connection. +// This implements the syscall.Conn interface. +func (c *UDPConn) SyscallConn() (syscall.RawConn, error) { + if !c.ok() { + return nil, syscall.EINVAL + } + return newRawConn(c.fd) +} + +// ReadFromUDP acts like ReadFrom but returns a UDPAddr. +func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) { + // This function is designed to allow the caller to control the lifetime + // of the returned *UDPAddr and thereby prevent an allocation. + // See https://blog.filippo.io/efficient-go-apis-with-the-inliner/. + // The real work is done by readFromUDP, below. + return c.readFromUDP(b, &UDPAddr{}) +} + +// readFromUDP implements ReadFromUDP. +func (c *UDPConn) readFromUDP(b []byte, addr *UDPAddr) (int, *UDPAddr, error) { + if !c.ok() { + return 0, nil, syscall.EINVAL + } + n, addr, err := c.readFrom(b, addr) + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, addr, err +} + +// ReadFrom implements the PacketConn ReadFrom method. +func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) { + n, addr, err := c.readFromUDP(b, &UDPAddr{}) + if addr == nil { + // Return Addr(nil), not Addr(*UDPConn(nil)). + return n, nil, err + } + return n, addr, err +} + +// ReadFromUDPAddrPort acts like ReadFrom but returns a netip.AddrPort. +func (c *UDPConn) ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) { + if !c.ok() { + return 0, netip.AddrPort{}, syscall.EINVAL + } + n, addr, err = c.readFromAddrPort(b) + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, addr, err +} + +// ReadMsgUDP reads a message from c, copying the payload into b and +// the associated out-of-band data into oob. It returns the number of +// bytes copied into b, the number of bytes copied into oob, the flags +// that were set on the message and the source address of the message. +// +// The packages golang.org/x/net/ipv4 and golang.org/x/net/ipv6 can be +// used to manipulate IP-level socket options in oob. +func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) { + var ap netip.AddrPort + n, oobn, flags, ap, err = c.ReadMsgUDPAddrPort(b, oob) + if ap.IsValid() { + addr = UDPAddrFromAddrPort(ap) + } + return +} + +// ReadMsgUDPAddrPort is like ReadMsgUDP but returns an netip.AddrPort instead of a UDPAddr. +func (c *UDPConn) ReadMsgUDPAddrPort(b, oob []byte) (n, oobn, flags int, addr netip.AddrPort, err error) { + if !c.ok() { + return 0, 0, 0, netip.AddrPort{}, syscall.EINVAL + } + n, oobn, flags, addr, err = c.readMsg(b, oob) + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return +} + +// WriteToUDP acts like WriteTo but takes a UDPAddr. +func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) { + if !c.ok() { + return 0, syscall.EINVAL + } + n, err := c.writeTo(b, addr) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} + } + return n, err +} + +// WriteToUDPAddrPort acts like WriteTo but takes a netip.AddrPort. +func (c *UDPConn) WriteToUDPAddrPort(b []byte, addr netip.AddrPort) (int, error) { + if !c.ok() { + return 0, syscall.EINVAL + } + n, err := c.writeToAddrPort(b, addr) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addrPortUDPAddr{addr}, Err: err} + } + return n, err +} + +// WriteTo implements the PacketConn WriteTo method. +func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) { + if !c.ok() { + return 0, syscall.EINVAL + } + a, ok := addr.(*UDPAddr) + if !ok { + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL} + } + n, err := c.writeTo(b, a) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err} + } + return n, err +} + +// WriteMsgUDP writes a message to addr via c if c isn't connected, or +// to c's remote address if c is connected (in which case addr must be +// nil). The payload is copied from b and the associated out-of-band +// data is copied from oob. It returns the number of payload and +// out-of-band bytes written. +// +// The packages golang.org/x/net/ipv4 and golang.org/x/net/ipv6 can be +// used to manipulate IP-level socket options in oob. +func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) { + if !c.ok() { + return 0, 0, syscall.EINVAL + } + n, oobn, err = c.writeMsg(b, oob, addr) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} + } + return +} + +// WriteMsgUDPAddrPort is like WriteMsgUDP but takes a netip.AddrPort instead of a UDPAddr. +func (c *UDPConn) WriteMsgUDPAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn int, err error) { + if !c.ok() { + return 0, 0, syscall.EINVAL + } + n, oobn, err = c.writeMsgAddrPort(b, oob, addr) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addrPortUDPAddr{addr}, Err: err} + } + return +} + +func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} } + +// DialUDP acts like Dial for UDP networks. +// +// The network must be a UDP network name; see func Dial for details. +// +// If laddr is nil, a local address is automatically chosen. +// If the IP field of raddr is nil or an unspecified IP address, the +// local system is assumed. +func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error) { + switch network { + case "udp", "udp4", "udp6": + default: + return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(network)} + } + if raddr == nil { + return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress} + } + sd := &sysDialer{network: network, address: raddr.String()} + c, err := sd.dialUDP(context.Background(), laddr, raddr) + if err != nil { + return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} + } + return c, nil +} + +// ListenUDP acts like ListenPacket for UDP networks. +// +// The network must be a UDP network name; see func Dial for details. +// +// If the IP field of laddr is nil or an unspecified IP address, +// ListenUDP listens on all available IP addresses of the local system +// except multicast IP addresses. +// If the Port field of laddr is 0, a port number is automatically +// chosen. +func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) { + switch network { + case "udp", "udp4", "udp6": + default: + return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(network)} + } + if laddr == nil { + laddr = &UDPAddr{} + } + sl := &sysListener{network: network, address: laddr.String()} + c, err := sl.listenUDP(context.Background(), laddr) + if err != nil { + return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err} + } + return c, nil +} + +// ListenMulticastUDP acts like ListenPacket for UDP networks but +// takes a group address on a specific network interface. +// +// The network must be a UDP network name; see func Dial for details. +// +// ListenMulticastUDP listens on all available IP addresses of the +// local system including the group, multicast IP address. +// If ifi is nil, ListenMulticastUDP uses the system-assigned +// multicast interface, although this is not recommended because the +// assignment depends on platforms and sometimes it might require +// routing configuration. +// If the Port field of gaddr is 0, a port number is automatically +// chosen. +// +// ListenMulticastUDP is just for convenience of simple, small +// applications. There are golang.org/x/net/ipv4 and +// golang.org/x/net/ipv6 packages for general purpose uses. +// +// Note that ListenMulticastUDP will set the IP_MULTICAST_LOOP socket option +// to 0 under IPPROTO_IP, to disable loopback of multicast packets. +func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { + switch network { + case "udp", "udp4", "udp6": + default: + return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: UnknownNetworkError(network)} + } + if gaddr == nil || gaddr.IP == nil { + return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress} + } + sl := &sysListener{network: network, address: gaddr.String()} + c, err := sl.listenMulticastUDP(context.Background(), ifi, gaddr) + if err != nil { + return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: err} + } + return c, nil +} |