[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