From 69e8291b91ebd5689142bf5c2ac5852e0b7bd91d Mon Sep 17 00:00:00 2001 From: Paul Schroeder Date: Fri, 28 Apr 2023 11:55:49 +0200 Subject: [PATCH] feat(net/udpsock): Expose contexts for several UDP related functions --- src/net/iprawsock.go | 13 ++++++- src/net/tcpsock.go | 13 ++++++- src/net/udpsock.go | 81 ++++++++++++++++++++++++++++++++++++++++---- src/net/unixsock.go | 12 ++++++- 4 files changed, 109 insertions(+), 10 deletions(-) diff --git a/src/net/iprawsock.go b/src/net/iprawsock.go index f18331a1fd5a2f..6478c1e61c4f9e 100644 --- a/src/net/iprawsock.go +++ b/src/net/iprawsock.go @@ -209,11 +209,22 @@ func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} } // If the IP field of raddr is nil or an unspecified IP address, the // local system is assumed. func DialIP(network string, laddr, raddr *IPAddr) (*IPConn, error) { + return DialIPWithContext(context.Background(), network, laddr, raddr) +} + +// DialIPWithContext acts like Dial for IP networks. +// +// The network must be an IP 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 DialIPWithContext(ctx context.Context, network string, laddr, raddr *IPAddr) (*IPConn, error) { 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.dialIP(context.Background(), laddr, raddr) + c, err := sd.dialIP(ctx, laddr, raddr) if err != nil { return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} } diff --git a/src/net/tcpsock.go b/src/net/tcpsock.go index 358e48723b9437..370a34276afa2f 100644 --- a/src/net/tcpsock.go +++ b/src/net/tcpsock.go @@ -258,6 +258,17 @@ func newTCPConn(fd *netFD, keepAlive time.Duration, keepAliveHook func(time.Dura // If the IP field of raddr is nil or an unspecified IP address, the // local system is assumed. func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error) { + return DialTCPWithContext(context.Background(), network, laddr, raddr) +} + +// DialTCPWithContext acts like Dial for TCP networks. +// +// The network must be a TCP 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 DialTCPWithContext(ctx context.Context, network string, laddr, raddr *TCPAddr) (*TCPConn, error) { switch network { case "tcp", "tcp4", "tcp6": default: @@ -267,7 +278,7 @@ func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error) { return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress} } sd := &sysDialer{network: network, address: raddr.String()} - c, err := sd.dialTCP(context.Background(), laddr, raddr) + c, err := sd.dialTCP(ctx, laddr, raddr) if err != nil { return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} } diff --git a/src/net/udpsock.go b/src/net/udpsock.go index e30624dea5a74e..6f8596ee358c9d 100644 --- a/src/net/udpsock.go +++ b/src/net/udpsock.go @@ -85,6 +85,25 @@ func (a *UDPAddr) opAddr() Addr { // See func Dial for a description of the network and address // parameters. func ResolveUDPAddr(network, address string) (*UDPAddr, error) { + return ResolveUDPAddrWithContext(context.Background(), network, address) +} + +// ResolveUDPAddrWithContext 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 ResolveUDPAddrWithContext(ctx context.Context, network, address string) (*UDPAddr, error) { switch network { case "udp", "udp4", "udp6": case "": // a hint wildcard for Go 1.0 undocumented behavior @@ -92,7 +111,7 @@ func ResolveUDPAddr(network, address string) (*UDPAddr, error) { default: return nil, UnknownNetworkError(network) } - addrs, err := DefaultResolver.internetAddrList(context.Background(), network, address) + addrs, err := DefaultResolver.internetAddrList(ctx, network, address) if err != nil { return nil, err } @@ -280,14 +299,14 @@ func (c *UDPConn) WriteMsgUDPAddrPort(b, oob []byte, addr netip.AddrPort) (n, oo func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} } -// DialUDP acts like Dial for UDP networks. +// DialUDPWithContext 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) { +func DialUDPWithContext(ctx context.Context, network string, laddr, raddr *UDPAddr) (*UDPConn, error) { switch network { case "udp", "udp4", "udp6": default: @@ -297,13 +316,24 @@ func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error) { 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) + c, err := sd.dialUDP(ctx, laddr, raddr) if err != nil { return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} } return c, nil } +// 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) { + return DialUDPWithContext(context.Background(), network, laddr, raddr) +} + // ListenUDP acts like ListenPacket for UDP networks. // // The network must be a UDP network name; see func Dial for details. @@ -314,6 +344,19 @@ func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error) { // If the Port field of laddr is 0, a port number is automatically // chosen. func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) { + return ListenUDPWithContext(context.Background(), network, laddr) +} + +// ListenUDPWithContext 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 ListenUDPWithContext(ctx context.Context, network string, laddr *UDPAddr) (*UDPConn, error) { switch network { case "udp", "udp4", "udp6": default: @@ -323,7 +366,7 @@ func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) { laddr = &UDPAddr{} } sl := &sysListener{network: network, address: laddr.String()} - c, err := sl.listenUDP(context.Background(), laddr) + c, err := sl.listenUDP(ctx, laddr) if err != nil { return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err} } @@ -339,7 +382,7 @@ func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) { // 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 +// 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. @@ -351,6 +394,30 @@ func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) { // 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) { + return ListenMulticastUDPWithContext(context.Background(), network, ifi, gaddr) +} + +// ListenMulticastUDPWithContext 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 ListenMulticastUDPWithContext(ctx context.Context, network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { switch network { case "udp", "udp4", "udp6": default: @@ -360,7 +427,7 @@ func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPCon 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) + c, err := sl.listenMulticastUDP(ctx, ifi, gaddr) if err != nil { return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: err} } diff --git a/src/net/unixsock.go b/src/net/unixsock.go index 14fbac0932da85..7a23a94a144f25 100644 --- a/src/net/unixsock.go +++ b/src/net/unixsock.go @@ -201,13 +201,23 @@ func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} } // If laddr is non-nil, it is used as the local address for the // connection. func DialUnix(network string, laddr, raddr *UnixAddr) (*UnixConn, error) { + return DialUnixWithContext(context.Background(), network, laddr, raddr) +} + +// DialUnixWithContext acts like Dial for Unix networks. +// +// The network must be a Unix network name; see func Dial for details. +// +// If laddr is non-nil, it is used as the local address for the +// connection. +func DialUnixWithContext(ctx context.Context, network string, laddr, raddr *UnixAddr) (*UnixConn, error) { switch network { case "unix", "unixgram", "unixpacket": default: return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(network)} } sd := &sysDialer{network: network, address: raddr.String()} - c, err := sd.dialUnix(context.Background(), laddr, raddr) + c, err := sd.dialUnix(ctx, laddr, raddr) if err != nil { return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} }