[RFC wayland 13/18] connections: Add remote sockets

Derek Foreman derekf at osg.samsung.com
Tue Feb 9 16:56:00 UTC 2016


This allows adding a tcp/ip socket and adds tracking of the remote status
for clients and proxies

Signed-off-by: Derek Foreman <derekf at osg.samsung.com>
---
 src/connection.c          |  11 +++-
 src/wayland-client.c      | 103 +++++++++++++++++++++++++-------
 src/wayland-private.h     |   5 ++
 src/wayland-server-core.h |   7 +++
 src/wayland-server.c      | 146 ++++++++++++++++++++++++++++++++++++----------
 5 files changed, 221 insertions(+), 51 deletions(-)

diff --git a/src/connection.c b/src/connection.c
index 05806b6..5fd085f 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -39,6 +39,7 @@
 #include <sys/socket.h>
 #include <time.h>
 #include <ffi.h>
+#include <stdbool.h>
 
 #include "wayland-util.h"
 #include "wayland-private.h"
@@ -61,6 +62,7 @@ struct wl_connection {
 	struct wl_buffer fds_in, fds_out;
 	int fd;
 	int want_flush;
+	bool remote;
 };
 
 static int
@@ -191,6 +193,12 @@ close_fds(struct wl_buffer *buffer, int max)
 	buffer->tail += size;
 }
 
+void
+wl_connection_set_remote(struct wl_connection *connection)
+{
+	connection->remote = true;
+}
+
 int
 wl_connection_destroy(struct wl_connection *connection)
 {
@@ -278,6 +286,7 @@ wl_connection_flush(struct wl_connection *connection)
 	char cmsg[CLEN];
 	int len = 0, count, clen;
 	uint32_t tail;
+	int wait = connection->remote ? 0 : MSG_DONTWAIT;
 
 	if (!connection->want_flush)
 		return 0;
@@ -298,7 +307,7 @@ wl_connection_flush(struct wl_connection *connection)
 
 		do {
 			len = sendmsg(connection->fd, &msg,
-				      MSG_NOSIGNAL | MSG_DONTWAIT);
+				      MSG_NOSIGNAL | wait);
 		} while (len == -1 && errno == EINTR);
 
 		if (len == -1)
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 8e7f612..1582760 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -36,11 +36,13 @@
 #include <unistd.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <netinet/in.h>
 #include <ctype.h>
 #include <assert.h>
 #include <fcntl.h>
 #include <poll.h>
 #include <pthread.h>
+#include <netdb.h>
 
 #include "wayland-util.h"
 #include "wayland-os.h"
@@ -344,6 +346,7 @@ proxy_create(struct wl_proxy *factory, const struct wl_interface *interface,
 	proxy->refcount = 1;
 	proxy->version = version;
 
+	proxy->object.remote = display->proxy.object.remote;
 	proxy->object.id = wl_map_insert_new(&display->objects, 0, proxy);
 
 	return proxy;
@@ -825,26 +828,41 @@ static const struct wl_display_listener display_listener = {
 };
 
 static int
-connect_to_socket(const char *name)
+connect_remote(const char *name)
 {
-	struct sockaddr_un addr;
-	socklen_t size;
-	const char *runtime_dir;
-	int name_size, fd;
+	int fd = -1;
+	char *host, *tmp;
+	struct addrinfo *result;
 
-	runtime_dir = getenv("XDG_RUNTIME_DIR");
-	if (!runtime_dir) {
-		wl_log("error: XDG_RUNTIME_DIR not set in the environment.\n");
-		/* to prevent programs reporting
-		 * "failed to create display: Success" */
-		errno = ENOENT;
-		return -1;
+	host = strdup(strchr(name, ':')+1);
+	tmp = strchr(host, ':');
+	if (!tmp)
+		goto fail;
+	*tmp = 0;
+	fprintf(stderr, "CONNECT TO %s\n", host);
+
+	if (getaddrinfo(host, "31337", NULL, &result))
+		goto fail;
+
+	fd = wl_os_socket_cloexec(PF_INET, SOCK_STREAM, 0);
+
+	if (connect(fd, result->ai_addr, result->ai_addrlen) < 0) {
+		close(fd);
+		fd = -1;
+		goto fail;
 	}
+fail:
+	free(host);
+	freeaddrinfo(result);
+	return fd;
+}
 
-	if (name == NULL)
-		name = getenv("WAYLAND_DISPLAY");
-	if (name == NULL)
-		name = "wayland-0";
+static int
+connect_local(const char *runtime_dir, const char *name)
+{
+	int fd, name_size;
+	struct sockaddr_un addr;
+	socklen_t size;
 
 	fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
 	if (fd < 0)
@@ -873,10 +891,36 @@ connect_to_socket(const char *name)
 		close(fd);
 		return -1;
 	}
-
 	return fd;
 }
 
+static int
+connect_to_socket(const char *name, bool *remote)
+{
+	const char *runtime_dir;
+
+	runtime_dir = getenv("XDG_RUNTIME_DIR");
+	if (!runtime_dir) {
+		wl_log("error: XDG_RUNTIME_DIR not set in the environment.\n");
+		/* to prevent programs reporting
+		 * "failed to create display: Success" */
+		errno = ENOENT;
+		return -1;
+	}
+
+	if (name == NULL)
+		name = getenv("WAYLAND_DISPLAY");
+	if (name == NULL)
+		name = "wayland-0";
+
+	if (strchr(name, ':')) {
+		*remote = true;
+		return connect_remote(name);
+	}
+	*remote = false;
+	return connect_local(runtime_dir, name);
+}
+
 /** Connect to Wayland display on an already open fd
  *
  * \param fd The fd to use for the connection
@@ -923,6 +967,7 @@ wl_display_connect_to_fd(int fd)
 	display->proxy.queue = &display->default_queue;
 	display->proxy.flags = 0;
 	display->proxy.refcount = 1;
+	display->proxy.object.remote = false;
 
 	/* We set this version to 0 for backwards compatibility.
 	 *
@@ -973,8 +1018,10 @@ wl_display_connect_to_fd(int fd)
 WL_EXPORT struct wl_display *
 wl_display_connect(const char *name)
 {
+	struct wl_display *display;
 	char *connection, *end;
 	int flags, fd;
+	bool remote = false;
 
 	connection = getenv("WAYLAND_SOCKET");
 	if (connection) {
@@ -990,12 +1037,15 @@ wl_display_connect(const char *name)
 			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
 		unsetenv("WAYLAND_SOCKET");
 	} else {
-		fd = connect_to_socket(name);
+		fd = connect_to_socket(name, &remote);
 		if (fd < 0)
 			return NULL;
 	}
-
-	return wl_display_connect_to_fd(fd);
+	display = wl_display_connect_to_fd(fd);
+	display->proxy.object.remote = remote;
+	if (display->proxy.object.remote)
+		wl_connection_set_remote(display->connection);
+	return display;
 }
 
 /** Close a connection to a Wayland display
@@ -1904,6 +1954,19 @@ wl_proxy_get_hook_data(struct wl_proxy *proxy)
 	return proxy->hook_data;
 }
 
+/** Get whether a proxy is remote or not
+ *
+ * \param proxy The proxy object
+ * \return True if the proxy is remote
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT bool
+wl_proxy_get_remote(struct wl_proxy *proxy)
+{
+	return proxy->object.remote;
+}
+
 /** Get the id of a proxy object
  *
  * \param proxy The proxy object
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 994bc45..67de269 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -30,6 +30,7 @@
 
 #include <stdarg.h>
 #include <stdlib.h>
+#include <stdbool.h>
 
 #define WL_HIDE_DEPRECATED 1
 
@@ -50,6 +51,7 @@ struct wl_object {
 	const struct wl_interface *interface;
 	const void *implementation;
 	uint32_t id;
+	bool remote;
 };
 
 extern struct wl_object global_zombie_object;
@@ -114,6 +116,9 @@ int
 wl_connection_destroy(struct wl_connection *connection);
 
 void
+wl_connection_set_remote(struct wl_connection *connection);
+
+void
 wl_connection_copy(struct wl_connection *connection, void *data, size_t size);
 
 void
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index 3316022..72581a7 100644
--- a/src/wayland-server-core.h
+++ b/src/wayland-server-core.h
@@ -32,6 +32,7 @@ extern "C" {
 
 #include <sys/types.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include "wayland-util.h"
 #include "wayland-version.h"
 
@@ -128,6 +129,9 @@ wl_display_get_event_loop(struct wl_display *display);
 int
 wl_display_add_socket(struct wl_display *display, const char *name);
 
+int
+wl_display_add_remote_socket(struct wl_display *display, const char *name);
+
 const char *
 wl_display_add_socket_auto(struct wl_display *display);
 
@@ -488,6 +492,9 @@ wl_shm_buffer_get_fd(struct wl_shm_buffer *buffer);
 
 void wl_log_set_handler_server(wl_log_func_t handler);
 
+bool
+wl_client_is_remote(struct wl_client *client);
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/src/wayland-server.c b/src/wayland-server.c
index ae9365f..270bcdb 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -36,6 +36,7 @@
 #include <unistd.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <netinet/in.h>
 #include <dlfcn.h>
 #include <assert.h>
 #include <sys/time.h>
@@ -59,13 +60,20 @@
 #define LOCK_SUFFIX	".lock"
 #define LOCK_SUFFIXLEN	5
 
+struct wl_display;
+
 struct wl_socket {
 	int fd;
 	int fd_lock;
-	struct sockaddr_un addr;
+	bool remote;
+	union {
+		struct sockaddr_un local;
+		struct sockaddr_in remote;
+	} addr;
 	char lock_addr[UNIX_PATH_MAX + LOCK_SUFFIXLEN];
 	struct wl_list link;
 	struct wl_event_source *source;
+	struct wl_display *display;
 	char *display_name;
 };
 
@@ -81,6 +89,7 @@ struct wl_client {
 	struct wl_signal destroy_signal;
 	struct ucred ucred;
 	int error;
+	bool remote;
 };
 
 struct wl_display {
@@ -123,6 +132,12 @@ struct wl_resource {
 
 static int debug_server = 0;
 
+WL_EXPORT bool
+wl_client_is_remote(struct wl_client *client)
+{
+	return client->remote;
+}
+
 WL_EXPORT void
 wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode,
 			     union wl_argument *args)
@@ -878,8 +893,8 @@ wl_socket_destroy(struct wl_socket *s)
 {
 	if (s->source)
 		wl_event_source_remove(s->source);
-	if (s->addr.sun_path[0])
-		unlink(s->addr.sun_path);
+	if (!s->remote && s->addr.local.sun_path[0])
+			unlink(s->addr.local.sun_path);
 	if (s->fd >= 0)
 		close(s->fd);
 	if (s->lock_addr[0])
@@ -1073,7 +1088,9 @@ wl_display_flush_clients(struct wl_display *display)
 static int
 socket_data(int fd, uint32_t mask, void *data)
 {
-	struct wl_display *display = data;
+	struct wl_client *client;
+	struct wl_socket *socket = data;
+	struct wl_display *display = socket->display;
 	struct sockaddr_un name;
 	socklen_t length;
 	int client_fd;
@@ -1081,11 +1098,20 @@ socket_data(int fd, uint32_t mask, void *data)
 	length = sizeof name;
 	client_fd = wl_os_accept_cloexec(fd, (struct sockaddr *) &name,
 					 &length);
-	if (client_fd < 0)
+	if (client_fd < 0) {
 		wl_log("failed to accept: %m\n");
-	else
-		if (!wl_client_create(display, client_fd))
-			close(client_fd);
+		return 1;
+	}
+
+	client = wl_client_create(display, client_fd);
+	if (!client) {
+		close(client_fd);
+		return 1;
+	}
+
+	client->remote = socket->remote;
+	if (client->remote)
+		wl_connection_set_remote(client->connection);
 
 	return 1;
 }
@@ -1095,8 +1121,11 @@ wl_socket_lock(struct wl_socket *socket)
 {
 	struct stat socket_stat;
 
+	if (socket->remote)
+		return 0;
+
 	snprintf(socket->lock_addr, sizeof socket->lock_addr,
-		 "%s%s", socket->addr.sun_path, LOCK_SUFFIX);
+		 "%s%s", socket->addr.local.sun_path, LOCK_SUFFIX);
 
 	socket->fd_lock = open(socket->lock_addr, O_CREAT | O_CLOEXEC,
 			       (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
@@ -1113,15 +1142,15 @@ wl_socket_lock(struct wl_socket *socket)
 		goto err_fd;
 	}
 
-	if (stat(socket->addr.sun_path, &socket_stat) < 0 ) {
+	if (stat(socket->addr.local.sun_path, &socket_stat) < 0 ) {
 		if (errno != ENOENT) {
 			wl_log("did not manage to stat file %s\n",
-				socket->addr.sun_path);
+				socket->addr.local.sun_path);
 			goto err_fd;
 		}
 	} else if (socket_stat.st_mode & S_IWUSR ||
 		   socket_stat.st_mode & S_IWGRP) {
-		unlink(socket->addr.sun_path);
+		unlink(socket->addr.local.sun_path);
 	}
 
 	return 0;
@@ -1134,16 +1163,17 @@ err:
 	 * socket won't be created anyway. This prevents the
 	 * wl_socket_destroy from unlinking already existing socket
 	 * created by other compositor */
-	*socket->addr.sun_path = 0;
+	*socket->addr.local.sun_path = 0;
 
 	return -1;
 }
 
 static int
