diff options
Diffstat (limited to 'src/wth-receiver-comm.c')
-rw-r--r-- | src/wth-receiver-comm.c | 453 |
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(®->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, ®->link); + wthp_registry_set_interface(registry, + ®istry_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; + } +} |