mirror of
https://github.com/tinygo-org/net.git
synced 2026-07-26 08:18:39 +00:00
d5da3ddeef
* net: add UDP listen, resolver, DNSError, and TCP listener APIs for wasm TinyGo's net package was missing several symbols that upstream Go's js/wasm net declares, blocking builds that pull pion/transport, pion/dtls, and similar (via netbird's WASM client). Add them, backed by the existing netdev abstraction so they compile for all targets and no-op cleanly under nopNetdev (matching Go's js runtime behavior): - DNSError type (dnserror.go), copied from Go 1.26.2. - Resolver + DefaultResolver with LookupHost/LookupIP/LookupIPAddr/ LookupNetIP/LookupPort; LookupHost/LookupIP package funcs; Dialer.Resolver field for API compatibility. - UDPConn: ListenUDP, ReadFromUDP(AddrPort), WriteToUDP(AddrPort), SetReadBuffer, SetWriteBuffer. - TCPConn: CloseRead, SetNoDelay, SetReadBuffer, SetWriteBuffer, ReadFrom(io.Reader). - TCPListener: ListenTCP, AcceptTCP, SetDeadline; ListenPacket package func. - Interface: Addrs, MulticastAddrs stubs. * more complete PR for adding more net support (#64) * format unixsock
310 lines
10 KiB
Go
310 lines
10 KiB
Go
// TINYGO: The following is copied and modified from Go 1.26.2 official implementation.
|
|
|
|
// TINYGO: Omit DualStack support
|
|
// TINYGO: Omit Fast Fallback support
|
|
// TINYGO: Don't allow alternate resolver
|
|
// TINYGO: Omit DialTimeout
|
|
// TINYGO: Omit Multipath TCP
|
|
|
|
// Copyright 2010 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"
|
|
"errors"
|
|
"fmt"
|
|
"internal/bytealg"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
|
|
// See go.dev/issue/31510
|
|
defaultTCPKeepAlive = 15 * time.Second
|
|
)
|
|
|
|
// mptcpStatus is a tristate for Multipath TCP, see go.dev/issue/56539
|
|
type mptcpStatus uint8
|
|
|
|
// TINYGO: mptcpStatusListen stub for ListenConfig compatibility
|
|
type mptcpStatusListen uint8
|
|
|
|
// A Dialer contains options for connecting to an address.
|
|
//
|
|
// The zero value for each field is equivalent to dialing
|
|
// without that option. Dialing with the zero value of Dialer
|
|
// is therefore equivalent to just calling the [Dial] function.
|
|
//
|
|
// It is safe to call Dialer's methods concurrently.
|
|
type Dialer struct {
|
|
// Timeout is the maximum amount of time a dial will wait for
|
|
// a connect to complete. If Deadline is also set, it may fail
|
|
// earlier.
|
|
//
|
|
// The default is no timeout.
|
|
//
|
|
// When using TCP and dialing a host name with multiple IP
|
|
// addresses, the timeout may be divided between them.
|
|
//
|
|
// With or without a timeout, the operating system may impose
|
|
// its own earlier timeout. For instance, TCP timeouts are
|
|
// often around 3 minutes.
|
|
Timeout time.Duration
|
|
|
|
// Deadline is the absolute point in time after which dials
|
|
// will fail. If Timeout is set, it may fail earlier.
|
|
// Zero means no deadline, or dependent on the operating system
|
|
// as with the Timeout option.
|
|
Deadline time.Time
|
|
|
|
// LocalAddr is the local address to use when dialing an
|
|
// address. The address must be of a compatible type for the
|
|
// network being dialed.
|
|
// If nil, a local address is automatically chosen.
|
|
LocalAddr Addr
|
|
|
|
// KeepAlive specifies the interval between keep-alive
|
|
// probes for an active network connection.
|
|
//
|
|
// KeepAlive is ignored if KeepAliveConfig.Enable is true.
|
|
//
|
|
// If zero, keep-alive probes are sent with a default value
|
|
// (currently 15 seconds), if supported by the protocol and operating
|
|
// system. Network protocols or operating systems that do
|
|
// not support keep-alive ignore this field.
|
|
// If negative, keep-alive probes are disabled.
|
|
KeepAlive time.Duration
|
|
|
|
// KeepAliveConfig specifies the keep-alive probe configuration
|
|
// for an active network connection, when supported by the
|
|
// protocol and operating system.
|
|
//
|
|
// If KeepAliveConfig.Enable is true, keep-alive probes are enabled.
|
|
// If KeepAliveConfig.Enable is false and KeepAlive is negative,
|
|
// keep-alive probes are disabled.
|
|
KeepAliveConfig KeepAliveConfig
|
|
|
|
// Resolver optionally specifies an alternate resolver to use.
|
|
//
|
|
// TINYGO: present for API compatibility; DialContext resolves via the
|
|
// netdev-backed ResolveTCPAddr/ResolveUDPAddr and does not consult this
|
|
// field.
|
|
Resolver *Resolver
|
|
}
|
|
|
|
// Dial connects to the address on the named network.
|
|
//
|
|
// See Go "net" package Dial() for more information.
|
|
//
|
|
// Note: Tinygo Dial supports a subset of networks supported by Go Dial,
|
|
// specifically: "tcp", "tcp4", "udp", and "udp4". IP and unix networks are
|
|
// not supported.
|
|
func Dial(network, address string) (Conn, error) {
|
|
var d Dialer
|
|
return d.Dial(network, address)
|
|
}
|
|
|
|
// DialTimeout acts like [Dial] but takes a timeout.
|
|
//
|
|
// The timeout includes name resolution, if required.
|
|
// When using TCP, and the host in the address parameter resolves to
|
|
// multiple IP addresses, the timeout is spread over each consecutive
|
|
// dial, such that each is given an appropriate fraction of the time
|
|
// to connect.
|
|
//
|
|
// See func Dial for a description of the network and address
|
|
// parameters.
|
|
func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
|
|
d := Dialer{Timeout: timeout}
|
|
return d.Dial(network, address)
|
|
}
|
|
|
|
// Dial connects to the address on the named network.
|
|
//
|
|
// See func Dial for a description of the network and address
|
|
// parameters.
|
|
//
|
|
// Dial uses [context.Background] internally; to specify the context, use
|
|
// [Dialer.DialContext].
|
|
func (d *Dialer) Dial(network, address string) (Conn, error) {
|
|
return d.DialContext(context.Background(), network, address)
|
|
}
|
|
|
|
// DialContext connects to the address on the named network using
|
|
// the provided context.
|
|
//
|
|
// The provided Context must be non-nil. If the context expires before
|
|
// the connection is complete, an error is returned. Once successfully
|
|
// connected, any expiration of the context will not affect the
|
|
// connection.
|
|
//
|
|
// When using TCP, and the host in the address parameter resolves to multiple
|
|
// network addresses, any dial timeout (from d.Timeout or ctx) is spread
|
|
// over each consecutive dial, such that each is given an appropriate
|
|
// fraction of the time to connect.
|
|
// For example, if a host has 4 IP addresses and the timeout is 1 minute,
|
|
// the connect to each single address will be given 15 seconds to complete
|
|
// before trying the next one.
|
|
//
|
|
// See func [Dial] for a description of the network and address
|
|
// parameters.
|
|
func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) {
|
|
|
|
// TINYGO: Ignoring context
|
|
|
|
switch network {
|
|
case "tcp", "tcp4":
|
|
raddr, err := ResolveTCPAddr(network, address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return DialTCP(network, nil, raddr)
|
|
case "udp", "udp4":
|
|
raddr, err := ResolveUDPAddr(network, address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return DialUDP(network, nil, raddr)
|
|
}
|
|
|
|
return nil, fmt.Errorf("Network %s not supported", network)
|
|
}
|
|
|
|
// ListenConfig contains options for listening to an address.
|
|
type ListenConfig struct {
|
|
// If Control is not nil, it is called after creating the network
|
|
// connection but before binding it to the operating system.
|
|
//
|
|
// Network and address parameters passed to Control function are not
|
|
// necessarily the ones passed to Listen. Calling Listen with TCP networks
|
|
// will cause the Control function to be called with "tcp4" or "tcp6",
|
|
// UDP networks become "udp4" or "udp6", IP networks become "ip4" or "ip6",
|
|
// and other known networks are passed as-is.
|
|
Control func(network, address string, c syscall.RawConn) error
|
|
|
|
// KeepAlive specifies the keep-alive period for network
|
|
// connections accepted by this listener.
|
|
//
|
|
// KeepAlive is ignored if KeepAliveConfig.Enable is true.
|
|
//
|
|
// If zero, keep-alive are enabled if supported by the protocol
|
|
// and operating system. Network protocols or operating systems
|
|
// that do not support keep-alive ignore this field.
|
|
// If negative, keep-alive are disabled.
|
|
KeepAlive time.Duration
|
|
|
|
// KeepAliveConfig specifies the keep-alive probe configuration
|
|
// for an active network connection, when supported by the
|
|
// protocol and operating system.
|
|
//
|
|
// If KeepAliveConfig.Enable is true, keep-alive probes are enabled.
|
|
// If KeepAliveConfig.Enable is false and KeepAlive is negative,
|
|
// keep-alive probes are disabled.
|
|
KeepAliveConfig KeepAliveConfig
|
|
|
|
// If mptcpStatus is set to a value allowing Multipath TCP (MPTCP) to be
|
|
// used, any call to Listen with "tcp(4|6)" as network will use MPTCP if
|
|
// supported by the operating system.
|
|
mptcpStatus mptcpStatusListen
|
|
}
|
|
|
|
// Listen announces on the local network address.
|
|
//
|
|
// See func Listen for a description of the network and address
|
|
// parameters.
|
|
//
|
|
// The ctx argument is used while resolving the address on which to listen;
|
|
// it does not affect the returned Listener.
|
|
func (lc *ListenConfig) Listen(ctx context.Context, network, address string) (Listener, error) {
|
|
return nil, errors.New("dial:ListenConfig:Listen not implemented")
|
|
}
|
|
|
|
// ListenPacket announces on the local network address.
|
|
//
|
|
// See func ListenPacket for a description of the network and address
|
|
// parameters.
|
|
//
|
|
// The ctx argument is used while resolving the address on which to listen;
|
|
// it does not affect the returned PacketConn.
|
|
func (lc *ListenConfig) ListenPacket(ctx context.Context, network, address string) (PacketConn, error) {
|
|
return nil, errors.New("dial:ListenConfig:ListenPacket not implemented")
|
|
}
|
|
|
|
func parseNetwork(ctx context.Context, network string, needsProto bool) (afnet string, proto int, err error) {
|
|
i := bytealg.LastIndexByteString(network, ':')
|
|
if i < 0 { // no colon
|
|
switch network {
|
|
case "tcp", "tcp4", "tcp6":
|
|
case "udp", "udp4", "udp6":
|
|
case "ip", "ip4", "ip6":
|
|
if needsProto {
|
|
return "", 0, UnknownNetworkError(network)
|
|
}
|
|
case "unix", "unixgram", "unixpacket":
|
|
default:
|
|
return "", 0, UnknownNetworkError(network)
|
|
}
|
|
return network, 0, nil
|
|
}
|
|
afnet = network[:i]
|
|
switch afnet {
|
|
case "ip", "ip4", "ip6":
|
|
protostr := network[i+1:]
|
|
proto, i, ok := dtoi(protostr)
|
|
if !ok || i != len(protostr) {
|
|
proto, err = lookupProtocol(ctx, protostr)
|
|
if err != nil {
|
|
return "", 0, err
|
|
}
|
|
}
|
|
return afnet, proto, nil
|
|
}
|
|
return "", 0, UnknownNetworkError(network)
|
|
}
|
|
|
|
// Listen announces on the local network address.
|
|
//
|
|
// See Go "net" package Listen() for more information.
|
|
//
|
|
// Note: Tinygo Listen supports a subset of networks supported by Go Listen,
|
|
// specifically: "tcp", "tcp4". "tcp6" and unix networks are not supported.
|
|
func Listen(network, address string) (Listener, error) {
|
|
|
|
// println("Listen", address)
|
|
switch network {
|
|
case "tcp", "tcp4":
|
|
default:
|
|
return nil, fmt.Errorf("Network %s not supported", network)
|
|
}
|
|
|
|
laddr, err := ResolveTCPAddr(network, address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return listenTCP(laddr)
|
|
}
|
|
|
|
// ListenPacket announces on the local network address.
|
|
//
|
|
// TINYGO: only UDP networks are supported, backed by ListenUDP; the
|
|
// returned PacketConn is a *UDPConn.
|
|
func ListenPacket(network, address string) (PacketConn, error) {
|
|
switch network {
|
|
case "udp", "udp4":
|
|
default:
|
|
return nil, fmt.Errorf("Network %s not supported", network)
|
|
}
|
|
|
|
laddr, err := ResolveUDPAddr(network, address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return ListenUDP(network, laddr)
|
|
}
|