code: func (m *Memberlist) resolveAddr(hostStr string) ([]ipPort, error) {
  	// This captures the supplied port, or the default one.
  	hostStr = ensurePort(hostStr, m.config.BindPort)
  	host, sport, err := net.SplitHostPort(hostStr)
  	if err != nil {
  		return nil, err
  	}
  	lport, err := strconv.ParseUint(sport, 10, 16)
  	if err != nil {
  		return nil, err
  	}
  	port := uint16(lport)
  
  	// If it looks like an IP address we are done. The SplitHostPort() above
  	// will make sure the host part is in good shape for parsing, even for
  	// IPv6 addresses.
  	if ip := net.ParseIP(host); ip != nil {
  		return []ipPort{ipPort{ip, port}}, nil
  	}
  
  	// First try TCP so we have the best chance for the largest list of
  	// hosts to join. If this fails it's not fatal since this isn't a standard
  	// way to query DNS, and we have a fallback below.
  	ips, err := m.tcpLookupIP(host, port)
  	if err != nil {
  		m.logger.Printf("[DEBUG] memberlist: TCP-first lookup failed for '%s', falling back to UDP: %s", hostStr, err)
  	}
  	if len(ips) > 0 {
  		return ips, nil
  	}
  
  	// If TCP didn't yield anything then use the normal Go resolver which
  	// will try UDP, then might possibly try TCP again if the UDP response
  	// indicates it was truncated.
  	ans, err := net.LookupIP(host)
  	if err != nil {
  		return nil, err
  	}
  	ips = make([]ipPort, 0, len(ans))
  	for _, ip := range ans {
  		ips = append(ips, ipPort{ip, port})
  	}
  	return ips, nil
  }
docs: // resolveAddr is used to resolve the address into an address,
  // port, and error. If no port is given, use the default