-wl_socket_init_for_display_name(struct wl_socket *s, const char *name)
+wl_socket_init_for_display_name(struct wl_socket *s, const char *name, bool remote)
 {
 	int name_size;
 	const char *runtime_dir;
+	char remote_lock[108];
 
 	runtime_dir = getenv("XDG_RUNTIME_DIR");
 	if (!runtime_dir) {
@@ -1155,17 +1185,28 @@ wl_socket_init_for_display_name(struct wl_socket *s, const char *name)
 		return -1;
 	}
 
-	s->addr.sun_family = AF_LOCAL;
-	name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path,
-			     "%s/%s", runtime_dir, name) + 1;
-
-	s->display_name = (s->addr.sun_path + name_size - 1) - strlen(name);
+	s->remote = remote;
+	if (remote) {
+		s->addr.remote.sin_family = AF_INET;
+		s->addr.remote.sin_port = htons(31337);
+		s->addr.remote.sin_addr.s_addr = INADDR_ANY;
+		name_size = snprintf(remote_lock,
+				     sizeof remote_lock,
+				     "%s/%s", runtime_dir, name) + 1;
+		s->display_name = strdup(name);
+	} else {
+		s->addr.local.sun_family = AF_LOCAL;
+		name_size = snprintf(s->addr.local.sun_path,
+				     sizeof s->addr.local.sun_path,
+				     "%s/%s", runtime_dir, name) + 1;
 
+		s->display_name = (s->addr.local.sun_path + name_size - 1) - strlen(name);
+	}
 	assert(name_size > 0);
