1 /*
2 * Copyright (C) 2019 Igalia S.L.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
16 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "ipc.h"
27 #include <cstdio>
28
29 namespace FdoIPC {
30
31 static const size_t messageSize = 2 * sizeof(uint32_t);
32
create(int fd,MessageReceiver * messageReceiver)33 std::unique_ptr<Connection> Connection::create(int fd, MessageReceiver* messageReceiver)
34 {
35 GError* error = nullptr;
36 auto* socket = g_socket_new_from_fd(fd, &error);
37 if (!socket) {
38 g_warning("Failed to create socket for fd %d: %s", fd, error->message);
39 g_error_free(error);
40
41 return nullptr;
42 }
43
44 return std::unique_ptr<Connection>(new Connection(socket, messageReceiver));
45 }
46
Connection(GSocket * socket,MessageReceiver * messageReceiver)47 Connection::Connection(GSocket* socket, MessageReceiver* messageReceiver)
48 : m_socket(socket)
49 , m_messageReceiver(messageReceiver)
50 {
51 g_socket_set_blocking(m_socket, FALSE);
52
53 if (m_messageReceiver) {
54 m_socketSource = g_socket_create_source(m_socket, G_IO_IN, nullptr);
55 g_source_set_name(m_socketSource, "WPEBackend-fdo::socket");
56 g_source_set_callback(m_socketSource, reinterpret_cast<GSourceFunc>(s_socketCallback), this, nullptr);
57 g_source_attach(m_socketSource, g_main_context_get_thread_default());
58 }
59 }
60
~Connection()61 Connection::~Connection()
62 {
63 if (m_socketSource) {
64 g_source_destroy(m_socketSource);
65 g_source_unref(m_socketSource);
66 }
67 g_clear_object(&m_socket);
68 }
69
send(uint32_t messageId,uint32_t messageBody)70 void Connection::send(uint32_t messageId, uint32_t messageBody)
71 {
72 GError* error = nullptr;
73 uint32_t message[2] = { messageId, messageBody };
74 gssize len = g_socket_send(m_socket, reinterpret_cast<gchar*>(message), messageSize, nullptr, &error);
75 if (len == -1) {
76 if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
77 g_warning("Failed to send message %u to socket: %s", messageId, error->message);
78 g_error_free(error);
79 }
80 }
81
s_socketCallback(GSocket * socket,GIOCondition condition,gpointer data)82 gboolean Connection::s_socketCallback(GSocket* socket, GIOCondition condition, gpointer data)
83 {
84 if (!(condition & G_IO_IN))
85 return TRUE;
86
87 GError* error = nullptr;
88 uint32_t message[2];
89 gssize len = g_socket_receive(socket, reinterpret_cast<gchar*>(message), messageSize, nullptr, &error);
90 if (len == -1) {
91 if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
92 g_warning("Failed to read message from socket: %s", error->message);
93 g_error_free(error);
94 return FALSE;
95 }
96
97 if (len != messageSize)
98 return TRUE;
99
100 static_cast<Connection*>(data)->m_messageReceiver->didReceiveMessage(message[0], message[1]);
101 return TRUE;
102 }
103
104 } // namespace FdoIPC
105