From e1901e97c2f3f6901ca7bac31a68ac9da1e3a4ee Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Wed, 4 Dec 2013 08:43:55 +0100
Subject: [PATCH] system/Resolver: sockaddr_to_string() returns std::string()

No GLib memory allocation.
---
 src/ClientNew.cxx                | 17 ++++------------
 src/event/ServerSocket.cxx       | 33 +++++++++++---------------------
 src/output/HttpdOutputPlugin.cxx | 11 +++--------
 src/system/Resolver.cxx          | 28 ++++++++++++++++-----------
 src/system/Resolver.hxx          | 13 ++++++-------
 test/run_resolver.cxx            | 12 ++----------
 6 files changed, 43 insertions(+), 71 deletions(-)

diff --git a/src/ClientNew.cxx b/src/ClientNew.cxx
index 1bcc2f4d3..5618e9ece 100644
--- a/src/ClientNew.cxx
+++ b/src/ClientNew.cxx
@@ -28,8 +28,6 @@
 #include "util/Error.hxx"
 #include "Log.hxx"
 
-#include <glib.h>
-
 #include <assert.h>
 #ifdef WIN32
 #include <winsock2.h>
@@ -63,15 +61,12 @@ client_new(EventLoop &loop, Partition &partition,
 	   int fd, const struct sockaddr *sa, size_t sa_length, int uid)
 {
 	static unsigned int next_client_num;
-	char *remote;
+	const auto remote = sockaddr_to_string(sa, sa_length);
 
 	assert(fd >= 0);
 
 #ifdef HAVE_LIBWRAP
 	if (sa->sa_family != AF_UNIX) {
-		char *hostaddr = sockaddr_to_string(sa, sa_length,
-						    IgnoreError());
-
 		// TODO: shall we obtain the program name from argv[0]?
 		const char *progname = "mpd";
 
@@ -84,14 +79,11 @@ client_new(EventLoop &loop, Partition &partition,
 			/* tcp wrappers says no */
 			FormatWarning(client_domain,
 				      "libwrap refused connection (libwrap=%s) from %s",
-				      progname, hostaddr);
+				      progname, remote.c_str());
 
-			g_free(hostaddr);
 			close_socket(fd);
 			return;
 		}
-
-		g_free(hostaddr);
 	}
 #endif	/* HAVE_WRAP */
 
@@ -109,9 +101,8 @@ client_new(EventLoop &loop, Partition &partition,
 
 	client_list.Add(*client);
 
-	remote = sockaddr_to_string(sa, sa_length, IgnoreError());
-	FormatInfo(client_domain, "[%u] opened from %s", client->num, remote);
-	g_free(remote);
+	FormatInfo(client_domain, "[%u] opened from %s",
+		   client->num, remote.c_str());
 }
 
 void
diff --git a/src/event/ServerSocket.cxx b/src/event/ServerSocket.cxx
index 72320b3eb..a05d7bde2 100644
--- a/src/event/ServerSocket.cxx
+++ b/src/event/ServerSocket.cxx
@@ -107,7 +107,10 @@ public:
 	using SocketMonitor::IsDefined;
 	using SocketMonitor::Close;
 
