aboutsummaryrefslogtreecommitdiffstats
path: root/src/wth-receiver-comm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wth-receiver-comm.c')
-rw-r--r--src/wth-receiver-comm.c453
1 files changed, 453 insertions, 0 deletions
diff --git a/src/wth-receiver-comm.c b/src/wth-receiver-comm.c
new file mode 100644
index 0000000..e6c0266
--- /dev/null
+++ b/src/wth-receiver-comm.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ * Copyright © 2020 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*******************************************************************************
+** **
+** TARGET : linux **
+** **
+** PROJECT : waltham-receiver **
+** **
+** PURPOSE : This file acts as interface to waltham IPC library **
+** **
+** **
+*******************************************************************************/
+
+#include "wth-receiver-comm.h"
+#include "wth-receiver-surface.h"
+#include "wth-receiver-seat.h"
+#include "wth-receiver-buffer.h"
+
+extern uint16_t tcp_port;
+extern const char *my_app_id;
+
+void
+client_post_out_of_memory(struct client *c)
+{
+ struct wth_display *disp;
+
+ disp = wth_connection_get_display(c->connection);
+ wth_object_post_error((struct wth_object *) disp, 1, "out of memory");
+}
+
+/*
+ * waltam ivi surface implementation
+ */
+static void
+wthp_ivi_surface_destroy(struct wthp_ivi_surface * ivi_surface)
+{
+ struct ivisurface *ivisurf = wth_object_get_user_data((struct wth_object *)ivi_surface);
+
+ if (ivisurf->surf->ivi_app_id)
+ free(ivisurf->surf->ivi_app_id);
+
+ free(ivisurf);
+}
+
+static const struct wthp_ivi_surface_interface wthp_ivi_surface_implementation = {
+ wthp_ivi_surface_destroy,
+};
+
+
+/**
+ * app_id version
+ */
+static void
+wthp_ivi_app_id_surface_create(struct wthp_ivi_app_id *ivi_application,
+ const char *app_id,
+ struct wthp_surface * wthp_surface,
+ struct wthp_ivi_surface *obj)
+{
+ struct surface *surface = wth_object_get_user_data((struct wth_object *)wthp_surface);
+
+ /* we destroy it wthp_ivi_surface_implementation:: */
+ if (my_app_id) {
+ surface->ivi_app_id = strdup(my_app_id);
+ surface->shm_window->app_id = surface->ivi_app_id;
+ }
+
+ struct ivisurface *ivisurf;
+
+ ivisurf = zalloc(sizeof *ivisurf);
+ if (!ivisurf) {
+ return;
+ }
+
+ ivisurf->obj = obj;
+ ivisurf->surf = surface;
+
+ wthp_ivi_surface_set_interface(obj,
+ &wthp_ivi_surface_implementation, ivisurf);
+
+ if (my_app_id)
+ wth_receiver_weston_main(surface->shm_window, my_app_id, tcp_port);
+ else
+ wth_receiver_weston_main(surface->shm_window, app_id, tcp_port);
+
+ while (!surface->shm_window->ready)
+ usleep(1);
+}
+
+static const struct wthp_ivi_app_id_interface wthp_ivi_app_id_implementation = {
+ wthp_ivi_app_id_surface_create,
+};
+
+static void
+client_bind_wthp_ivi_app_id(struct client *c, struct wthp_ivi_app_id *obj)
+{
+ struct application_id *app;
+
+ app = zalloc(sizeof *app);
+ if (!app) {
+ client_post_out_of_memory(c);
+ return;
+ }
+
+ app->obj = obj;
+ app->client = c;
+ wl_list_insert(&c->compositor_list, &app->link);
+
+ wthp_ivi_app_id_set_interface(obj, &wthp_ivi_app_id_implementation, app);
+}
+
+/*
+ * waltham registry implementation
+ */
+static void
+registry_destroy(struct registry *reg)
+{
+ wthp_registry_free(reg->obj);
+ wl_list_remove(&reg->link);
+ free(reg);
+}
+
+static void
+registry_handle_destroy(struct wthp_registry *registry)
+{
+ struct registry *reg = wth_object_get_user_data((struct wth_object *)registry);
+ registry_destroy(reg);
+}
+
+static void
+registry_handle_bind(struct wthp_registry *registry,
+ uint32_t name, struct wth_object *id,
+ const char *interface, uint32_t version)
+{
+
+ struct registry *reg = wth_object_get_user_data((struct wth_object *)registry);
+
+ if (strcmp(interface, "wthp_compositor") == 0) {
+ client_bind_compositor(reg->client, (struct wthp_compositor *)id);
+ } else if (strcmp(interface, "wthp_blob_factory") == 0) {
+ struct client *client = reg->client;
+ struct seat *seat, *tmp, *get_seat;
+
+ client_bind_blob_factory(reg->client, (struct wthp_blob_factory *)id);
+
+ get_seat = NULL;
+ wl_list_for_each_safe(seat, tmp, &client->seat_list, link) {
+ get_seat = seat;
+ }
+
+ if (get_seat)
+ seat_send_updated_caps(get_seat);
+ } else if (strcmp(interface, "wthp_ivi_app_id") == 0) {
+ client_bind_wthp_ivi_app_id(reg->client, (struct wthp_ivi_app_id *) id);
+ } else if (strcmp(interface, "wthp_seat") == 0) {
+ client_bind_seat(reg->client, (struct wthp_seat *)id);
+ } else {
+ wth_object_post_error((struct wth_object *)registry, 0,
+ "%s: unknown name %u", __func__, name);
+ wth_object_delete(id);
+ }
+}
+
+static const struct wthp_registry_interface registry_implementation = {
+ registry_handle_destroy,
+ registry_handle_bind
+};
+
+/*
+ * waltham display implementation
+ */
+
+static void
+display_handle_client_version(struct wth_display *wth_display,
+ uint32_t client_version)
+{
+ wth_object_post_error((struct wth_object *)wth_display, 0,
+ "unimplemented: %s", __func__);
+}
+
+static void
+display_handle_sync(struct wth_display * wth_display, struct wthp_callback * callback)
+{
+ wthp_callback_send_done(callback, 0);
+ wthp_callback_free(callback);
+}
+
+static void
+display_handle_get_registry(struct wth_display *wth_display,
+ struct wthp_registry *registry)
+{
+ struct client *c = wth_object_get_user_data((struct wth_object *)wth_display);
+ struct registry *reg;
+
+ reg = zalloc(sizeof *reg);
+ if (!reg) {
+ client_post_out_of_memory(c);
+ return;
+ }
+
+ reg->obj = registry;
+ reg->client = c;
+ wl_list_insert(&c->registry_list, &reg->link);
+ wthp_registry_set_interface(registry,
+ &registry_implementation, reg);
+
+ wthp_registry_send_global(registry, 1, "wthp_compositor", 4);
+ wthp_registry_send_global(registry, 1, "wthp_ivi_app_id", 1);
+ wthp_registry_send_global(registry, 1, "wthp_seat", 4);
+ wthp_registry_send_global(registry, 1, "wthp_blob_factory", 4);
+
+}
+
+const struct wth_display_interface display_implementation = {
+ display_handle_client_version,
+ display_handle_sync,
+ display_handle_get_registry
+};
+
+/*
+ * utility functions
+ */
+static int
+watch_ctl(struct watch *w, int op, uint32_t events)
+{
+ struct epoll_event ee;
+
+ ee.events = events;
+ ee.data.ptr = w;
+ return epoll_ctl(w->receiver->epoll_fd, op, w->fd, &ee);
+}
+
+/**
+* client_destroy
+*
+* Destroy client connection
+*
+* @param names struct client *c
+* @param value client data
+* @return none
+*/
+void
+client_destroy(struct client *c)
+{
+ struct region *region;
+ struct compositor *comp;
+ struct registry *reg;
+ struct surface *surface;
+
+ /* clean up remaining client resources in case the client
+ * did not.
+ */
+ wl_list_last_until_empty(region, &c->region_list, link)
+ region_destroy(region);
+
+ wl_list_last_until_empty(comp, &c->compositor_list, link)
+ compositor_destroy(comp);
+
+ wl_list_last_until_empty(reg, &c->registry_list, link)
+ registry_destroy(reg);
+
+ wl_list_last_until_empty(surface, &c->surface_list, link)
+ surface_destroy(surface);
+
+ wl_list_remove(&c->link);
+ watch_ctl(&c->conn_watch, EPOLL_CTL_DEL, 0);
+ wth_connection_destroy(c->connection);
+ free(c);
+}
+
+/*
+ * functions to handle waltham client connections
+ */
+static void
+connection_handle_data(struct watch *w, uint32_t events)
+{
+
+ struct client *c = container_of(w, struct client, conn_watch);
+ int ret;
+
+ if (events & EPOLLERR) {
+ wth_error("Client %p errored out.\n", c);
+ client_destroy(c);
+ return;
+ }
+
+ if (events & EPOLLHUP) {
+ wth_error("Client %p hung up.\n", c);
+ client_destroy(c);
+ return;
+ }
+
+ if (events & EPOLLOUT) {
+ ret = wth_connection_flush(c->connection);
+ if (ret == 0) {
+ watch_ctl(&c->conn_watch, EPOLL_CTL_MOD, EPOLLIN);
+ } else if (ret < 0 && errno != EAGAIN) {
+ wth_error("Client %p flush error.\n", c);
+ client_destroy(c);
+ return;
+ }
+ }
+
+ if (events & EPOLLIN) {
+ ret = wth_connection_read(c->connection);
+ if (ret < 0) {
+ wth_error("Client %p read error.\n", c);
+ client_destroy(c);
+ return;
+ }
+
+ ret = wth_connection_dispatch(c->connection);
+ if (ret < 0 && errno != EPROTO) {
+ wth_error("Client %p dispatch error.\n", c);
+ client_destroy(c);
+ return;
+ }
+ }
+}
+
+/**
+ * client_create
+ *
+ * Create new client connection
+ *
+ * @param srv receiver structure
+ * @param wth_connection Waltham connection handle
+ * @return Pointer to client structure
+ */
+static struct client *
+client_create(struct receiver *srv, struct wth_connection *conn)
+{
+
+ struct client *c;
+ struct wth_display *disp;
+
+ c = zalloc(sizeof *c);
+ if (!c)
+ return NULL;
+
+ c->receiver = srv;
+ c->connection = conn;
+
+ c->conn_watch.receiver = srv;
+ c->conn_watch.fd = wth_connection_get_fd(conn);
+ c->conn_watch.cb = connection_handle_data;
+ if (watch_ctl(&c->conn_watch, EPOLL_CTL_ADD, EPOLLIN) < 0) {
+ free(c);
+ return NULL;
+ }
+
+
+ wl_list_insert(&srv->client_list, &c->link);
+
+ wl_list_init(&c->registry_list);
+ wl_list_init(&c->compositor_list);
+ wl_list_init(&c->seat_list);
+ wl_list_init(&c->pointer_list);
+ wl_list_init(&c->touch_list);
+ wl_list_init(&c->region_list);
+ wl_list_init(&c->surface_list);
+ wl_list_init(&c->buffer_list);
+
+ disp = wth_connection_get_display(c->connection);
+ wth_display_set_interface(disp, &display_implementation, c);
+
+ return c;
+}
+
+
+/**
+* receiver_flush_clients
+*
+* write all the pending requests from the clients to socket
+*
+* @param names struct receiver *srv
+* @param value socket connection info and client data
+* @return none
+*/
+void
+receiver_flush_clients(struct receiver *srv)
+{
+ struct client *c, *tmp;
+ int ret;
+
+ wl_list_for_each_safe(c, tmp, &srv->client_list, link) {
+ /* Flush out buffered requests. If the Waltham socket is
+ * full, poll it for writable too.
+ */
+ ret = wth_connection_flush(c->connection);
+ if (ret < 0 && errno == EAGAIN) {
+ watch_ctl(&c->conn_watch, EPOLL_CTL_MOD, EPOLLIN | EPOLLOUT);
+ } else if (ret < 0) {
+ perror("Connection flush failed");
+ client_destroy(c);
+ return;
+ }
+ }
+}
+
+/**
+* receiver_accept_client
+*
+* Accepts new waltham client connection and instantiates client structure
+*
+* @param names struct receiver *srv
+* @param value socket connection info and client data
+* @return none
+*/
+void
+receiver_accept_client(struct receiver *srv)
+{
+ struct client *client;
+ struct wth_connection *conn;
+ struct sockaddr_in addr;
+ socklen_t len;
+
+ len = sizeof(addr);
+ conn = wth_accept(srv->listen_fd, (struct sockaddr *)&addr, &len);
+ if (!conn) {
+ wth_error("Failed to accept a connection.\n");
+ return;
+ }
+
+ client = client_create(srv, conn);
+ if (!client) {
+ wth_error("Failed client_create().\n");
+ return;
+ }
+}