protocol-native: always create a local server

Always create a local server without any socket. We can use this
to create clients that connect locally (in-process), such as
the cli or any app that wants to create a local pipeline.
This commit is contained in:
Wim Taymans 2019-12-10 16:23:43 +01:00
parent 8917e1e149
commit c0f5e8d967
3 changed files with 101 additions and 23 deletions

View file

@ -75,6 +75,8 @@ struct protocol_data {
struct pw_module *module; struct pw_module *module;
struct spa_hook module_listener; struct spa_hook module_listener;
struct pw_protocol *protocol; struct pw_protocol *protocol;
struct server *local;
}; };
struct client { struct client {
@ -317,7 +319,7 @@ static const struct pw_protocol_native_connection_events server_conn_events = {
.start = on_start, .start = on_start,
}; };
static struct pw_client *client_new(struct server *s, int fd) static struct client_data *client_new(struct server *s, int fd)
{ {
struct client_data *this; struct client_data *this;
struct pw_client *client; struct pw_client *client;
@ -360,6 +362,7 @@ static struct pw_client *client_new(struct server *s, int fd)
if (client == NULL) if (client == NULL)
goto exit; goto exit;
this = pw_client_get_user_data(client); this = pw_client_get_user_data(client);
client->protocol = protocol; client->protocol = protocol;
spa_list_append(&s->this.client_list, &client->protocol_link); spa_list_append(&s->this.client_list, &client->protocol_link);
@ -391,7 +394,11 @@ static struct pw_client *client_new(struct server *s, int fd)
if ((res = pw_client_register(client, NULL)) < 0) if ((res = pw_client_register(client, NULL)) < 0)
goto cleanup_client; goto cleanup_client;
return client; if (!client->busy)
pw_loop_update_io(pw_core_get_main_loop(core),
this->source, this->source->mask | SPA_IO_IN);
return this;
cleanup_client: cleanup_client:
pw_client_destroy(client); pw_client_destroy(client);
@ -472,8 +479,7 @@ static void
socket_data(void *data, int fd, uint32_t mask) socket_data(void *data, int fd, uint32_t mask)
{ {
struct server *s = data; struct server *s = data;
struct pw_client *client; struct client_data *client;
struct client_data *c;
struct sockaddr_un name; struct sockaddr_un name;
socklen_t length; socklen_t length;
int client_fd; int client_fd;
@ -491,11 +497,6 @@ socket_data(void *data, int fd, uint32_t mask)
close(client_fd); close(client_fd);
return; return;
} }
c = client->user_data;
if (!client->busy)
pw_loop_update_io(client->protocol->core->main_loop,
c->source, c->source->mask | SPA_IO_IN);
} }
static int add_socket(struct pw_protocol *protocol, struct server *s) static int add_socket(struct pw_protocol *protocol, struct server *s)
@ -764,9 +765,52 @@ static void impl_destroy(struct pw_protocol_client *client)
free(impl); free(impl);
} }
static int pw_protocol_native_connect_internal(struct pw_protocol_client *client,
const struct spa_dict *props,
void (*done_callback) (void *data, int res),
void *data)
{
int res, sv[2];
struct pw_protocol *protocol = client->protocol;
struct protocol_data *d = pw_protocol_get_user_data(protocol);
struct server *s = d->local;
struct pw_permission permissions[1];
struct client_data *c;
pw_log_debug("server %p: internal connect", s);
if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, sv) < 0) {
res = -errno;
pw_log_error("server %p: socketpair() failed with error: %m", s);
goto error;
}
c = client_new(s, sv[0]);
if (c == NULL) {
res = -errno;
pw_log_error("server %p: failed to create client: %m", s);
goto error_close;
}
permissions[0].id = SPA_ID_INVALID;
permissions[0].permissions = PW_PERM_RWX;
pw_client_update_permissions(c->client, 1, permissions);
res = pw_protocol_client_connect_fd(client, sv[1], true);
done:
if (done_callback)
done_callback(data, res);
return res;
error_close:
close(sv[0]);
close(sv[1]);
error:
goto done;
}
static struct pw_protocol_client * static struct pw_protocol_client *
impl_new_client(struct pw_protocol *protocol, impl_new_client(struct pw_protocol *protocol,
struct pw_properties *properties) const struct pw_properties *properties)
{ {
struct client *impl; struct client *impl;
struct pw_protocol_client *this; struct pw_protocol_client *this;
@ -776,6 +820,8 @@ impl_new_client(struct pw_protocol *protocol,
if ((impl = calloc(1, sizeof(struct client))) == NULL) if ((impl = calloc(1, sizeof(struct client))) == NULL)
return NULL; return NULL;
pw_log_debug(NAME" %p: new client %p", protocol, impl);
this = &impl->this; this = &impl->this;
this->protocol = protocol; this->protocol = protocol;
@ -786,13 +832,22 @@ impl_new_client(struct pw_protocol *protocol,
goto error_free; goto error_free;
} }
if (properties) if (properties) {
str = pw_properties_get(properties, PW_KEY_REMOTE_INTENTION); str = pw_properties_get(properties, PW_KEY_REMOTE_INTENTION);
if (str == NULL &&
(str = pw_properties_get(properties, PW_KEY_REMOTE_NAME)) != NULL &&
strcmp(str, impl->core->info.name) == 0)
str = "internal";
}
if (str == NULL) if (str == NULL)
str = "generic"; str = "generic";
pw_log_debug(NAME" %p: connect %s", protocol, str);
if (!strcmp(str, "screencast")) if (!strcmp(str, "screencast"))
this->connect = pw_protocol_native_connect_portal_screencast; this->connect = pw_protocol_native_connect_portal_screencast;
else if (!strcmp(str, "internal"))
this->connect = pw_protocol_native_connect_internal;
else else
this->connect = pw_protocol_native_connect_local_socket; this->connect = pw_protocol_native_connect_local_socket;
@ -880,15 +935,13 @@ get_name(const struct pw_properties *properties)
return name; return name;
} }
static struct pw_protocol_server * static struct server *
impl_add_server(struct pw_protocol *protocol, create_server(struct pw_protocol *protocol,
struct pw_properties *properties) const struct pw_properties *properties)
{ {
struct pw_protocol_server *this; struct pw_protocol_server *this;
struct pw_core *core = protocol->core; struct pw_core *core = protocol->core;
struct server *s; struct server *s;
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;
@ -902,10 +955,29 @@ impl_add_server(struct pw_protocol *protocol,
spa_list_append(&protocol->server_list, &this->link); spa_list_append(&protocol->server_list, &this->link);
name = get_name(pw_core_get_properties(core));
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);
pw_log_info(NAME" %p: created server %p", protocol, this);
return s;
}
static struct pw_protocol_server *
impl_add_server(struct pw_protocol *protocol,
const struct pw_properties *properties)
{
struct pw_protocol_server *this;
struct server *s;
const char *name;
int res;
if ((s = create_server(protocol, properties)) == NULL)
return NULL;
this = &s->this;
name = get_name(properties);
if ((res = init_socket_name(s, name)) < 0) if ((res = init_socket_name(s, name)) < 0)
goto error; goto error;
@ -915,7 +987,7 @@ impl_add_server(struct pw_protocol *protocol,
if ((res = add_socket(protocol, s)) < 0) if ((res = add_socket(protocol, s)) < 0)
goto error; goto error;
pw_log_info(NAME" %p: Added server %p %s", protocol, this, name); pw_log_info(NAME" %p: Listening on '%s'", protocol, name);
return this; return this;
@ -1017,6 +1089,7 @@ int pipewire__module_init(struct pw_module *module, const char *args)
struct pw_protocol *this; struct pw_protocol *this;
const char *val; const char *val;
struct protocol_data *d; struct protocol_data *d;
const struct pw_properties *props;
int res; 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)
@ -1040,11 +1113,15 @@ int pipewire__module_init(struct pw_module *module, const char *args)
d->protocol = this; d->protocol = this;
d->module = module; d->module = module;
d->local = create_server(this, props);
props = pw_core_get_properties(core);
val = getenv("PIPEWIRE_DAEMON"); val = getenv("PIPEWIRE_DAEMON");
if (val == NULL) if (val == NULL)
val = pw_properties_get(pw_core_get_properties(core), PW_KEY_CORE_DAEMON); val = pw_properties_get(props, PW_KEY_CORE_DAEMON);
if (val && pw_properties_parse_bool(val)) { if (val && pw_properties_parse_bool(val)) {
if (impl_add_server(this, NULL) == NULL) { if (impl_add_server(this, props) == NULL) {
res = -errno; res = -errno;
goto error_cleanup; goto error_cleanup;
} }

View file

@ -285,6 +285,7 @@ static struct pw_core_proxy *core_proxy_new(struct pw_core *core,
res = -errno; res = -errno;
goto exit_cleanup; goto exit_cleanup;
} }
pw_log_debug(NAME" %p: new", p);
if (properties == NULL) if (properties == NULL)
properties = pw_properties_new(NULL, NULL); properties = pw_properties_new(NULL, NULL);

View file

@ -91,9 +91,9 @@ struct pw_protocol_implementaton {
uint32_t version; uint32_t version;
struct pw_protocol_client * (*new_client) (struct pw_protocol *protocol, struct pw_protocol_client * (*new_client) (struct pw_protocol *protocol,
struct pw_properties *properties); const struct pw_properties *properties);
struct pw_protocol_server * (*add_server) (struct pw_protocol *protocol, struct pw_protocol_server * (*add_server) (struct pw_protocol *protocol,
struct pw_properties *properties); const struct pw_properties *properties);
}; };
struct pw_protocol_events { struct pw_protocol_events {