-	char *ToString() const;
+	gcc_pure
+	std::string ToString() const {
+		return sockaddr_to_string(address, address_length);
+	}
 
 	void SetFD(int _fd) {
 		SocketMonitor::Open(_fd);
@@ -122,18 +125,6 @@ private:
 
 static constexpr Domain server_socket_domain("server_socket");
 
-/**
- * Wraper for sockaddr_to_string() which never fails.
- */
-char *
-OneServerSocket::ToString() const
-{
-	char *p = sockaddr_to_string(address, address_length, IgnoreError());
-	if (p == nullptr)
-		p = g_strdup("[unknown]");
-	return p;
-}
-
 static int
 get_remote_uid(int fd)
 {
@@ -243,23 +234,21 @@ ServerSocket::Open(Error &error)
 		Error error2;
 		if (!i.Open(error2)) {
 			if (good != nullptr && good->GetSerial() == i.GetSerial()) {
-				char *address_string = i.ToString();
-				char *good_string = good->ToString();
+				const auto address_string = i.ToString();
+				const auto good_string = good->ToString();
 				FormatWarning(server_socket_domain,
 					      "bind to '%s' failed: %s "
 					      "(continuing anyway, because "
 					      "binding to '%s' succeeded)",
-					      address_string, error2.GetMessage(),
-					      good_string);
-				g_free(address_string);
-				g_free(good_string);
+					      address_string.c_str(),
+					      error2.GetMessage(),
+					      good_string.c_str());
 			} else if (bad == nullptr) {
 				bad = &i;
 
-				char *address_string = i.ToString();
+				const auto address_string = i.ToString();
 				error2.FormatPrefix("Failed to bind to '%s': ",
-						    address_string);
-				g_free(address_string);
+						    address_string.c_str());
 
 				last_error = std::move(error2);
 			}
diff --git a/src/output/HttpdOutputPlugin.cxx b/src/output/HttpdOutputPlugin.cxx
index 1d80011dd..8cbc150ad 100644
--- a/src/output/HttpdOutputPlugin.cxx
+++ b/src/output/HttpdOutputPlugin.cxx
@@ -33,8 +33,6 @@
 #include "util/Domain.hxx"
 #include "Log.hxx"
 
-#include <glib.h>
-
 #include <assert.h>
 
 #include <sys/types.h>
@@ -199,8 +197,8 @@ HttpdOutput::OnAccept(int fd, const sockaddr &address,
 
 #ifdef HAVE_LIBWRAP
 	if (address.sa_family != AF_UNIX) {
-		char *hostaddr = sockaddr_to_string(&address, address_length,
-						    IgnoreError());
+		const auto hostaddr = sockaddr_to_string(&address,
+							 address_length);
 		// TODO: shall we obtain the program name from argv[0]?
 		const char *progname = "mpd";
 
@@ -213,13 +211,10 @@ HttpdOutput::OnAccept(int fd, const sockaddr &address,
 			/* tcp wrappers says no */
 			FormatWarning(httpd_output_domain,
 				      "libwrap refused connection (libwrap=%s) from %s",
-				      progname, hostaddr);
-			g_free(hostaddr);
+				      progname, hostaddr.c_str());
 			close_socket(fd);
 			return;
 		}
-
-		g_free(hostaddr);
 	}
 #else
 	(void)address;
diff --git a/src/system/Resolver.cxx b/src/system/Resolver.cxx
index 8f4f4dcda..6e0870403 100644
--- a/src/system/Resolver.cxx
+++ b/src/system/Resolver.cxx
@@ -44,17 +44,17 @@
 
 const Domain resolver_domain("resolver");
 
-char *
-sockaddr_to_string(const struct sockaddr *sa, size_t length, Error &error)
+std::string
+sockaddr_to_string(const struct sockaddr *sa, size_t length)
 {
 #ifdef HAVE_UN
 	if (sa->sa_family == AF_UNIX) {
 		/* return path of UNIX domain sockets */
 		const sockaddr_un &s_un = *(const sockaddr_un *)sa;
 		if (length < sizeof(s_un) || s_un.sun_path[0] == 0)
-			return g_strdup("local");
+			return "local";
 
-		return g_strdup(s_un.sun_path);
+		return s_un.sun_path;
 	}
 #endif
 
@@ -83,17 +83,23 @@ sockaddr_to_string(const struct sockaddr *sa, size_t length, Error &error)
 
 	ret = getnameinfo(sa, length, host, sizeof(host), serv, sizeof(serv),
 			  NI_NUMERICHOST|NI_NUMERICSERV);
-	if (ret != 0) {
-		error.Set(resolver_domain, ret, gai_strerror(ret));
-		return NULL;
-	}
+	if (ret != 0)
+		return "unknown";
 
 #ifdef HAVE_IPV6
-	if (strchr(host, ':') != NULL)
-		return g_strconcat("[", host, "]:", serv, NULL);
+	if (strchr(host, ':') != NULL) {
+		std::string result("[");
+		result.append(host);
+		result.append("]:");
+		result.append(serv);
+		return result;
+	}
 #endif
 
-	return g_strconcat(host, ":", serv, NULL);
+	std::string result(host);
+	result.push_back(':');
+	result.append(serv);
+	return result;
 }
 
 struct addrinfo *
diff --git a/src/system/Resolver.hxx b/src/system/Resolver.hxx
index ec557d1a0..044d3f96a 100644
--- a/src/system/Resolver.hxx
+++ b/src/system/Resolver.hxx
@@ -22,6 +22,8 @@
 
 #include "Compiler.h"
 
+#include <string>
+
 #include <stddef.h>
 
 struct sockaddr;
@@ -33,17 +35,14 @@ extern const Domain resolver_domain;
 
 /**
  * Converts the specified socket address into a string in the form
- * "IP:PORT".  The return value must be freed with g_free() when you
- * don't need it anymore.
+ * "IP:PORT".
  *
  * @param sa the sockaddr struct
  * @param length the length of #sa in bytes
- * @param error location to store the error occurring, or NULL to
- * ignore errors
  */
-gcc_malloc
-char *
-sockaddr_to_string(const sockaddr *sa, size_t length, Error &error);
+gcc_pure
+std::string
+sockaddr_to_string(const sockaddr *sa, size_t length);
 
 /**
  * Resolve a specification in the form "host", "host:port",
diff --git a/test/run_resolver.cxx b/test/run_resolver.cxx
index 7da2fd5b2..65c55b4df 100644
--- a/test/run_resolver.cxx
+++ b/test/run_resolver.cxx
@@ -51,16 +51,8 @@ int main(int argc, char **argv)
 	}
 
 	for (const struct addrinfo *i = ai; i != NULL; i = i->ai_next) {
-		char *p = sockaddr_to_string(i->ai_addr, i->ai_addrlen,
-					     error);
-		if (p == NULL) {
-			freeaddrinfo(ai);
-			LogError(error);
-			return EXIT_FAILURE;
-		}
-
-		g_print("%s\n", p);
-		g_free(p);
+		const auto s = sockaddr_to_string(i->ai_addr, i->ai_addrlen);
+		g_print("%s\n", s.c_str());
 	}
 
 	freeaddrinfo(ai);