mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	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:
		
							parent
							
								
									8917e1e149
								
							
						
					
					
						commit
						c0f5e8d967
					
				
					 3 changed files with 101 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -75,6 +75,8 @@ struct protocol_data {
 | 
			
		|||
	struct pw_module *module;
 | 
			
		||||
	struct spa_hook module_listener;
 | 
			
		||||
	struct pw_protocol *protocol;
 | 
			
		||||
 | 
			
		||||
	struct server *local;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct client {
 | 
			
		||||
| 
						 | 
				
			
			@ -317,7 +319,7 @@ static const struct pw_protocol_native_connection_events server_conn_events = {
 | 
			
		|||
	.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 pw_client *client;
 | 
			
		||||
| 
						 | 
				
			
			@ -360,6 +362,7 @@ static struct pw_client *client_new(struct server *s, int fd)
 | 
			
		|||
	if (client == NULL)
 | 
			
		||||
		goto exit;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	this = pw_client_get_user_data(client);
 | 
			
		||||
	client->protocol = protocol;
 | 
			
		||||
	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)
 | 
			
		||||
		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:
 | 
			
		||||
	pw_client_destroy(client);
 | 
			
		||||
| 
						 | 
				
			
			@ -472,8 +479,7 @@ static void
 | 
			
		|||
socket_data(void *data, int fd, uint32_t mask)
 | 
			
		||||
{
 | 
			
		||||
	struct server *s = data;
 | 
			
		||||
	struct pw_client *client;
 | 
			
		||||
	struct client_data *c;
 | 
			
		||||
	struct client_data *client;
 | 
			
		||||
	struct sockaddr_un name;
 | 
			
		||||
	socklen_t length;
 | 
			
		||||
	int client_fd;
 | 
			
		||||
| 
						 | 
				
			
			@ -491,11 +497,6 @@ socket_data(void *data, int fd, uint32_t mask)
 | 
			
		|||
		close(client_fd);
 | 
			
		||||
		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)
 | 
			
		||||
| 
						 | 
				
			
			@ -764,9 +765,52 @@ static void impl_destroy(struct pw_protocol_client *client)
 | 
			
		|||
	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 *
 | 
			
		||||
impl_new_client(struct pw_protocol *protocol,
 | 
			
		||||
		struct pw_properties *properties)
 | 
			
		||||
		const struct pw_properties *properties)
 | 
			
		||||
{
 | 
			
		||||
	struct client *impl;
 | 
			
		||||
	struct pw_protocol_client *this;
 | 
			
		||||
| 
						 | 
				
			
			@ -776,6 +820,8 @@ impl_new_client(struct pw_protocol *protocol,
 | 
			
		|||
	if ((impl = calloc(1, sizeof(struct client))) == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	pw_log_debug(NAME" %p: new client %p", protocol, impl);
 | 
			
		||||
 | 
			
		||||
	this = &impl->this;
 | 
			
		||||
	this->protocol = protocol;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -786,13 +832,22 @@ impl_new_client(struct pw_protocol *protocol,
 | 
			
		|||
		goto error_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (properties)
 | 
			
		||||
	if (properties) {
 | 
			
		||||
		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)
 | 
			
		||||
		str = "generic";
 | 
			
		||||
 | 
			
		||||
	pw_log_debug(NAME" %p: connect %s", protocol, str);
 | 
			
		||||
 | 
			
		||||
	if (!strcmp(str, "screencast"))
 | 
			
		||||
		this->connect = pw_protocol_native_connect_portal_screencast;
 | 
			
		||||
	else if (!strcmp(str, "internal"))
 | 
			
		||||
		this->connect = pw_protocol_native_connect_internal;
 | 
			
		||||
	else
 | 
			
		||||
		this->connect = pw_protocol_native_connect_local_socket;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -880,15 +935,13 @@ get_name(const struct pw_properties *properties)
 | 
			
		|||
	return name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct pw_protocol_server *
 | 
			
		||||
impl_add_server(struct pw_protocol *protocol,
 | 
			
		||||
                struct pw_properties *properties)
 | 
			
		||||
static struct server *
 | 
			
		||||
create_server(struct pw_protocol *protocol,
 | 
			
		||||
                const struct pw_properties *properties)
 | 
			
		||||
{
 | 
			
		||||
	struct pw_protocol_server *this;
 | 
			
		||||
	struct pw_core *core = protocol->core;
 | 
			
		||||
	struct server *s;
 | 
			
		||||
	const char *name;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	if ((s = calloc(1, sizeof(struct server))) == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -902,10 +955,29 @@ impl_add_server(struct pw_protocol *protocol,
 | 
			
		|||
 | 
			
		||||
	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_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)
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -915,7 +987,7 @@ impl_add_server(struct pw_protocol *protocol,
 | 
			
		|||
	if ((res = add_socket(protocol, s)) < 0)
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1017,6 +1089,7 @@ int pipewire__module_init(struct pw_module *module, const char *args)
 | 
			
		|||
	struct pw_protocol *this;
 | 
			
		||||
	const char *val;
 | 
			
		||||
	struct protocol_data *d;
 | 
			
		||||
	const struct pw_properties *props;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	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->module = module;
 | 
			
		||||
 | 
			
		||||
	d->local = create_server(this, props);
 | 
			
		||||
 | 
			
		||||
	props = pw_core_get_properties(core);
 | 
			
		||||
 | 
			
		||||
	val = getenv("PIPEWIRE_DAEMON");
 | 
			
		||||
	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 (impl_add_server(this, NULL) == NULL) {
 | 
			
		||||
		if (impl_add_server(this, props) == NULL) {
 | 
			
		||||
			res = -errno;
 | 
			
		||||
			goto error_cleanup;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -285,6 +285,7 @@ static struct pw_core_proxy *core_proxy_new(struct pw_core *core,
 | 
			
		|||
		res = -errno;
 | 
			
		||||
		goto exit_cleanup;
 | 
			
		||||
	}
 | 
			
		||||
	pw_log_debug(NAME" %p: new", p);
 | 
			
		||||
 | 
			
		||||
	if (properties == NULL)
 | 
			
		||||
		properties = pw_properties_new(NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,9 +91,9 @@ struct pw_protocol_implementaton {
 | 
			
		|||
	uint32_t version;
 | 
			
		||||
 | 
			
		||||
	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_properties *properties);
 | 
			
		||||
						   const struct pw_properties *properties);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct pw_protocol_events {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue