broadway: Support fd passing in protocol

This will be used to pass buffers
This commit is contained in:
Alexander Larsson 2017-11-17 15:57:28 +01:00
parent 43a02da07b
commit f31d7e1f91
2 changed files with 86 additions and 12 deletions

View File

@ -13,6 +13,7 @@
#include <gio/gio.h> #include <gio/gio.h>
#ifdef G_OS_UNIX #ifdef G_OS_UNIX
#include <gio/gunixsocketaddress.h> #include <gio/gunixsocketaddress.h>
#include <gio/gunixfdmessage.h>
#endif #endif
#include "broadway-server.h" #include "broadway-server.h"
@ -54,8 +55,15 @@ typedef struct {
GSList *serial_mappings; GSList *serial_mappings;
GList *windows; GList *windows;
guint disconnect_idle; guint disconnect_idle;
GList *fds;
} BroadwayClient; } BroadwayClient;
static void
close_fd (void *data)
{
close (GPOINTER_TO_INT (data));
}
static void static void
client_free (BroadwayClient *client) client_free (BroadwayClient *client)
{ {
@ -66,6 +74,7 @@ client_free (BroadwayClient *client)
g_object_unref (client->in); g_object_unref (client->in);
g_string_free (client->buffer, TRUE); g_string_free (client->buffer, TRUE);
g_slist_free_full (client->serial_mappings, g_free); g_slist_free_full (client->serial_mappings, g_free);
g_list_free_full (client->fds, close_fd);
g_free (client); g_free (client);
} }
@ -341,6 +350,9 @@ client_input_cb (GPollableInputStream *stream,
gsize old_len; gsize old_len;
guchar *buffer; guchar *buffer;
gsize buffer_len; gsize buffer_len;
GInputVector input_vector;
GSocketControlMessage **messages = NULL;
int i, num_messages;
old_len = client->buffer->len; old_len = client->buffer->len;
@ -348,10 +360,13 @@ client_input_cb (GPollableInputStream *stream,
g_string_set_size (client->buffer, old_len + INPUT_BUFFER_SIZE); g_string_set_size (client->buffer, old_len + INPUT_BUFFER_SIZE);
g_string_set_size (client->buffer, old_len); g_string_set_size (client->buffer, old_len);
res = g_socket_receive_with_blocking (socket, client->buffer->str + old_len, input_vector.buffer = client->buffer->str + old_len;
client->buffer->allocated_len - client->buffer->len -1, input_vector.size = client->buffer->allocated_len - client->buffer->len -1;
FALSE, NULL, NULL);
res = g_socket_receive_message (socket, NULL,
&input_vector, 1,
&messages, &num_messages,
NULL, NULL, NULL);
if (res <= 0) if (res <= 0)
{ {
client->source = NULL; client->source = NULL;
@ -359,6 +374,23 @@ client_input_cb (GPollableInputStream *stream,
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
for (i = 0; i < num_messages; i++)
{
if (G_IS_UNIX_FD_MESSAGE (messages[i]))
{
int j, n_fds;
int *fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (messages[i]), &n_fds);
for (j = 0; j < n_fds; j++)
{
int fd = fds[i];
client->fds = g_list_append (client->fds, GINT_TO_POINTER (fd));
}
g_free (fds);
}
g_object_unref (messages[i]);
}
g_free (messages);
g_string_set_size (client->buffer, old_len + res); g_string_set_size (client->buffer, old_len + res);
buffer = (guchar *)client->buffer->str; buffer = (guchar *)client->buffer->str;

View File

@ -12,9 +12,8 @@
#include <glib.h> #include <glib.h>
#include <glib/gprintf.h> #include <glib/gprintf.h>
#ifdef G_OS_UNIX
#include <gio/gunixsocketaddress.h> #include <gio/gunixsocketaddress.h>
#endif #include <gio/gunixfdmessage.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
@ -160,30 +159,73 @@ _gdk_broadway_server_get_last_seen_time (GdkBroadwayServer *server)
static guint32 static guint32
gdk_broadway_server_send_message_with_size (GdkBroadwayServer *server, BroadwayRequestBase *base, gdk_broadway_server_send_message_with_size (GdkBroadwayServer *server, BroadwayRequestBase *base,
gsize size, guint32 type) gsize size, guint32 type, int fd)
{ {
GOutputStream *out; GOutputStream *out;
gsize written; gsize written;
guchar *buf;
base->size = size; base->size = size;
base->type = type; base->type = type;
base->serial = server->next_serial++; base->serial = server->next_serial++;
out = g_io_stream_get_output_stream (G_IO_STREAM (server->connection)); buf = (guchar *)base;
if (!g_output_stream_write_all (out, base, size, &written, NULL, NULL)) if (fd != -1)
{ {
g_printerr ("Unable to write to server\n"); GUnixFDList *fd_list = g_unix_fd_list_new_from_array (&fd, 1);
exit (1); GSocketControlMessage *control_message = g_unix_fd_message_new_with_fd_list (fd_list);
GSocket *socket = g_socket_connection_get_socket (server->connection);
GOutputVector vector;
gssize bytes_written;
vector.buffer = buf;
vector.size = size;
bytes_written = g_socket_send_message (socket,
NULL, /* address */
&vector,
1,
&control_message, 1,
G_SOCKET_MSG_NONE,
NULL,
NULL);
if (bytes_written <= 0)
{
g_printerr ("Unable to write to server\n");
exit (1);
}
g_print ("socket send message wrote %d of %d\n", (int)bytes_written, (int)size);
buf += bytes_written;
size -= bytes_written;
g_object_unref (control_message);
g_object_unref (fd_list);
}
if (size > 0)
{
out = g_io_stream_get_output_stream (G_IO_STREAM (server->connection));
if (!g_output_stream_write_all (out, buf, size, &written, NULL, NULL))
{
g_printerr ("Unable to write to server\n");
exit (1);
}
g_assert (written == size);
} }
g_assert (written == size);
return base->serial; return base->serial;
} }
#define gdk_broadway_server_send_message(_server, _msg, _type) \ #define gdk_broadway_server_send_message(_server, _msg, _type) \
gdk_broadway_server_send_message_with_size(_server, (BroadwayRequestBase *)&_msg, sizeof (_msg), _type) gdk_broadway_server_send_message_with_size(_server, (BroadwayRequestBase *)&_msg, sizeof (_msg), _type, -1)
#define gdk_broadway_server_send_fd_message(_server, _msg, _type, _fd) \
gdk_broadway_server_send_message_with_size(_server, (BroadwayRequestBase *)&_msg, sizeof (_msg), _type, _fd)
static void static void
parse_all_input (GdkBroadwayServer *server) parse_all_input (GdkBroadwayServer *server)