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