(ctx context.Context, network, address string)
| 955 | var protoSplitter = regexp.MustCompile(`^(tcp|udp|ping)(4|6)?$`) |
| 956 | |
| 957 | func (tnet *Net) DialContext(ctx context.Context, network, address string) (net.Conn, error) { |
| 958 | if ctx == nil { |
| 959 | panic("nil context") |
| 960 | } |
| 961 | var acceptV4, acceptV6 bool |
| 962 | matches := protoSplitter.FindStringSubmatch(network) |
| 963 | if matches == nil { |
| 964 | return nil, &net.OpError{Op: "dial", Err: net.UnknownNetworkError(network)} |
| 965 | } else if len(matches[2]) == 0 { |
| 966 | acceptV4 = true |
| 967 | acceptV6 = true |
| 968 | } else { |
| 969 | acceptV4 = matches[2][0] == '4' |
| 970 | acceptV6 = !acceptV4 |
| 971 | } |
| 972 | var host string |
| 973 | var port int |
| 974 | if matches[1] == "ping" { |
| 975 | host = address |
| 976 | } else { |
| 977 | var sport string |
| 978 | var err error |
| 979 | host, sport, err = net.SplitHostPort(address) |
| 980 | if err != nil { |
| 981 | return nil, &net.OpError{Op: "dial", Err: err} |
| 982 | } |
| 983 | port, err = strconv.Atoi(sport) |
| 984 | if err != nil || port < 0 || port > 65535 { |
| 985 | return nil, &net.OpError{Op: "dial", Err: errNumericPort} |
| 986 | } |
| 987 | } |
| 988 | allAddr, err := tnet.LookupContextHost(ctx, host) |
| 989 | if err != nil { |
| 990 | return nil, &net.OpError{Op: "dial", Err: err} |
| 991 | } |
| 992 | var addrs []netip.AddrPort |
| 993 | for _, addr := range allAddr { |
| 994 | ip, err := netip.ParseAddr(addr) |
| 995 | if err == nil && ((ip.Is4() && acceptV4) || (ip.Is6() && acceptV6)) { |
| 996 | addrs = append(addrs, netip.AddrPortFrom(ip, uint16(port))) |
| 997 | } |
| 998 | } |
| 999 | if len(addrs) == 0 && len(allAddr) != 0 { |
| 1000 | return nil, &net.OpError{Op: "dial", Err: errNoSuitableAddress} |
| 1001 | } |
| 1002 | |
| 1003 | var firstErr error |
| 1004 | for i, addr := range addrs { |
| 1005 | select { |
| 1006 | case <-ctx.Done(): |
| 1007 | err := ctx.Err() |
| 1008 | if err == context.Canceled { |
| 1009 | err = errCanceled |
| 1010 | } else if err == context.DeadlineExceeded { |
| 1011 | err = errTimeout |
| 1012 | } |
| 1013 | return nil, &net.OpError{Op: "dial", Err: err} |
| 1014 | default: |
no test coverage detected