-	if (name_size > (int)sizeof s->addr.sun_path) {
+	if (name_size > (int)sizeof s->addr.local.sun_path) {
 		wl_log("error: socket path \"%s/%s\" plus null terminator"
 		       " exceeds 108 bytes\n", runtime_dir, name);
-		*s->addr.sun_path = 0;
+		*s->addr.local.sun_path = 0;
 		/* to prevent programs reporting
 		 * "failed to add socket: Success" */
 		errno = ENAMETOOLONG;
@@ -1176,17 +1217,29 @@ wl_socket_init_for_display_name(struct wl_socket *s, const char *name)
 }
 
 static int
-_wl_display_add_socket(struct wl_display *display, struct wl_socket *s)
+_wl_display_add_socket(struct wl_display *display, struct wl_socket *s, bool remote)
 {
 	socklen_t size;
+	struct sockaddr *sockaddr;
+
+	if (remote) {
+		s->fd = wl_os_socket_cloexec(PF_INET, SOCK_STREAM, 0);
+		wl_os_socket_reuseaddr(s->fd);
+	} else
+		s->fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
 
-	s->fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
 	if (s->fd < 0) {
 		return -1;
 	}
 
-	size = offsetof (struct sockaddr_un, sun_path) + strlen(s->addr.sun_path);
-	if (bind(s->fd, (struct sockaddr *) &s->addr, size) < 0) {
+	sockaddr = (struct sockaddr *)&s->addr;
+	if (remote)
+		size = sizeof(struct sockaddr_in);
+	else
+		size = offsetof (struct sockaddr_un, sun_path)
+		     + strlen(s->addr.local.sun_path);
+
+	if (bind(s->fd, sockaddr, size) < 0) {
 		wl_log("bind() failed with error: %m\n");
 		return -1;
 	}
@@ -1196,9 +1249,10 @@ _wl_display_add_socket(struct wl_display *display, struct wl_socket *s)
 		return -1;
 	}
 
+	s->display = display;
 	s->source = wl_event_loop_add_fd(display->loop, s->fd,
 					 WL_EVENT_READABLE,
-					 socket_data, display);
+					 socket_data, s);
 	if (s->source == NULL) {
 		return -1;
 	}
@@ -1224,7 +1278,7 @@ wl_display_add_socket_auto(struct wl_display *display)
 
 	do {
 		snprintf(display_name, sizeof display_name, "wayland-%d", displayno);
-		if (wl_socket_init_for_display_name(s, display_name) < 0) {
+		if (wl_socket_init_for_display_name(s, display_name, false) < 0) {
 			wl_socket_destroy(s);
 			return NULL;
 		}
@@ -1232,7 +1286,7 @@ wl_display_add_socket_auto(struct wl_display *display)
 		if (wl_socket_lock(s) < 0)
 			continue;
 
-		if (_wl_display_add_socket(display, s) < 0) {
+		if (_wl_display_add_socket(display, s, false) < 0) {
 			wl_socket_destroy(s);
 			return NULL;
 		}
@@ -1328,7 +1382,38 @@ wl_display_add_socket(struct wl_display *display, const char *name)
 	if (name == NULL)
 		name = "wayland-0";
 
-	if (wl_socket_init_for_display_name(s, name) < 0) {
+	if (wl_socket_init_for_display_name(s, name, false) < 0) {
+		wl_socket_destroy(s);
+		return -1;
+	}
+
+	if (wl_socket_lock(s) < 0) {
+		wl_socket_destroy(s);
+		return -1;
+	}
+
+	if (_wl_display_add_socket(display, s, false) < 0) {
+		wl_socket_destroy(s);
+		return -1;
+	}
+
+	return 0;
+}
+
+WL_EXPORT int
+wl_display_add_remote_socket(struct wl_display *display, const char *name)
+{
+	struct wl_socket *s;
+
+	s = wl_socket_alloc();
+	if (s == NULL)
+		return -1;
+	if (name == NULL)
+		name = getenv("WAYLAND_DISPLAY");
+	if (name == NULL)
+		name = "wayland-0";
+
+	if (wl_socket_init_for_display_name(s, name, true) < 0) {
 		wl_socket_destroy(s);
 		return -1;
 	}
@@ -1338,7 +1423,7 @@ wl_display_add_socket(struct wl_display *display, const char *name)
 		return -1;
 	}
 
-	if (_wl_display_add_socket(display, s) < 0) {
+	if (_wl_display_add_socket(display, s, true) < 0) {
 		wl_socket_destroy(s);
 		return -1;
 	}
@@ -1400,6 +1485,7 @@ wl_resource_create(struct wl_client *client,
 	resource->object.id = id;
 	resource->object.interface = interface;
 	resource->object.implementation = NULL;
+	resource->object.remote = client->remote;
 
 	wl_signal_init(&resource->destroy_signal);
 
-- 
2.7.0



More information about the wayland-devel mailing list