aboutsummaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2015-02-10 21:46:23 +0100
committerMax Kellermann <max@duempel.org>2015-02-10 22:06:06 +0100
commit42890b9acf50c4406b61b3b37078c00ec79411fa (patch)
tree2a723dde7d6da3d82a68885a763bc24b187ebd94 /src/net
parent33a27379f9b2540660f9b52cd70904918c33fe4b (diff)
downloadmpd-42890b9acf50c4406b61b3b37078c00ec79411fa.tar.gz
mpd-42890b9acf50c4406b61b3b37078c00ec79411fa.tar.xz
mpd-42890b9acf50c4406b61b3b37078c00ec79411fa.zip
system/{Resolver,Socket{Error,Util}}: move to new library libnet.a
Diffstat (limited to 'src/net')
-rw-r--r--src/net/Resolver.cxx161
-rw-r--r--src/net/Resolver.hxx62
-rw-r--r--src/net/SocketError.cxx46
-rw-r--r--src/net/SocketError.hxx139
-rw-r--r--src/net/SocketUtil.cxx93
-rw-r--r--src/net/SocketUtil.hxx57
6 files changed, 558 insertions, 0 deletions
diff --git a/src/net/Resolver.cxx b/src/net/Resolver.cxx
new file mode 100644
index 000000000..389b3d4b5
--- /dev/null
+++ b/src/net/Resolver.cxx
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2003-2015 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.hxx"
+#include "util/Error.hxx"
+#include "util/Domain.hxx"
+
+#ifndef WIN32
+#include <sys/socket.h>
+#include <netdb.h>
+#ifdef HAVE_TCP
+#include <netinet/in.h>
+#endif
+#else
+#include <ws2tcpip.h>
+#include <winsock.h>
+#endif
+
+#ifdef HAVE_UN
+#include <sys/un.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+const Domain resolver_domain("resolver");
+
+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 "local";
+
+ return s_un.sun_path;
+ }
+#endif
+
+#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)
+ return "unknown";
+
+#ifdef HAVE_IPV6
+ if (strchr(host, ':') != nullptr) {
+ std::string result("[");
+ result.append(host);
+ result.append("]:");
+ result.append(serv);
+ return result;
+ }
+#endif
+
+ std::string result(host);
+ result.push_back(':');
+ result.append(serv);
+ return result;
+}
+
+struct addrinfo *
+resolve_host_port(const char *host_port, unsigned default_port,
+ int flags, int socktype,
+ Error &error)
+{
+ 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;
+ }
+ }
+
+ if (port == nullptr) {
+ /* port is after the colon, but only if it's the only
+ colon (don't split IPv6 addresses) */
+
+ 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;
+ }
+ }
+
+ char buffer[32];
+ if (port == nullptr && default_port != 0) {
+ snprintf(buffer, sizeof(buffer), "%u", default_port);
+ port = buffer;
+ }
+
+ if ((flags & AI_PASSIVE) != 0 && strcmp(host, "*") == 0)
+ host = nullptr;
+
+ 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) {
+ error.Format(resolver_domain, ret,
+ "Failed to look up '%s': %s",
+ host_port, gai_strerror(ret));
+ return nullptr;
+ }
+
+ return ai;
+}
diff --git a/src/net/Resolver.hxx b/src/net/Resolver.hxx
new file mode 100644
index 000000000..a9596c299
--- /dev/null
+++ b/src/net/Resolver.hxx
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2003-2015 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.
+ */
+
+#ifndef MPD_RESOLVER_HXX
+#define MPD_RESOLVER_HXX
+
+#include "Compiler.h"
+
+#include <string>
+
+#include <stddef.h>
+
+struct sockaddr;
+struct addrinfo;
+class Error;
+class Domain;
+
+extern const Domain resolver_domain;
+
+/**
+ * Converts the specified socket address into a string in the form
+ * "IP:PORT".
+ *
+ * @param sa the sockaddr struct
+ * @param length the length of #sa in bytes
+ */
+gcc_pure
+std::string
+sockaddr_to_string(const sockaddr *sa, size_t length);
+
+/**
+ * Resolve a specification in the form "host", "host:port",
+ * "[host]:port". This is a convenience wrapper for getaddrinfo().
+ *
+ * @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(), or NULL on error
+ */
+addrinfo *
+resolve_host_port(const char *host_port, unsigned default_port,
+ int flags, int socktype,
+ Error &error);
+
+#endif
diff --git a/src/net/SocketError.cxx b/src/net/SocketError.cxx
new file mode 100644
index 000000000..c4c9d7a2c
--- /dev/null
+++ b/src/net/SocketError.cxx
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2003-2015 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 "SocketError.hxx"
+#include "util/Domain.hxx"
+
+#include <string.h>
+
+const Domain socket_domain("socket");
+
+#ifdef WIN32
+
+SocketErrorMessage::SocketErrorMessage(socket_error_t code)
+{
+ DWORD nbytes = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL, code, 0,
+ (LPSTR)msg, sizeof(msg), NULL);
+ if (nbytes == 0)
+ strcpy(msg, "Unknown error");
+}
+
+#else
+
+SocketErrorMessage::SocketErrorMessage(socket_error_t code)
+ :msg(strerror(code)) {}
+
+#endif
diff --git a/src/net/SocketError.hxx b/src/net/SocketError.hxx
new file mode 100644
index 000000000..c9435d6fb
--- /dev/null
+++ b/src/net/SocketError.hxx
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2003-2015 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.
+ */
+
+#ifndef MPD_SOCKET_ERROR_HXX
+#define MPD_SOCKET_ERROR_HXX
+
+#include "Compiler.h"
+#include "util/Error.hxx" // IWYU pragma: export
+
+#ifdef WIN32
+#include <winsock2.h>
+typedef DWORD socket_error_t;
+#else
+#include <errno.h>
+typedef int socket_error_t;
+#endif
+
+class Domain;
+
+/**
+ * A #Domain for #Error for socket I/O errors. The code is an errno
+ * value (or WSAGetLastError() on Windows).
+ */
+extern const Domain socket_domain;
+
+gcc_pure
+static inline socket_error_t
+GetSocketError()
+{
+#ifdef WIN32
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+}
+
+gcc_const
+static inline bool
+IsSocketErrorAgain(socket_error_t code)
+{
+#ifdef WIN32
+ return code == WSAEINPROGRESS;
+#else
+ return code == EAGAIN;
+#endif
+}
+
+gcc_const
+static inline bool
+IsSocketErrorInterruped(socket_error_t code)
+{
+#ifdef WIN32
+ return code == WSAEINTR;
+#else
+ return code == EINTR;
+#endif
+}
+
+gcc_const
+static inline bool
+IsSocketErrorClosed(socket_error_t code)
+{
+#ifdef WIN32
+ return code == WSAECONNRESET;
+#else
+ return code == EPIPE || code == ECONNRESET;
+#endif
+}
+
+/**
+ * Helper class that formats a socket error message into a
+ * human-readable string. On Windows, a buffer is necessary for this,
+ * and this class hosts the buffer.
+ */
+class SocketErrorMessage {
+#ifdef WIN32
+ char msg[256];
+#else
+ const char *const msg;
+#endif
+
+public:
+#ifdef WIN32
+ explicit SocketErrorMessage(socket_error_t code=GetSocketError());
+#else
+ explicit SocketErrorMessage(socket_error_t code=GetSocketError());
+#endif
+
+ operator const char *() const {
+ return msg;
+ }
+};
+
+static inline void
+SetSocketError(Error &error, socket_error_t code)
+{
+ const SocketErrorMessage msg(code);
+ error.Set(socket_domain, code, msg);
+}
+
+static inline void
+SetSocketError(Error &error)
+{
+ SetSocketError(error, GetSocketError());
+}
+
+gcc_const
+static inline Error
+NewSocketError(socket_error_t code)
+{
+ Error error;
+ SetSocketError(error, code);
+ return error;
+}
+
+gcc_pure
+static inline Error
+NewSocketError()
+{
+ return NewSocketError(GetSocketError());
+}
+
+#endif
diff --git a/src/net/SocketUtil.cxx b/src/net/SocketUtil.cxx
new file mode 100644
index 000000000..556a8d037
--- /dev/null
+++ b/src/net/SocketUtil.cxx
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2003-2015 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 "SocketUtil.hxx"
+#include "SocketError.hxx"
+#include "system/fd_util.h"
+
+#include <unistd.h>
+
+#ifndef WIN32
+#include <sys/socket.h>
+#else
+#include <ws2tcpip.h>
+#include <winsock.h>
+#endif
+
+#ifdef HAVE_IPV6
+#include <string.h>
+#endif
+
+int
+socket_bind_listen(int domain, int type, int protocol,
+ const struct sockaddr *address, size_t address_length,
+ int backlog,
+ Error &error)
+{
+ int fd, ret;
+ const int reuse = 1;
+
+ fd = socket_cloexec_nonblock(domain, type, protocol);
+ if (fd < 0) {
+ SetSocketError(error);
+ error.AddPrefix("Failed to create socket: ");
+ return -1;
+ }
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (const char *) &reuse, sizeof(reuse));
+ if (ret < 0) {
+ SetSocketError(error);
+ error.AddPrefix("setsockopt() failed: ");
+ close_socket(fd);
+ return -1;
+ }
+
+ ret = bind(fd, address, address_length);
+ if (ret < 0) {
+ SetSocketError(error);
+ close_socket(fd);
+ return -1;
+ }
+
+ ret = listen(fd, backlog);
+ if (ret < 0) {
+ SetSocketError(error);
+ error.AddPrefix("listen() failed: ");
+ close_socket(fd);
+ return -1;
+ }
+
+#ifdef HAVE_STRUCT_UCRED
+ setsockopt(fd, SOL_SOCKET, SO_PASSCRED,
+ (const char *) &reuse, sizeof(reuse));
+#endif
+
+ return fd;
+}
+
+int
+socket_keepalive(int fd)
+{
+ const int reuse = 1;
+
+ return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
+ (const char *)&reuse, sizeof(reuse));
+}
diff --git a/src/net/SocketUtil.hxx b/src/net/SocketUtil.hxx
new file mode 100644
index 000000000..ad02ef481
--- /dev/null
+++ b/src/net/SocketUtil.hxx
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2003-2015 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.
+ */
+
+/*
+ * This library provides easy helper functions for working with
+ * sockets.
+ *
+ */
+
+#ifndef MPD_SOCKET_UTIL_HXX
+#define MPD_SOCKET_UTIL_HXX
+
+#include <stddef.h>
+
+struct sockaddr;
+class Error;
+
+/**
+ * Creates a socket listening on the specified address. This is a
+ * shortcut for socket(), bind() and listen().
+ *
+ * @param domain the socket domain, e.g. PF_INET6
+ * @param type the socket type, e.g. SOCK_STREAM
+ * @param protocol the protocol, usually 0 to let the kernel choose
+ * @param address the address to listen on
+ * @param address_length the size of #address
+ * @param backlog the backlog parameter for the listen() system call
+ * @param error location to store the error occurring, or NULL to
+ * ignore errors
+ * @return the socket file descriptor or -1 on error
+ */
+int
+socket_bind_listen(int domain, int type, int protocol,
+ const struct sockaddr *address, size_t address_length,
+ int backlog,
+ Error &error);
+
+int
+socket_keepalive(int fd);
+
+#endif