diff options
author | Max Kellermann <max@duempel.org> | 2011-09-20 07:56:59 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2011-09-20 08:49:36 +0200 |
commit | 3ea1073809bf324e5b75fd33d61dcb0422463358 (patch) | |
tree | 2fdb6aee5783b2ea88aa10089e2708d1fadb6977 /src/resolver.c | |
parent | 76a959a578c1039235988d886bcf335fff0c85f1 (diff) | |
download | mpd-3ea1073809bf324e5b75fd33d61dcb0422463358.tar.gz mpd-3ea1073809bf324e5b75fd33d61dcb0422463358.tar.xz mpd-3ea1073809bf324e5b75fd33d61dcb0422463358.zip |
socket_util: move sockaddr_to_string() to resolver.c
Diffstat (limited to '')
-rw-r--r-- | src/resolver.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/src/resolver.c b/src/resolver.c new file mode 100644 index 000000000..81099b2af --- /dev/null +++ b/src/resolver.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "resolver.h" + +#ifndef G_OS_WIN32 +#include <sys/socket.h> +#include <netdb.h> +#else /* G_OS_WIN32 */ +#define WINVER 0x0501 +#include <ws2tcpip.h> +#include <winsock.h> +#endif /* G_OS_WIN32 */ + +#ifdef HAVE_IPV6 +#include <string.h> +#endif + +char * +sockaddr_to_string(const struct sockaddr *sa, size_t length, GError **error) +{ +#if defined(HAVE_IPV6) && defined(IN6_IS_ADDR_V4MAPPED) + const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *)sa; + struct sockaddr_in a4; +#endif + int ret; + char host[NI_MAXHOST], serv[NI_MAXSERV]; + +#if defined(HAVE_IPV6) && defined(IN6_IS_ADDR_V4MAPPED) + if (sa->sa_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr)) { + /* convert "::ffff:127.0.0.1" to "127.0.0.1" */ + + memset(&a4, 0, sizeof(a4)); + a4.sin_family = AF_INET; + memcpy(&a4.sin_addr, ((const char *)&a6->sin6_addr) + 12, + sizeof(a4.sin_addr)); + a4.sin_port = a6->sin6_port; + + sa = (const struct sockaddr *)&a4; + length = sizeof(a4); + } +#endif + + ret = getnameinfo(sa, length, host, sizeof(host), serv, sizeof(serv), + NI_NUMERICHOST|NI_NUMERICSERV); + if (ret != 0) { + g_set_error(error, g_quark_from_static_string("netdb"), ret, + "%s", gai_strerror(ret)); + return NULL; + } + +#ifdef HAVE_UN + if (sa->sa_family == AF_UNIX) + /* "serv" contains corrupt information with unix + sockets */ + return g_strdup(host); +#endif + +#ifdef HAVE_IPV6 + if (strchr(host, ':') != NULL) + return g_strconcat("[", host, "]:", serv, NULL); +#endif + + return g_strconcat(host, ":", serv, NULL); +} |