+static void nfs_set_port(struct sockaddr *sap, const unsigned short port)
+{
+ switch (sap->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)sap)->sin_port = htons(port);
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
+ break;
+ default:
+ nfs_error(_("%s: unrecognized address family in %s"),
+ progname, __func__);
+ }
+}
+
+#ifdef HAVE_DECL_AI_ADDRCONFIG
+/**
+ * nfs_name_to_address - resolve hostname to an IPv4 or IPv6 socket address
+ * @hostname: pointer to C string containing DNS hostname to resolve
+ * @af_hint: hint to restrict resolution to one address family
+ * @sap: pointer to buffer to fill with socket address
+ * @len: IN: size of buffer to fill; OUT: size of socket address
+ *
+ * Returns 1 and places a socket address at @sap if successful;
+ * otherwise zero.
+ */
+int nfs_name_to_address(const char *hostname,
+ const sa_family_t af_hint,
+ struct sockaddr *sap, socklen_t *salen)
+{
+ struct addrinfo *gai_results;
+ struct addrinfo gai_hint = {
+ .ai_family = af_hint,
+ .ai_flags = AI_ADDRCONFIG,
+ };
+ socklen_t len = *salen;
+ int error, ret = 0;
+
+ if (af_hint == AF_INET6)
+ gai_hint.ai_flags |= AI_V4MAPPED|AI_ALL;
+
+ *salen = 0;
+
+ error = getaddrinfo(hostname, NULL, &gai_hint, &gai_results);
+ if (error) {
+ nfs_error(_("%s: DNS resolution failed for %s: %s"),
+ progname, hostname, (error == EAI_SYSTEM ?
+ strerror(errno) : gai_strerror(error)));
+ return ret;
+ }
+
+ switch (gai_results->ai_addr->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ if (len >= gai_results->ai_addrlen) {
+ *salen = gai_results->ai_addrlen;
+ memcpy(sap, gai_results->ai_addr, *salen);
+ ret = 1;
+ }
+ break;
+ default:
+ /* things are really broken if we get here, so warn */
+ nfs_error(_("%s: unrecognized DNS resolution results for %s"),
+ progname, hostname);
+ break;
+ }
+
+ freeaddrinfo(gai_results);
+ return ret;
+}
+#else /* HAVE_DECL_AI_ADDRCONFIG */
+/**
+ * nfs_name_to_address - resolve hostname to an IPv4 socket address
+ * @hostname: pointer to C string containing DNS hostname to resolve
+ * @af_hint: hint to restrict resolution to one address family
+ * @sap: pointer to buffer to fill with socket address
+ * @len: IN: size of buffer to fill; OUT: size of socket address
+ *
+ * Returns 1 and places a socket address at @sap if successful;
+ * otherwise zero.
+ *
+ * Some older getaddrinfo(3) implementations don't support
+ * AI_ADDRCONFIG or AI_V4MAPPED properly. For those cases, a DNS
+ * resolver based on the traditional gethostbyname(3) is provided.
+ */
+int nfs_name_to_address(const char *hostname,
+ const sa_family_t af_hint,
+ struct sockaddr *sap, socklen_t *salen)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+ socklen_t len = *salen;
+ struct hostent *hp;
+
+ *salen = 0;
+
+ if (af_hint != AF_INET) {
+ nfs_error(_("%s: address family not supported by DNS resolver\n"),
+ progname, hostname);
+ return 0;
+ }
+
+ sin->sin_family = AF_INET;
+ if (inet_aton(hostname, &sin->sin_addr)) {
+ *salen = sizeof(*sin);
+ return 1;
+ }
+
+ hp = gethostbyname(hostname);
+ if (hp == NULL) {
+ nfs_error(_("%s: DNS resolution failed for %s: %s"),
+ progname, hostname, hstrerror(h_errno));
+ return 0;
+ }
+
+ if (hp->h_length > len) {
+ nfs_error(_("%s: DNS resolution results too long for buffer\n"),
+ progname);
+ return 0;
+ }
+
+ memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
+ *salen = sizeof(struct sockaddr_in);
+ return 1;
+}
+#endif /* HAVE_DECL_AI_ADDRCONFIG */
+