func addr(prot pb.CreateSocketRequest_SocketProtocol, ap *pb.AddressPort) net.Addr { if ap == nil { return nil } switch prot { case pb.CreateSocketRequest_TCP: return &net.TCPAddr{ IP: net.IP(ap.PackedAddress), Port: int(*ap.Port), } case pb.CreateSocketRequest_UDP: return &net.UDPAddr{ IP: net.IP(ap.PackedAddress), Port: int(*ap.Port), } } panic("unknown protocol " + prot.String()) }
// DialTimeout is like Dial but takes a timeout. // The timeout includes name resolution, if required. func DialTimeout(ctx context.Context, protocol, addr string, timeout time.Duration) (*Conn, error) { dialCtx := ctx // Used for dialing and name resolution, but not stored in the *Conn. if timeout > 0 { var cancel context.CancelFunc dialCtx, cancel = context.WithTimeout(ctx, timeout) defer cancel() } host, portStr, err := net.SplitHostPort(addr) if err != nil { return nil, err } port, err := strconv.Atoi(portStr) if err != nil { return nil, fmt.Errorf("socket: bad port %q: %v", portStr, err) } var prot pb.CreateSocketRequest_SocketProtocol switch protocol { case "tcp": prot = pb.CreateSocketRequest_TCP case "udp": prot = pb.CreateSocketRequest_UDP default: return nil, fmt.Errorf("socket: unknown protocol %q", protocol) } packedAddrs, resolved, err := resolve(dialCtx, ipFamilies, host) if err != nil { return nil, fmt.Errorf("socket: failed resolving %q: %v", host, err) } if len(packedAddrs) == 0 { return nil, fmt.Errorf("no addresses for %q", host) } packedAddr := packedAddrs[0] // use first address fam := pb.CreateSocketRequest_IPv4 if len(packedAddr) == net.IPv6len { fam = pb.CreateSocketRequest_IPv6 } req := &pb.CreateSocketRequest{ Family: fam.Enum(), Protocol: prot.Enum(), RemoteIp: &pb.AddressPort{ Port: proto.Int32(int32(port)), PackedAddress: packedAddr, }, } if resolved { req.RemoteIp.HostnameHint = &host } res := &pb.CreateSocketReply{} if err := internal.Call(dialCtx, "remote_socket", "CreateSocket", req, res); err != nil { return nil, err } return &Conn{ ctx: ctx, desc: res.GetSocketDescriptor(), prot: prot, local: res.ProxyExternalIp, remote: req.RemoteIp, }, nil }