event/ServerSocket: migrate from class Error to C++ exceptions
This commit is contained in:
parent
16d1c9f5d6
commit
aead221184
@ -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:
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
|
|
||||||
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 @@
|
|||||||
#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:
|
|||||||
}
|
}
|
||||||
#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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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()
|
|||||||
|
|
||||||
#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)
|
|||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
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:
|
|||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
bool AddFD(int fd, Error &error);
|
void AddFD(int fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws #std::runtime_error on error.
|
||||||
|
*/
|
||||||
|
void Open();
|
||||||
|
|
||||||
bool Open(Error &error);
|
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -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 @@
|
|||||||
#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,
|
|||||||
|
|
||||||
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 @@
|
|||||||
#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 @@
|
|||||||
#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()
|
|||||||
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 @@
|
|||||||
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 @@
|
|||||||
#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;
|
|||||||
* @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:
|
|||||||
return &base;
|
return &base;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bind(Error &error);
|
void Bind();
|
||||||
void Unbind();
|
void Unbind();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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)
|
|||||||
/* 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)
|
|||||||
{
|
{
|
||||||
HttpdOutput *httpd = new HttpdOutput(io_thread_get());
|
HttpdOutput *httpd = new HttpdOutput(io_thread_get());
|
||||||
|
|
||||||
AudioOutput *result = httpd->InitAndConfigure(block, error);
|
try {
|
||||||
if (result == nullptr)
|
AudioOutput *result = httpd->InitAndConfigure(block, error);
|
||||||
delete httpd;
|
if (result == nullptr)
|
||||||
|
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()
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 @@
|
|||||||
#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 @@
|
|||||||
#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)
|
|||||||
|
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
} catch (const std::runtime_error &e) {
|
||||||
|
LogError(e);
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user