diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/event/ServerSocket.cxx | 10 | ||||
-rw-r--r-- | src/net/AddressInfo.cxx | 81 | ||||
-rw-r--r-- | src/net/AddressInfo.hxx | 142 | ||||
-rw-r--r-- | src/net/HostParser.cxx | 140 | ||||
-rw-r--r-- | src/net/HostParser.hxx | 76 | ||||
-rw-r--r-- | src/net/Resolver.cxx | 181 | ||||
-rw-r--r-- | src/net/Resolver.hxx | 69 | ||||
-rw-r--r-- | test/run_resolver.cxx | 18 |
9 files changed, 613 insertions, 106 deletions
diff --git a/Makefile.am b/Makefile.am index 30ba26786..db18baf69 100644 --- a/Makefile.am +++ b/Makefile.am @@ -594,7 +594,9 @@ libnet_a_SOURCES = \ src/net/Features.hxx \ src/net/Init.hxx \ src/net/ToString.cxx src/net/ToString.hxx \ + src/net/HostParser.cxx src/net/HostParser.hxx \ src/net/Resolver.cxx src/net/Resolver.hxx \ + src/net/AddressInfo.cxx src/net/AddressInfo.hxx \ src/net/StaticSocketAddress.cxx src/net/StaticSocketAddress.hxx \ src/net/AllocatedSocketAddress.cxx src/net/AllocatedSocketAddress.hxx \ src/net/IPv4Address.cxx src/net/IPv4Address.hxx \ diff --git a/src/event/ServerSocket.cxx b/src/event/ServerSocket.cxx index 67919b913..e2a97f5cb 100644 --- a/src/event/ServerSocket.cxx +++ b/src/event/ServerSocket.cxx @@ -27,6 +27,7 @@ #include "net/SocketError.hxx" #include "net/UniqueSocketDescriptor.hxx" #include "net/Resolver.hxx" +#include "net/AddressInfo.hxx" #include "net/ToString.hxx" #include "event/SocketMonitor.hxx" #include "fs/AllocatedPath.hxx" @@ -369,12 +370,9 @@ void ServerSocket::AddHost(const char *hostname, unsigned port) { #ifdef HAVE_TCP - struct addrinfo *ai = resolve_host_port(hostname, port, - AI_PASSIVE, SOCK_STREAM); - AtScopeExit(ai) { freeaddrinfo(ai); }; - - for (const struct addrinfo *i = ai; i != nullptr; i = i->ai_next) - AddAddress(SocketAddress(i->ai_addr, i->ai_addrlen)); + for (const auto &i : Resolve(hostname, port, + AI_PASSIVE, SOCK_STREAM)) + AddAddress(i); ++next_serial; #else /* HAVE_TCP */ diff --git a/src/net/AddressInfo.cxx b/src/net/AddressInfo.cxx new file mode 100644 index 000000000..100214d8d --- /dev/null +++ b/src/net/AddressInfo.cxx @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016-2017 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AddressInfo.hxx" + +#include <assert.h> + +static constexpr int address_family_ranking[] = { +#ifdef HAVE_UN + AF_LOCAL, +#endif + AF_INET6, +}; + +static bool +IsAddressFamilyBetter(int previous, int next) +{ + for (auto i : address_family_ranking) { + if (next == i) + return previous != i; + if (previous == i) + return false; + } + + return false; +} + +static bool +IsBetter(const AddressInfo &previous, const AddressInfo &next) +{ + return IsAddressFamilyBetter(previous.GetFamily(), + next.GetFamily()); +} + +static bool +IsBetter(const AddressInfo *previous, const AddressInfo &next) +{ + return previous == nullptr || IsBetter(*previous, next); +} + +const AddressInfo & +AddressInfoList::GetBest() const +{ + assert(!empty()); + + const AddressInfo *best = nullptr; + + for (const auto &i : *this) + if (IsBetter(best, i)) + best = &i; + + assert(best != nullptr); + return *best; +} diff --git a/src/net/AddressInfo.hxx b/src/net/AddressInfo.hxx new file mode 100644 index 000000000..63f8ebe64 --- /dev/null +++ b/src/net/AddressInfo.hxx @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2016-2017 Max Kellermann <max.kellermann@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NET_ADDRESS_INFO_HXX +#define NET_ADDRESS_INFO_HXX + +#include "SocketAddress.hxx" + +#include <algorithm> +#include <utility> + +#ifdef _WIN32 +#include <ws2tcpip.h> +#else +#include <netdb.h> +#endif + +class AddressInfo : addrinfo { + /* this class cannot be instantiated, it can only be cast from + a struct addrinfo pointer */ + AddressInfo() = delete; + ~AddressInfo() = delete; + +public: + constexpr int GetFamily() const { + return ai_family; + } + + constexpr int GetType() const { + return ai_socktype; + } + + constexpr int GetProtocol() const { + return ai_protocol; + } + + constexpr operator SocketAddress() const { + return {ai_addr, (SocketAddress::size_type)ai_addrlen}; + } +}; + +class AddressInfoList { + struct addrinfo *value = nullptr; + +public: + AddressInfoList() = default; + explicit AddressInfoList(struct addrinfo *_value):value(_value) {} + + AddressInfoList(AddressInfoList &&src) + :value(std::exchange(src.value, nullptr)) {} + + ~AddressInfoList() { + freeaddrinfo(value); + } + + AddressInfoList &operator=(AddressInfoList &&src) { + std::swap(value, src.value); + return *this; + } + + bool empty() const { + return value == nullptr; + } + + const AddressInfo &front() const { + return *(const AddressInfo *)value; + } + + /** + * Pick the best address from the list, e.g. prefer IPv6 over + * IPv4 (if both are available). We do this because binding + * to an IPv6 wildcard address also allows accepting IPv4 + * connections. + */ + gcc_pure + const AddressInfo &GetBest() const; + + class const_iterator { + struct addrinfo *cursor; + + public: + explicit constexpr const_iterator(struct addrinfo *_cursor) + :cursor(_cursor) {} + + constexpr bool operator==(const_iterator other) const { + return cursor == other.cursor; + } + + constexpr bool operator!=(const_iterator other) const { + return cursor != other.cursor; + } + + const_iterator &operator++() { + cursor = cursor->ai_next; + return *this; + } + + constexpr const AddressInfo &operator*() const { + return *(const AddressInfo *)cursor; + } + + constexpr const AddressInfo *operator->() const { + return (const AddressInfo *)cursor; + } + }; + + const_iterator begin() const { + return const_iterator(value); + } + + const_iterator end() const { + return const_iterator(nullptr); + } +}; + +#endif diff --git a/src/net/HostParser.cxx b/src/net/HostParser.cxx new file mode 100644 index 000000000..18bc986b3 --- /dev/null +++ b/src/net/HostParser.cxx @@ -0,0 +1,140 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "HostParser.hxx" +#include "util/CharUtil.hxx" + +#include <string.h> + +static inline bool +IsValidHostnameChar(char ch) +{ + return IsAlphaNumericASCII(ch) || + ch == '-' || ch == '.' || + ch == '*'; /* for wildcards */ +} + +static inline bool +IsValidScopeChar(char ch) +{ + return IsAlphaNumericASCII(ch) || + ch == '-' || ch == '_'; +} + +static const char * +FindScopeEnd(const char *p) +{ + if (*p == '%' && IsValidScopeChar(p[1])) { + p += 2; + while (IsValidScopeChar(*p)) + ++p; + } + + return p; +} + +static inline bool +IsValidIPv6Char(char ch) +{ + return IsDigitASCII(ch) || + (ch >= 'a' && ch <= 'f') || + (ch >= 'A' && ch <= 'F') || + ch == ':'; +} + +static const char * +FindIPv6End(const char *p) +{ + while (IsValidIPv6Char(*p)) + ++p; + + /* allow "%scope" after numeric IPv6 address */ + p = FindScopeEnd(p); + + return p; +} + +ExtractHostResult +ExtractHost(const char *src) +{ + ExtractHostResult result{nullptr, src}; + const char *hostname; + + if (IsValidHostnameChar(*src)) { + const char *colon = nullptr; + + hostname = src++; + + while (IsValidHostnameChar(*src) || *src == ':') { + if (*src == ':') { + if (colon != nullptr) { + /* found a second colon: assume it's an IPv6 + address */ + result.end = FindIPv6End(src + 1); + result.host = {hostname, result.end}; + return result; + } else + /* remember the position of the first colon */ + colon = src; + } + + ++src; + } + + if (colon != nullptr) + /* hostname ends at colon */ + src = colon; + + result.end = src; + result.host = {hostname, result.end}; + } else if (src[0] == ':' && src[1] == ':') { + /* IPv6 address beginning with "::" */ + result.end = FindIPv6End(src + 2); + result.host = {src, result.end}; + } else if (src[0] == '[') { + /* "[hostname]:port" (IPv6?) */ + + hostname = ++src; + const char *end = strchr(hostname, ']'); + if (end == nullptr || end == hostname) + /* failed, return nullptr */ + return result; + + result.host = {hostname, end}; + result.end = end + 1; + } else { + /* failed, return nullptr */ + } + + return result; +} diff --git a/src/net/HostParser.hxx b/src/net/HostParser.hxx new file mode 100644 index 000000000..0166feadf --- /dev/null +++ b/src/net/HostParser.hxx @@ -0,0 +1,76 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: Max Kellermann <mk@cm4all.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NET_HOST_PARSER_HXX +#define NET_HOST_PARSER_HXX + +#include "util/StringView.hxx" +#include "util/Compiler.h" + +/** + * Result type for ExtractHost(). + */ +struct ExtractHostResult { + /** + * The host part of the address. + * + * If nothing was parsed, then this is nullptr. + */ + StringView host; + + /** + * Pointer to the first character that was not parsed. On + * success, this is usually a pointer to the zero terminator or to + * a colon followed by a port number. + * + * If nothing was parsed, then this is a pointer to the given + * source string. + */ + const char *end; + + constexpr bool HasFailed() const { + return host == nullptr; + } +}; + +/** + * Extract the host from a string in the form "IP:PORT" or + * "[IPv6]:PORT". Stops at the first invalid character (e.g. the + * colon). + * + * @param src the input string + */ +gcc_pure +ExtractHostResult +ExtractHost(const char *src); + +#endif diff --git a/src/net/Resolver.cxx b/src/net/Resolver.cxx index 160447e03..2eeddc7aa 100644 --- a/src/net/Resolver.cxx +++ b/src/net/Resolver.cxx @@ -1,91 +1,160 @@ /* - * Copyright 2003-2017 The Music Player Daemon Project - * http://www.musicpd.org + * Copyright 2007-2017 Content Management AG + * All rights reserved. * - * 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. + * author: Max Kellermann <mk@cm4all.com> * - * 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. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * 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. + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "Resolver.hxx" +#include "AddressInfo.hxx" +#include "HostParser.hxx" #include "util/RuntimeError.hxx" - -#include <string> +#include "util/CharUtil.hxx" #ifdef _WIN32 #include <ws2tcpip.h> #else -#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> +#include <net/if.h> #endif #include <string.h> #include <stdio.h> +#include <errno.h> -struct addrinfo * -resolve_host_port(const char *host_port, unsigned default_port, - int flags, int socktype) +static inline bool +ai_is_passive(const struct addrinfo *ai) { - std::string p(host_port); - const char *host = p.c_str(), *port = nullptr; - - if (host_port[0] == '[') { - /* IPv6 needs enclosing square braces, to - differentiate between IP colons and the port - separator */ - - size_t q = p.find(']', 1); - if (q != p.npos && p[q + 1] == ':' && p[q + 2] != 0) { - p[q] = 0; - port = host + q + 2; - ++host; - } - } + return ai == nullptr || (ai->ai_flags & AI_PASSIVE) != 0; +} + +#ifndef _WIN32 + +/** + * Check if there is an interface name after '%', and if so, replace + * it with the interface index, because getaddrinfo() understands only + * the index, not the name (tested on Linux/glibc). + */ +static void +FindAndResolveInterfaceName(char *host, size_t size) +{ + char *percent = strchr(host, '%'); + if (percent == nullptr || percent + 64 > host + size) + return; - if (port == nullptr) { - /* port is after the colon, but only if it's the only - colon (don't split IPv6 addresses) */ + char *interface = percent + 1; + if (!IsAlphaASCII(*interface)) + return; - auto q = p.find(':'); - if (q != p.npos && p[q + 1] != 0 && - p.find(':', q + 1) == p.npos) { - p[q] = 0; - port = host + q + 1; + const unsigned i = if_nametoindex(interface); + if (i == 0) + throw FormatRuntimeError("No such interface: %s", interface); + + sprintf(interface, "%u", i); +} + +#endif + +static int +Resolve(const char *host_and_port, int default_port, + const struct addrinfo *hints, + struct addrinfo **ai_r) +{ + const char *host, *port; + char buffer[256], port_string[16]; + + if (host_and_port != nullptr) { + const auto eh = ExtractHost(host_and_port); + if (eh.HasFailed()) + return EAI_NONAME; + + if (eh.host.size >= sizeof(buffer)) { +#ifdef _WIN32 + return EAI_MEMORY; +#else + errno = ENAMETOOLONG; + return EAI_SYSTEM; +#endif } - } - char buffer[32]; - if (port == nullptr && default_port != 0) { - snprintf(buffer, sizeof(buffer), "%u", default_port); - port = buffer; - } + memcpy(buffer, eh.host.data, eh.host.size); + buffer[eh.host.size] = 0; + host = buffer; - if ((flags & AI_PASSIVE) != 0 && strcmp(host, "*") == 0) +#ifndef _WIN32 + FindAndResolveInterfaceName(buffer, sizeof(buffer)); +#endif + + port = eh.end; + if (*port == ':') { + /* port specified */ + ++port; + } else if (*port == 0) { + /* no port specified */ + snprintf(port_string, sizeof(port_string), "%d", default_port); + port = port_string; + } else + throw std::runtime_error("Garbage after host name"); + + if (ai_is_passive(hints) && strcmp(host, "*") == 0) + host = nullptr; + } else { host = nullptr; + snprintf(port_string, sizeof(port_string), "%d", default_port); + port = port_string; + } + + return getaddrinfo(host, port, hints, ai_r); +} +AddressInfoList +Resolve(const char *host_and_port, int default_port, + const struct addrinfo *hints) +{ + struct addrinfo *ai; + int result = Resolve(host_and_port, default_port, hints, &ai); + if (result != 0) + throw FormatRuntimeError("Failed to resolve '%s': %s", + host_and_port, gai_strerror(result)); + + return AddressInfoList(ai); +} + +AddressInfoList +Resolve(const char *host_port, unsigned default_port, int flags, int socktype) +{ addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_flags = flags; hints.ai_family = AF_UNSPEC; hints.ai_socktype = socktype; - struct addrinfo *ai; - int ret = getaddrinfo(host, port, &hints, &ai); - if (ret != 0) - throw FormatRuntimeError("Failed to look up '%s': %s", - host_port, gai_strerror(ret)); - - return ai; + return Resolve(host_port, default_port, &hints); } diff --git a/src/net/Resolver.hxx b/src/net/Resolver.hxx index 1f8b89659..f5630e02e 100644 --- a/src/net/Resolver.hxx +++ b/src/net/Resolver.hxx @@ -1,44 +1,55 @@ /* - * Copyright 2003-2017 The Music Player Daemon Project - * http://www.musicpd.org + * Copyright 2007-2017 Content Management AG + * All rights reserved. * - * 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. + * author: Max Kellermann <mk@cm4all.com> * - * 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. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * 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. + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MPD_RESOLVER_HXX -#define MPD_RESOLVER_HXX - -#include "check.h" -#include "util/Compiler.h" +#ifndef NET_RESOLVER_HXX +#define NET_RESOLVER_HXX struct addrinfo; +class AddressInfoList; /** - * Resolve a specification in the form "host", "host:port", - * "[host]:port". This is a convenience wrapper for getaddrinfo(). + * Resolve the given host name (which may include a port), and fall + * back to the given default port. * - * Throws #std::runtime_error on error. + * This is a wrapper for getaddrinfo() and it does not support local + * sockets. * - * @param default_port a default port number that will be used if none - * is given in the string (if applicable); pass 0 to go without a - * default - * @return an #addrinfo linked list that must be freed with - * freeaddrinfo() + * Throws on error. */ -addrinfo * -resolve_host_port(const char *host_port, unsigned default_port, - int flags, int socktype); +AddressInfoList +Resolve(const char *host_and_port, int default_port, + const struct addrinfo *hints); + +AddressInfoList +Resolve(const char *host_port, unsigned default_port, int flags, int socktype); #endif diff --git a/test/run_resolver.cxx b/test/run_resolver.cxx index 681d64445..8e712301a 100644 --- a/test/run_resolver.cxx +++ b/test/run_resolver.cxx @@ -19,20 +19,13 @@ #include "config.h" #include "net/Resolver.hxx" +#include "net/AddressInfo.hxx" #include "net/ToString.hxx" #include "net/SocketAddress.hxx" #include "Log.hxx" #include <exception> -#ifdef _WIN32 -#include <ws2tcpip.h> -#include <winsock.h> -#else -#include <sys/socket.h> -#include <netdb.h> -#endif - #include <stdio.h> #include <stdlib.h> @@ -43,15 +36,10 @@ try { return EXIT_FAILURE; } - struct addrinfo *ai = - resolve_host_port(argv[1], 80, AI_PASSIVE, SOCK_STREAM); - - for (const struct addrinfo *i = ai; i != NULL; i = i->ai_next) { - const auto s = ToString({i->ai_addr, i->ai_addrlen}); - printf("%s\n", s.c_str()); + for (const auto &i : Resolve(argv[1], 80, AI_PASSIVE, SOCK_STREAM)) { + printf("%s\n", ToString(i).c_str()); } - freeaddrinfo(ai); return EXIT_SUCCESS; } catch (...) { LogError(std::current_exception()); |