Commit aead2211 authored by Max Kellermann's avatar Max Kellermann

event/ServerSocket: migrate from class Error to C++ exceptions

parent 16d1c9f5
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
#include "config/ConfigOption.hxx" #include "config/ConfigOption.hxx"
#include "net/SocketAddress.hxx" #include "net/SocketAddress.hxx"
#include "event/ServerSocket.hxx" #include "event/ServerSocket.hxx"
#include "util/Error.hxx" #include "system/Error.hxx"
#include "util/RuntimeError.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "Log.hxx" #include "Log.hxx"
...@@ -58,50 +59,47 @@ private: ...@@ -58,50 +59,47 @@ private:
static ClientListener *listen_socket; static ClientListener *listen_socket;
int listen_port; int listen_port;
static bool /**
* Throws #std::runtime_error on error.
*/
static void
listen_add_config_param(unsigned int port, listen_add_config_param(unsigned int port,
const ConfigParam *param, const ConfigParam *param)
Error &error_r)
{ {
assert(param != nullptr); assert(param != nullptr);
if (0 == strcmp(param->value.c_str(), "any")) { if (0 == strcmp(param->value.c_str(), "any")) {
return listen_socket->AddPort(port, error_r); listen_socket->AddPort(port);
} else if (param->value[0] == '/' || param->value[0] == '~') { } else if (param->value[0] == '/' || param->value[0] == '~') {
auto path = param->GetPath(error_r); listen_socket->AddPath(param->GetPath());
return !path.IsNull() &&
listen_socket->AddPath(std::move(path), error_r);
} else { } else {
return listen_socket->AddHost(param->value.c_str(), port, listen_socket->AddHost(param->value.c_str(), port);
error_r);
} }
} }
#ifdef ENABLE_SYSTEMD_DAEMON #ifdef ENABLE_SYSTEMD_DAEMON
static bool static bool
listen_systemd_activation(Error &error_r) listen_systemd_activation()
{ {
int n = sd_listen_fds(true); int n = sd_listen_fds(true);
if (n <= 0) { if (n <= 0) {
if (n < 0) if (n < 0)
FormatErrno(listen_domain, -n, throw MakeErrno(-n, "sd_listen_fds() failed");
"sd_listen_fds() failed");
return false; return false;
} }
for (int i = SD_LISTEN_FDS_START, end = SD_LISTEN_FDS_START + n; for (int i = SD_LISTEN_FDS_START, end = SD_LISTEN_FDS_START + n;
i != end; ++i) i != end; ++i)
if (!listen_socket->AddFD(i, error_r)) listen_socket->AddFD(i);
return false;
return true; return true;
} }
#endif #endif
bool void
listen_global_init(EventLoop &loop, Partition &partition, Error &error) listen_global_init(EventLoop &loop, Partition &partition)
{ {
int port = config_get_positive(ConfigOption::PORT, DEFAULT_PORT); int port = config_get_positive(ConfigOption::PORT, DEFAULT_PORT);
const auto *param = config_get_param(ConfigOption::BIND_TO_ADDRESS); const auto *param = config_get_param(ConfigOption::BIND_TO_ADDRESS);
...@@ -109,11 +107,8 @@ listen_global_init(EventLoop &loop, Partition &partition, Error &error) ...@@ -109,11 +107,8 @@ listen_global_init(EventLoop &loop, Partition &partition, Error &error)
listen_socket = new ClientListener(loop, partition); listen_socket = new ClientListener(loop, partition);
#ifdef ENABLE_SYSTEMD_DAEMON #ifdef ENABLE_SYSTEMD_DAEMON
if (listen_systemd_activation(error)) if (listen_systemd_activation())
return true; return;
if (error.IsDefined())
return false;
#endif #endif
if (param != nullptr) { if (param != nullptr) {
...@@ -121,32 +116,35 @@ listen_global_init(EventLoop &loop, Partition &partition, Error &error) ...@@ -121,32 +116,35 @@ listen_global_init(EventLoop &loop, Partition &partition, Error &error)
for all values */ for all values */
do { do {
if (!listen_add_config_param(port, param, error)) { try {
listen_add_config_param(port, param);
} catch (const std::runtime_error &e) {
delete listen_socket; delete listen_socket;
error.FormatPrefix("Failed to listen on %s (line %i): ", std::throw_with_nested(FormatRuntimeError("Failed to listen on %s (line %i)",
param->value.c_str(), param->value.c_str(),
param->line); param->line));
return false;
} }
} while ((param = param->next) != nullptr); } while ((param = param->next) != nullptr);
} else { } else {
/* no "bind_to_address" configured, bind the /* no "bind_to_address" configured, bind the
configured port on all interfaces */ configured port on all interfaces */
if (!listen_socket->AddPort(port, error)) { try {
listen_socket->AddPort(port);
} catch (const std::runtime_error &e) {
delete listen_socket; delete listen_socket;
error.FormatPrefix("Failed to listen on *:%d: ", port); std::throw_with_nested(FormatRuntimeError("Failed to listen on *:%d: ", port));
return false;
} }
} }
if (!listen_socket->Open(error)) { try {
listen_socket->Open();
} catch (const std::runtime_error &e) {
delete listen_socket; delete listen_socket;
return false; throw;
} }
listen_port = port; listen_port = port;
return true;
} }
void listen_global_finish(void) void listen_global_finish(void)
......
...@@ -21,13 +21,12 @@ ...@@ -21,13 +21,12 @@
#define MPD_LISTEN_HXX #define MPD_LISTEN_HXX
class EventLoop; class EventLoop;
class Error;
struct Partition; struct Partition;
extern int listen_port; extern int listen_port;
bool void
listen_global_init(EventLoop &loop, Partition &partition, Error &error); listen_global_init(EventLoop &loop, Partition &partition);
void void
listen_global_finish(); listen_global_finish();
......
...@@ -465,11 +465,7 @@ try { ...@@ -465,11 +465,7 @@ try {
initialize_decoder_and_player(); initialize_decoder_and_player();
if (!listen_global_init(instance->event_loop, *instance->partition, listen_global_init(instance->event_loop, *instance->partition);
error)) {
LogError(error);
return EXIT_FAILURE;
}
#ifdef ENABLE_DAEMON #ifdef ENABLE_DAEMON
daemonize_set_user(); daemonize_set_user();
......
...@@ -30,8 +30,9 @@ ...@@ -30,8 +30,9 @@
#include "system/fd_util.h" #include "system/fd_util.h"
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "fs/FileSystem.hxx" #include "fs/FileSystem.hxx"
#include "util/Error.hxx" #include "util/RuntimeError.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "util/ScopeExit.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <string> #include <string>
...@@ -96,7 +97,7 @@ public: ...@@ -96,7 +97,7 @@ public:
} }
#endif #endif
bool Open(Error &error); void Open();
using SocketMonitor::IsDefined; using SocketMonitor::IsDefined;
using SocketMonitor::Close; using SocketMonitor::Close;
...@@ -179,17 +180,14 @@ OneServerSocket::OnSocketReady(gcc_unused unsigned flags) ...@@ -179,17 +180,14 @@ OneServerSocket::OnSocketReady(gcc_unused unsigned flags)
return true; return true;
} }
inline bool inline void
OneServerSocket::Open(Error &error) OneServerSocket::Open()
{ {
assert(!IsDefined()); assert(!IsDefined());
int _fd = socket_bind_listen(address.GetFamily(), int _fd = socket_bind_listen(address.GetFamily(),
SOCK_STREAM, 0, SOCK_STREAM, 0,
address, 5, address, 5);
error);
if (_fd < 0)
return false;
#ifdef HAVE_UN #ifdef HAVE_UN
/* allow everybody to connect */ /* allow everybody to connect */
...@@ -201,8 +199,6 @@ OneServerSocket::Open(Error &error) ...@@ -201,8 +199,6 @@ OneServerSocket::Open(Error &error)
/* register in the EventLoop */ /* register in the EventLoop */
SetFD(_fd); SetFD(_fd);
return true;
} }
ServerSocket::ServerSocket(EventLoop &_loop) ServerSocket::ServerSocket(EventLoop &_loop)
...@@ -212,11 +208,11 @@ ServerSocket::ServerSocket(EventLoop &_loop) ...@@ -212,11 +208,11 @@ ServerSocket::ServerSocket(EventLoop &_loop)
declaration */ declaration */
ServerSocket::~ServerSocket() {} ServerSocket::~ServerSocket() {}
bool void
ServerSocket::Open(Error &error) ServerSocket::Open()
{ {
OneServerSocket *good = nullptr, *bad = nullptr; OneServerSocket *good = nullptr, *bad = nullptr;
Error last_error; std::exception_ptr last_error;
for (auto &i : sockets) { for (auto &i : sockets) {
assert(i.GetSerial() > 0); assert(i.GetSerial() > 0);
...@@ -224,30 +220,32 @@ ServerSocket::Open(Error &error) ...@@ -224,30 +220,32 @@ ServerSocket::Open(Error &error)
if (bad != nullptr && i.GetSerial() != bad->GetSerial()) { if (bad != nullptr && i.GetSerial() != bad->GetSerial()) {
Close(); Close();
error = std::move(last_error); std::rethrow_exception(last_error);
return false;
} }
Error error2; try {
if (!i.Open(error2)) { i.Open();
} catch (const std::runtime_error &e) {
if (good != nullptr && good->GetSerial() == i.GetSerial()) { if (good != nullptr && good->GetSerial() == i.GetSerial()) {
const auto address_string = i.ToString(); const auto address_string = i.ToString();
const auto good_string = good->ToString(); const auto good_string = good->ToString();
FormatWarning(server_socket_domain, FormatError(e,
"bind to '%s' failed: %s " "bind to '%s' failed "
"(continuing anyway, because " "(continuing anyway, because "
"binding to '%s' succeeded)", "binding to '%s' succeeded)",
address_string.c_str(), address_string.c_str(),
error2.GetMessage(),
good_string.c_str()); good_string.c_str());
} else if (bad == nullptr) { } else if (bad == nullptr) {
bad = &i; bad = &i;
const auto address_string = i.ToString(); const auto address_string = i.ToString();
error2.FormatPrefix("Failed to bind to '%s': ",
address_string.c_str());
last_error = std::move(error2); try {
std::throw_with_nested(FormatRuntimeError("Failed to bind to '%s'",
address_string.c_str()));
} catch (...) {
last_error = std::current_exception();
}
} }
continue; continue;
...@@ -260,17 +258,14 @@ ServerSocket::Open(Error &error) ...@@ -260,17 +258,14 @@ ServerSocket::Open(Error &error)
if (bad != nullptr) { if (bad != nullptr) {
bad = nullptr; bad = nullptr;
last_error.Clear(); last_error = nullptr;
} }
} }
if (bad != nullptr) { if (bad != nullptr) {
Close(); Close();
error = std::move(last_error); std::rethrow_exception(last_error);
return false;
} }
return true;
} }
void void
...@@ -299,26 +294,21 @@ ServerSocket::AddAddress(AllocatedSocketAddress &&address) ...@@ -299,26 +294,21 @@ ServerSocket::AddAddress(AllocatedSocketAddress &&address)
return sockets.back(); return sockets.back();
} }
bool void
ServerSocket::AddFD(int fd, Error &error) ServerSocket::AddFD(int fd)
{ {
assert(fd >= 0); assert(fd >= 0);
StaticSocketAddress address; StaticSocketAddress address;
socklen_t address_length = sizeof(address); socklen_t address_length = sizeof(address);
if (getsockname(fd, address.GetAddress(), if (getsockname(fd, address.GetAddress(),
&address_length) < 0) { &address_length) < 0)
SetSocketError(error); throw MakeSocketError("Failed to get socket address");
error.AddPrefix("Failed to get socket address: ");
return false;
}
address.SetSize(address_length); address.SetSize(address_length);
OneServerSocket &s = AddAddress(address); OneServerSocket &s = AddAddress(address);
s.SetFD(fd); s.SetFD(fd);
return true;
} }
#ifdef HAVE_TCP #ifdef HAVE_TCP
...@@ -367,14 +357,12 @@ SupportsIPv6() ...@@ -367,14 +357,12 @@ SupportsIPv6()
#endif /* HAVE_TCP */ #endif /* HAVE_TCP */
bool void
ServerSocket::AddPort(unsigned port, Error &error) ServerSocket::AddPort(unsigned port)
{ {
#ifdef HAVE_TCP #ifdef HAVE_TCP
if (port == 0 || port > 0xffff) { if (port == 0 || port > 0xffff)
error.Set(server_socket_domain, "Invalid TCP port"); throw std::runtime_error("Invalid TCP port");
return false;
}
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (SupportsIPv6()) if (SupportsIPv6())
...@@ -383,49 +371,37 @@ ServerSocket::AddPort(unsigned port, Error &error) ...@@ -383,49 +371,37 @@ ServerSocket::AddPort(unsigned port, Error &error)
AddPortIPv4(port); AddPortIPv4(port);
++next_serial; ++next_serial;
return true;
#else /* HAVE_TCP */ #else /* HAVE_TCP */
(void)port; (void)port;
error.Set(server_socket_domain, "TCP support is disabled"); throw std::runtime_error("TCP support is disabled");
return false;
#endif /* HAVE_TCP */ #endif /* HAVE_TCP */
} }
bool void
ServerSocket::AddHost(const char *hostname, unsigned port, Error &error) ServerSocket::AddHost(const char *hostname, unsigned port)
{ {
#ifdef HAVE_TCP #ifdef HAVE_TCP
struct addrinfo *ai = resolve_host_port(hostname, port, struct addrinfo *ai = resolve_host_port(hostname, port,
AI_PASSIVE, SOCK_STREAM, AI_PASSIVE, SOCK_STREAM);
error); AtScopeExit(ai) { freeaddrinfo(ai); };
if (ai == nullptr)
return false;
for (const struct addrinfo *i = ai; i != nullptr; i = i->ai_next) for (const struct addrinfo *i = ai; i != nullptr; i = i->ai_next)
AddAddress(SocketAddress(i->ai_addr, i->ai_addrlen)); AddAddress(SocketAddress(i->ai_addr, i->ai_addrlen));
freeaddrinfo(ai);
++next_serial; ++next_serial;
return true;
#else /* HAVE_TCP */ #else /* HAVE_TCP */
(void)hostname; (void)hostname;
(void)port; (void)port;
error.Set(server_socket_domain, "TCP support is disabled"); throw std::runtime_error("TCP support is disabled");
return false;
#endif /* HAVE_TCP */ #endif /* HAVE_TCP */
} }
bool void
ServerSocket::AddPath(AllocatedPath &&path, Error &error) ServerSocket::AddPath(AllocatedPath &&path)
{ {
#ifdef HAVE_UN #ifdef HAVE_UN
(void)error;
unlink(path.c_str()); unlink(path.c_str());
AllocatedSocketAddress address; AllocatedSocketAddress address;
...@@ -433,14 +409,10 @@ ServerSocket::AddPath(AllocatedPath &&path, Error &error) ...@@ -433,14 +409,10 @@ ServerSocket::AddPath(AllocatedPath &&path, Error &error)
OneServerSocket &s = AddAddress(std::move(address)); OneServerSocket &s = AddAddress(std::move(address));
s.SetPath(std::move(path)); s.SetPath(std::move(path));
return true;
#else /* !HAVE_UN */ #else /* !HAVE_UN */
(void)path; (void)path;
error.Set(server_socket_domain, throw std::runtime_error("UNIX domain socket support is disabled");
"UNIX domain socket support is disabled");
return false;
#endif /* !HAVE_UN */ #endif /* !HAVE_UN */
} }
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
class SocketAddress; class SocketAddress;
class AllocatedSocketAddress; class AllocatedSocketAddress;
class EventLoop; class EventLoop;
class Error;
class AllocatedPath; class AllocatedPath;
class OneServerSocket; class OneServerSocket;
...@@ -71,40 +70,49 @@ public: ...@@ -71,40 +70,49 @@ public:
/** /**
* Add a listener on a port on all interfaces. * Add a listener on a port on all interfaces.
* *
* Throws #std::runtime_error on error.
*
* @param port the TCP port * @param port the TCP port
* @param error location to store the error occurring * @param error location to store the error occurring
* @return true on success
*/ */
bool AddPort(unsigned port, Error &error); void AddPort(unsigned port);
/** /**
* Resolves a host name, and adds listeners on all addresses in the * Resolves a host name, and adds listeners on all addresses in the
* result set. * result set.
* *
* Throws #std::runtime_error on error.
*
* @param hostname the host name to be resolved * @param hostname the host name to be resolved
* @param port the TCP port * @param port the TCP port
* @param error location to store the error occurring * @param error location to store the error occurring
* @return true on success
*/ */
bool AddHost(const char *hostname, unsigned port, Error &error); void AddHost(const char *hostname, unsigned port);
/** /**
* Add a listener on a Unix domain socket. * Add a listener on a Unix domain socket.
* *
* Throws #std::runtime_error on error.
*
* @param path the absolute socket path * @param path the absolute socket path
* @param error location to store the error occurring * @param error location to store the error occurring
* @return true on success
*/ */
bool AddPath(AllocatedPath &&path, Error &error); void AddPath(AllocatedPath &&path);
/** /**
* Add a socket descriptor that is accepting connections. After this * Add a socket descriptor that is accepting connections. After this
* has been called, don't call server_socket_open(), because the * has been called, don't call server_socket_open(), because the
* socket is already open. * socket is already open.
*
* Throws #std::runtime_error on error.
*/
void AddFD(int fd);
/**
* Throws #std::runtime_error on error.
*/ */
bool AddFD(int fd, Error &error); void Open();
bool Open(Error &error);
void Close(); void Close();
protected: protected:
......
...@@ -19,8 +19,7 @@ ...@@ -19,8 +19,7 @@
#include "config.h" #include "config.h"
#include "Resolver.hxx" #include "Resolver.hxx"
#include "util/Error.hxx" #include "util/RuntimeError.hxx"
#include "util/Domain.hxx"
#include <string> #include <string>
...@@ -35,12 +34,9 @@ ...@@ -35,12 +34,9 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
const Domain resolver_domain("resolver");
struct addrinfo * struct addrinfo *
resolve_host_port(const char *host_port, unsigned default_port, resolve_host_port(const char *host_port, unsigned default_port,
int flags, int socktype, int flags, int socktype)
Error &error)
{ {
std::string p(host_port); std::string p(host_port);
const char *host = p.c_str(), *port = nullptr; const char *host = p.c_str(), *port = nullptr;
...@@ -87,12 +83,9 @@ resolve_host_port(const char *host_port, unsigned default_port, ...@@ -87,12 +83,9 @@ resolve_host_port(const char *host_port, unsigned default_port,
struct addrinfo *ai; struct addrinfo *ai;
int ret = getaddrinfo(host, port, &hints, &ai); int ret = getaddrinfo(host, port, &hints, &ai);
if (ret != 0) { if (ret != 0)
error.Format(resolver_domain, ret, throw FormatRuntimeError("Failed to look up '%s': %s",
"Failed to look up '%s': %s",
host_port, gai_strerror(ret)); host_port, gai_strerror(ret));
return nullptr;
}
return ai; return ai;
} }
...@@ -24,24 +24,21 @@ ...@@ -24,24 +24,21 @@
#include "Compiler.h" #include "Compiler.h"
struct addrinfo; struct addrinfo;
class Error;
class Domain;
extern const Domain resolver_domain;
/** /**
* Resolve a specification in the form "host", "host:port", * Resolve a specification in the form "host", "host:port",
* "[host]:port". This is a convenience wrapper for getaddrinfo(). * "[host]:port". This is a convenience wrapper for getaddrinfo().
* *
* Throws #std::runtime_error on error.
*
* @param default_port a default port number that will be used if none * @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 * is given in the string (if applicable); pass 0 to go without a
* default * default
* @return an #addrinfo linked list that must be freed with * @return an #addrinfo linked list that must be freed with
* freeaddrinfo(), or NULL on error * freeaddrinfo()
*/ */
addrinfo * addrinfo *
resolve_host_port(const char *host_port, unsigned default_port, resolve_host_port(const char *host_port, unsigned default_port,
int flags, int socktype, int flags, int socktype);
Error &error);
#endif #endif
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define MPD_SOCKET_ERROR_HXX #define MPD_SOCKET_ERROR_HXX
#include "Compiler.h" #include "Compiler.h"
#include "system/Error.hxx"
#include "util/Error.hxx" // IWYU pragma: export #include "util/Error.hxx" // IWYU pragma: export
#ifdef WIN32 #ifdef WIN32
...@@ -136,4 +137,22 @@ NewSocketError() ...@@ -136,4 +137,22 @@ NewSocketError()
return NewSocketError(GetSocketError()); return NewSocketError(GetSocketError());
} }
gcc_const
static inline std::system_error
MakeSocketError(socket_error_t code, const char *msg)
{
#ifdef WIN32
return MakeLastError(code, msg);
#else
return MakeErrno(code, msg);
#endif
}
gcc_pure
static inline std::system_error
MakeSocketError(const char *msg)
{
return MakeSocketError(GetSocketError(), msg);
}
#endif #endif
...@@ -26,41 +26,35 @@ ...@@ -26,41 +26,35 @@
int int
socket_bind_listen(int domain, int type, int protocol, socket_bind_listen(int domain, int type, int protocol,
SocketAddress address, SocketAddress address,
int backlog, int backlog)
Error &error)
{ {
int fd, ret; int fd, ret;
const int reuse = 1; const int reuse = 1;
fd = socket_cloexec_nonblock(domain, type, protocol); fd = socket_cloexec_nonblock(domain, type, protocol);
if (fd < 0) { if (fd < 0)
SetSocketError(error); throw MakeSocketError("Failed to create socket");
error.AddPrefix("Failed to create socket: ");
return -1;
}
ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(const char *) &reuse, sizeof(reuse)); (const char *) &reuse, sizeof(reuse));
if (ret < 0) { if (ret < 0) {
SetSocketError(error); auto error = GetSocketError();
error.AddPrefix("setsockopt() failed: ");
close_socket(fd); close_socket(fd);
return -1; throw MakeSocketError(error, "setsockopt() failed");
} }
ret = bind(fd, address.GetAddress(), address.GetSize()); ret = bind(fd, address.GetAddress(), address.GetSize());
if (ret < 0) { if (ret < 0) {
SetSocketError(error); auto error = GetSocketError();
close_socket(fd); close_socket(fd);
return -1; throw MakeSocketError(error, "Failed to bind socket");
} }
ret = listen(fd, backlog); ret = listen(fd, backlog);
if (ret < 0) { if (ret < 0) {
SetSocketError(error); auto error = GetSocketError();
error.AddPrefix("listen() failed: ");
close_socket(fd); close_socket(fd);
return -1; throw MakeSocketError(error, "Failed to listen on socket");
} }
#if defined(HAVE_STRUCT_UCRED) && defined(SO_PASSCRED) #if defined(HAVE_STRUCT_UCRED) && defined(SO_PASSCRED)
......
...@@ -27,12 +27,13 @@ ...@@ -27,12 +27,13 @@
#define MPD_SOCKET_UTIL_HXX #define MPD_SOCKET_UTIL_HXX
class SocketAddress; class SocketAddress;
class Error;
/** /**
* Creates a socket listening on the specified address. This is a * Creates a socket listening on the specified address. This is a
* shortcut for socket(), bind() and listen(). * shortcut for socket(), bind() and listen().
* *
* Throws #std::system_error on error.
*
* @param domain the socket domain, e.g. PF_INET6 * @param domain the socket domain, e.g. PF_INET6
* @param type the socket type, e.g. SOCK_STREAM * @param type the socket type, e.g. SOCK_STREAM
* @param protocol the protocol, usually 0 to let the kernel choose * @param protocol the protocol, usually 0 to let the kernel choose
...@@ -40,13 +41,12 @@ class Error; ...@@ -40,13 +41,12 @@ class Error;
* @param backlog the backlog parameter for the listen() system call * @param backlog the backlog parameter for the listen() system call
* @param error location to store the error occurring, or NULL to * @param error location to store the error occurring, or NULL to
* ignore errors * ignore errors
* @return the socket file descriptor or -1 on error * @return the socket file descriptor
*/ */
int int
socket_bind_listen(int domain, int type, int protocol, socket_bind_listen(int domain, int type, int protocol,
SocketAddress address, SocketAddress address,
int backlog, int backlog);
Error &error);
int int
socket_keepalive(int fd); socket_keepalive(int fd);
......
...@@ -177,7 +177,7 @@ public: ...@@ -177,7 +177,7 @@ public:
return &base; return &base;
} }
bool Bind(Error &error); void Bind();
void Unbind(); void Unbind();
/** /**
......
...@@ -66,16 +66,14 @@ HttpdOutput::~HttpdOutput() ...@@ -66,16 +66,14 @@ HttpdOutput::~HttpdOutput()
delete prepared_encoder; delete prepared_encoder;
} }
inline bool inline void
HttpdOutput::Bind(Error &error) HttpdOutput::Bind()
{ {
open = false; open = false;
bool result = false; BlockingCall(GetEventLoop(), [this](){
BlockingCall(GetEventLoop(), [this, &error, &result](){ ServerSocket::Open();
result = ServerSocket::Open(error);
}); });
return result;
} }
inline void inline void
...@@ -112,12 +110,10 @@ HttpdOutput::Configure(const ConfigBlock &block, Error &error) ...@@ -112,12 +110,10 @@ HttpdOutput::Configure(const ConfigBlock &block, Error &error)
/* set up bind_to_address */ /* set up bind_to_address */
const char *bind_to_address = block.GetBlockValue("bind_to_address"); const char *bind_to_address = block.GetBlockValue("bind_to_address");
bool success = bind_to_address != nullptr && if (bind_to_address != nullptr && strcmp(bind_to_address, "any") != 0)
strcmp(bind_to_address, "any") != 0 AddHost(bind_to_address, port);
? AddHost(bind_to_address, port, error) else
: AddPort(port, error); AddPort(port);
if (!success)
return false;
/* initialize encoder */ /* initialize encoder */
...@@ -144,11 +140,16 @@ httpd_output_init(const ConfigBlock &block, Error &error) ...@@ -144,11 +140,16 @@ httpd_output_init(const ConfigBlock &block, Error &error)
{ {
HttpdOutput *httpd = new HttpdOutput(io_thread_get()); HttpdOutput *httpd = new HttpdOutput(io_thread_get());
try {
AudioOutput *result = httpd->InitAndConfigure(block, error); AudioOutput *result = httpd->InitAndConfigure(block, error);
if (result == nullptr) if (result == nullptr)
delete httpd; delete httpd;
return result; return result;
} catch (const std::runtime_error &e) {
delete httpd;
throw;
}
} }
static void static void
...@@ -271,11 +272,12 @@ HttpdOutput::ReadPage() ...@@ -271,11 +272,12 @@ HttpdOutput::ReadPage()
} }
static bool static bool
httpd_output_enable(AudioOutput *ao, Error &error) httpd_output_enable(AudioOutput *ao, gcc_unused Error &error)
{ {
HttpdOutput *httpd = HttpdOutput::Cast(ao); HttpdOutput *httpd = HttpdOutput::Cast(ao);
return httpd->Bind(error); httpd->Bind();
return true;
} }
static void static void
......
...@@ -21,9 +21,10 @@ ...@@ -21,9 +21,10 @@
#include "net/Resolver.hxx" #include "net/Resolver.hxx"
#include "net/ToString.hxx" #include "net/ToString.hxx"
#include "net/SocketAddress.hxx" #include "net/SocketAddress.hxx"
#include "util/Error.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <stdexcept>
#ifdef WIN32 #ifdef WIN32
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <winsock.h> #include <winsock.h>
...@@ -36,20 +37,14 @@ ...@@ -36,20 +37,14 @@
#include <stdlib.h> #include <stdlib.h>
int main(int argc, char **argv) int main(int argc, char **argv)
{ try {
if (argc != 2) { if (argc != 2) {
fprintf(stderr, "Usage: run_resolver HOST\n"); fprintf(stderr, "Usage: run_resolver HOST\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
Error error;
struct addrinfo *ai = struct addrinfo *ai =
resolve_host_port(argv[1], 80, AI_PASSIVE, SOCK_STREAM, resolve_host_port(argv[1], 80, AI_PASSIVE, SOCK_STREAM);
error);
if (ai == NULL) {
LogError(error);
return EXIT_FAILURE;
}
for (const struct addrinfo *i = ai; i != NULL; i = i->ai_next) { for (const struct addrinfo *i = ai; i != NULL; i = i->ai_next) {
const auto s = ToString({i->ai_addr, i->ai_addrlen}); const auto s = ToString({i->ai_addr, i->ai_addrlen});
...@@ -58,4 +53,7 @@ int main(int argc, char **argv) ...@@ -58,4 +53,7 @@ int main(int argc, char **argv)
freeaddrinfo(ai); freeaddrinfo(ai);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} catch (const std::runtime_error &e) {
LogError(e);
return EXIT_FAILURE;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment