mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-04 13:30:12 -05:00
protocol: improve error handling
This commit is contained in:
parent
216b641ebb
commit
c4f35825fe
2 changed files with 100 additions and 52 deletions
|
|
@ -318,14 +318,14 @@ static struct pw_client *client_new(struct server *s, int fd)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool init_socket_name(struct server *s, const char *name)
|
static int init_socket_name(struct server *s, const char *name)
|
||||||
{
|
{
|
||||||
int name_size;
|
int name_size;
|
||||||
const char *runtime_dir;
|
const char *runtime_dir;
|
||||||
|
|
||||||
if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) {
|
if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) {
|
||||||
pw_log_error("XDG_RUNTIME_DIR not set in the environment");
|
pw_log_error("XDG_RUNTIME_DIR not set in the environment");
|
||||||
return false;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->addr.sun_family = AF_LOCAL;
|
s->addr.sun_family = AF_LOCAL;
|
||||||
|
|
@ -336,29 +336,33 @@ static bool init_socket_name(struct server *s, const char *name)
|
||||||
pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes",
|
pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes",
|
||||||
runtime_dir, name);
|
runtime_dir, name);
|
||||||
*s->addr.sun_path = 0;
|
*s->addr.sun_path = 0;
|
||||||
return false;
|
return -ENAMETOOLONG;
|
||||||
}
|
}
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lock_socket(struct server *s)
|
static int lock_socket(struct server *s)
|
||||||
{
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
snprintf(s->lock_addr, sizeof(s->lock_addr), "%s%s", s->addr.sun_path, LOCK_SUFFIX);
|
snprintf(s->lock_addr, sizeof(s->lock_addr), "%s%s", s->addr.sun_path, LOCK_SUFFIX);
|
||||||
|
|
||||||
s->fd_lock = open(s->lock_addr, O_CREAT | O_CLOEXEC,
|
s->fd_lock = open(s->lock_addr, O_CREAT | O_CLOEXEC,
|
||||||
(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
|
(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
|
||||||
|
|
||||||
if (s->fd_lock < 0) {
|
if (s->fd_lock < 0) {
|
||||||
pw_log_error("unable to open lockfile %s check permissions", s->lock_addr);
|
res = -errno;
|
||||||
|
pw_log_error("unable to open lockfile '%s': %m", s->lock_addr);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flock(s->fd_lock, LOCK_EX | LOCK_NB) < 0) {
|
if (flock(s->fd_lock, LOCK_EX | LOCK_NB) < 0) {
|
||||||
pw_log_error("unable to lock lockfile %s, maybe another daemon is running",
|
res = -errno;
|
||||||
|
pw_log_error("unable to lock lockfile '%s': %m (maybe another daemon is running)",
|
||||||
s->lock_addr);
|
s->lock_addr);
|
||||||
goto err_fd;
|
goto err_fd;
|
||||||
}
|
}
|
||||||
return true;
|
return 0;
|
||||||
|
|
||||||
err_fd:
|
err_fd:
|
||||||
close(s->fd_lock);
|
close(s->fd_lock);
|
||||||
|
|
@ -366,7 +370,7 @@ static bool lock_socket(struct server *s)
|
||||||
err:
|
err:
|
||||||
*s->lock_addr = 0;
|
*s->lock_addr = 0;
|
||||||
*s->addr.sun_path = 0;
|
*s->addr.sun_path = 0;
|
||||||
return false;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -399,10 +403,10 @@ socket_data(void *data, int fd, uint32_t mask)
|
||||||
c->source, SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP);
|
c->source, SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool add_socket(struct pw_protocol *protocol, struct server *s)
|
static int add_socket(struct pw_protocol *protocol, struct server *s)
|
||||||
{
|
{
|
||||||
socklen_t size;
|
socklen_t size;
|
||||||
int fd = -1;
|
int fd = -1, res;
|
||||||
bool activated = false;
|
bool activated = false;
|
||||||
|
|
||||||
#ifdef HAVE_SYSTEMD_DAEMON
|
#ifdef HAVE_SYSTEMD_DAEMON
|
||||||
|
|
@ -421,33 +425,42 @@ static bool add_socket(struct pw_protocol *protocol, struct server *s)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0)
|
if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) {
|
||||||
|
res = -errno;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
size = offsetof(struct sockaddr_un, sun_path) + strlen(s->addr.sun_path);
|
size = offsetof(struct sockaddr_un, sun_path) + strlen(s->addr.sun_path);
|
||||||
if (bind(fd, (struct sockaddr *) &s->addr, size) < 0) {
|
if (bind(fd, (struct sockaddr *) &s->addr, size) < 0) {
|
||||||
|
res = -errno;
|
||||||
pw_log_error("bind() failed with error: %m");
|
pw_log_error("bind() failed with error: %m");
|
||||||
goto error_close;
|
goto error_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(fd, 128) < 0) {
|
if (listen(fd, 128) < 0) {
|
||||||
|
res = -errno;
|
||||||
pw_log_error("listen() failed with error: %m");
|
pw_log_error("listen() failed with error: %m");
|
||||||
goto error_close;
|
goto error_close;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s->loop = pw_core_get_main_loop(protocol->core);
|
|
||||||
s->source = pw_loop_add_io(s->loop, fd, SPA_IO_IN, true, socket_data, s);
|
|
||||||
s->activated = activated;
|
s->activated = activated;
|
||||||
if (s->source == NULL)
|
s->loop = pw_core_get_main_loop(protocol->core);
|
||||||
|
if (s->loop == NULL) {
|
||||||
|
res = -errno;
|
||||||
goto error_close;
|
goto error_close;
|
||||||
|
}
|
||||||
return true;
|
s->source = pw_loop_add_io(s->loop, fd, SPA_IO_IN, true, socket_data, s);
|
||||||
|
if (s->source == NULL) {
|
||||||
|
res = -errno;
|
||||||
|
goto error_close;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
error_close:
|
error_close:
|
||||||
close(fd);
|
close(fd);
|
||||||
error:
|
error:
|
||||||
return false;
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -460,9 +473,12 @@ static int impl_steal_fd(struct pw_protocol_client *client)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
fd = dup(impl->source->fd);
|
fd = dup(impl->source->fd);
|
||||||
|
if (fd == -1) {
|
||||||
|
fd = -errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
pw_protocol_client_disconnect(client);
|
pw_protocol_client_disconnect(client);
|
||||||
|
out:
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -574,31 +590,37 @@ static int impl_connect_fd(struct pw_protocol_client *client, int fd, bool do_cl
|
||||||
{
|
{
|
||||||
struct client *impl = SPA_CONTAINER_OF(client, struct client, this);
|
struct client *impl = SPA_CONTAINER_OF(client, struct client, this);
|
||||||
struct pw_remote *remote = client->remote;
|
struct pw_remote *remote = client->remote;
|
||||||
|
int res;
|
||||||
|
|
||||||
impl->disconnecting = false;
|
impl->disconnecting = false;
|
||||||
|
|
||||||
impl->connection = pw_protocol_native_connection_new(remote->core, fd);
|
impl->connection = pw_protocol_native_connection_new(remote->core, fd);
|
||||||
if (impl->connection == NULL)
|
if (impl->connection == NULL) {
|
||||||
goto error_close;
|
res = -errno;
|
||||||
|
goto error_cleanup;
|
||||||
pw_protocol_native_connection_add_listener(impl->connection,
|
}
|
||||||
&impl->conn_listener,
|
|
||||||
&conn_events,
|
|
||||||
impl);
|
|
||||||
|
|
||||||
impl->source = pw_loop_add_io(remote->core->main_loop,
|
impl->source = pw_loop_add_io(remote->core->main_loop,
|
||||||
fd,
|
fd,
|
||||||
SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR,
|
SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR,
|
||||||
do_close, on_remote_data, impl);
|
do_close, on_remote_data, impl);
|
||||||
if (impl->source == NULL)
|
if (impl->source == NULL) {
|
||||||
goto error_close;
|
res = -errno;
|
||||||
|
goto error_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
pw_protocol_native_connection_add_listener(impl->connection,
|
||||||
|
&impl->conn_listener,
|
||||||
|
&conn_events,
|
||||||
|
impl);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_close:
|
error_cleanup:
|
||||||
if (do_close)
|
if (impl->connection) {
|
||||||
close(fd);
|
pw_protocol_native_connection_destroy(impl->connection);
|
||||||
return -ENOMEM;
|
impl->connection = NULL;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void impl_disconnect(struct pw_protocol_client *client)
|
static void impl_disconnect(struct pw_protocol_client *client)
|
||||||
|
|
@ -641,6 +663,7 @@ impl_new_client(struct pw_protocol *protocol,
|
||||||
struct client *impl;
|
struct client *impl;
|
||||||
struct pw_protocol_client *this;
|
struct pw_protocol_client *this;
|
||||||
const char *str = NULL;
|
const char *str = NULL;
|
||||||
|
int res;
|
||||||
|
|
||||||
if ((impl = calloc(1, sizeof(struct client))) == NULL)
|
if ((impl = calloc(1, sizeof(struct client))) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -667,10 +690,21 @@ impl_new_client(struct pw_protocol *protocol,
|
||||||
this->destroy = impl_destroy;
|
this->destroy = impl_destroy;
|
||||||
|
|
||||||
impl->flush_event = pw_loop_add_event(remote->core->main_loop, do_flush_event, impl);
|
impl->flush_event = pw_loop_add_event(remote->core->main_loop, do_flush_event, impl);
|
||||||
|
if (impl->flush_event == NULL) {
|
||||||
|
res = -errno;
|
||||||
|
goto error_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
spa_list_append(&protocol->client_list, &this->link);
|
spa_list_append(&protocol->client_list, &this->link);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
|
error_cleanup:
|
||||||
|
if (impl->properties)
|
||||||
|
pw_properties_free(impl->properties);
|
||||||
|
free(impl);
|
||||||
|
errno = -res;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_server(struct pw_protocol_server *server)
|
static void destroy_server(struct pw_protocol_server *server)
|
||||||
|
|
@ -679,6 +713,7 @@ static void destroy_server(struct pw_protocol_server *server)
|
||||||
struct pw_client *client, *tmp;
|
struct pw_client *client, *tmp;
|
||||||
|
|
||||||
spa_list_remove(&server->link);
|
spa_list_remove(&server->link);
|
||||||
|
spa_hook_remove(&s->hook);
|
||||||
|
|
||||||
spa_list_for_each_safe(client, tmp, &server->client_list, protocol_link)
|
spa_list_for_each_safe(client, tmp, &server->client_list, protocol_link)
|
||||||
pw_client_destroy(client);
|
pw_client_destroy(client);
|
||||||
|
|
@ -736,6 +771,7 @@ impl_add_server(struct pw_protocol *protocol,
|
||||||
struct pw_protocol_server *this;
|
struct pw_protocol_server *this;
|
||||||
struct server *s;
|
struct server *s;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
int res;
|
||||||
|
|
||||||
if ((s = calloc(1, sizeof(struct server))) == NULL)
|
if ((s = calloc(1, sizeof(struct server))) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -751,23 +787,24 @@ impl_add_server(struct pw_protocol *protocol,
|
||||||
|
|
||||||
name = get_name(pw_core_get_properties(core));
|
name = get_name(pw_core_get_properties(core));
|
||||||
|
|
||||||
if (!init_socket_name(s, name))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!lock_socket(s))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!add_socket(protocol, s))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
pw_loop_add_hook(pw_core_get_main_loop(core), &s->hook, &impl_hooks, s);
|
pw_loop_add_hook(pw_core_get_main_loop(core), &s->hook, &impl_hooks, s);
|
||||||
|
|
||||||
|
if ((res = init_socket_name(s, name)) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if ((res = lock_socket(s)) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if ((res = add_socket(protocol, s)) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
pw_log_info("protocol-native %p: Added server %p %s", protocol, this, name);
|
pw_log_info("protocol-native %p: Added server %p %s", protocol, this, name);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
destroy_server(this);
|
destroy_server(this);
|
||||||
|
errno = -res;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -865,13 +902,14 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie
|
||||||
struct pw_protocol *this;
|
struct pw_protocol *this;
|
||||||
const char *val;
|
const char *val;
|
||||||
struct protocol_data *d;
|
struct protocol_data *d;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (pw_core_find_protocol(core, PW_TYPE_INFO_PROTOCOL_Native) != NULL)
|
if (pw_core_find_protocol(core, PW_TYPE_INFO_PROTOCOL_Native) != NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
this = pw_protocol_new(core, PW_TYPE_INFO_PROTOCOL_Native, sizeof(struct protocol_data));
|
this = pw_protocol_new(core, PW_TYPE_INFO_PROTOCOL_Native, sizeof(struct protocol_data));
|
||||||
if (this == NULL)
|
if (this == NULL)
|
||||||
return -ENOMEM;
|
return -errno;
|
||||||
|
|
||||||
debug_messages = pw_debug_is_category_enabled("connection");
|
debug_messages = pw_debug_is_category_enabled("connection");
|
||||||
|
|
||||||
|
|
@ -891,8 +929,10 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie
|
||||||
if (val == NULL)
|
if (val == NULL)
|
||||||
val = pw_properties_get(pw_core_get_properties(core), PW_KEY_CORE_DAEMON);
|
val = pw_properties_get(pw_core_get_properties(core), PW_KEY_CORE_DAEMON);
|
||||||
if (val && pw_properties_parse_bool(val)) {
|
if (val && pw_properties_parse_bool(val)) {
|
||||||
if (impl_add_server(this, core, properties) == NULL)
|
if (impl_add_server(this, core, properties) == NULL) {
|
||||||
return -errno;
|
res = -errno;
|
||||||
|
goto error_cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pw_module_add_listener(module, &d->module_listener, &module_events, d);
|
pw_module_add_listener(module, &d->module_listener, &module_events, d);
|
||||||
|
|
@ -900,6 +940,10 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie
|
||||||
pw_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
|
pw_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
error_cleanup:
|
||||||
|
pw_protocol_destroy(this);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPA_EXPORT
|
SPA_EXPORT
|
||||||
|
|
|
||||||
|
|
@ -62,13 +62,16 @@ int pw_protocol_native_connect_local_socket(struct pw_protocol_client *client,
|
||||||
|
|
||||||
if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) {
|
if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) {
|
||||||
pw_log_error("connect failed: XDG_RUNTIME_DIR not set in the environment");
|
pw_log_error("connect failed: XDG_RUNTIME_DIR not set in the environment");
|
||||||
return -EIO;
|
res = -EIO;
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = get_remote(pw_remote_get_properties(remote));
|
name = get_remote(pw_remote_get_properties(remote));
|
||||||
|
|
||||||
if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0)
|
if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) {
|
||||||
return -errno;
|
res = -errno;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
addr.sun_family = AF_LOCAL;
|
addr.sun_family = AF_LOCAL;
|
||||||
|
|
@ -94,7 +97,8 @@ int pw_protocol_native_connect_local_socket(struct pw_protocol_client *client,
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
error_close:
|
error_close:
|
||||||
close(fd);
|
close(fd);
|
||||||
|
error:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue