IPC: Support older glib
[platform/core/security/vasum.git] / common / ipc / ipc-gsource.cpp
1 /*
2 *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 *  Contact: Jan Olszak <j.olszak@samsung.com>
5 *
6 *  Licensed under the Apache License, Version 2.0 (the "License");
7 *  you may not use this file except in compliance with the License.
8 *  You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 *  Unless required by applicable law or agreed to in writing, software
13 *  distributed under the License is distributed on an "AS IS" BASIS,
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 *  See the License for the specific language governing permissions and
16 *  limitations under the License
17 */
18
19 /**
20  * @file
21  * @author  Jan Olszak (j.olszak@samsung.com)
22  * @brief   Class for creating a dedicated GSource
23  */
24
25
26 #include "config.hpp"
27
28 #include "ipc/ipc-gsource.hpp"
29 #include "utils/callback-wrapper.hpp"
30 #include "logger/logger.hpp"
31
32 #include <algorithm>
33
34 namespace vasum {
35 namespace ipc {
36
37 namespace {
38
39 gushort conditions = static_cast<gushort>(G_IO_IN |
40                                           G_IO_ERR |
41                                           G_IO_HUP);
42
43 }
44
45 IPCGSource::IPCGSource(const HandlerCallback& handlerCallback)
46     : mHandlerCallback(handlerCallback)
47 {
48     LOGT("IPCGSource Constructor");
49 }
50
51 IPCGSource::~IPCGSource()
52 {
53     LOGT("IPCGSource Destructor");
54 }
55
56 IPCGSource::Pointer IPCGSource::create(const HandlerCallback& handlerCallback)
57 {
58     LOGT("Creating IPCGSource");
59
60     static GSourceFuncs funcs = { &IPCGSource::prepare,
61                                   &IPCGSource::check,
62                                   &IPCGSource::dispatch,
63                                   &IPCGSource::finalize,
64                                   nullptr,
65                                   nullptr
66                                 };
67
68     // New GSource
69     GSource* gSource = g_source_new(&funcs, sizeof(IPCGSource));
70     g_source_set_priority(gSource, G_PRIORITY_HIGH);
71
72     // Fill additional data
73     IPCGSource* source = reinterpret_cast<IPCGSource*>(gSource);
74     new(source) IPCGSource(handlerCallback);
75
76     auto deleter = [](IPCGSource * ptr) {
77         LOGD("Deleter");
78         g_source_unref(&ptr->mGSource);
79     };
80
81     Pointer ipcGSourcePtr(source, deleter);
82
83     g_source_set_callback(gSource,
84                           &IPCGSource::onHandlerCall,
85                           utils::createCallbackWrapper(Pointer(ipcGSourcePtr), ipcGSourcePtr->mGuard.spawn()),
86                           &utils::deleteCallbackWrapper<Pointer>);
87
88     return ipcGSourcePtr;
89 }
90
91 void IPCGSource::addFD(const FileDescriptor fd)
92 {
93     LOGI("Adding to glib FD: " << fd);
94     Lock lock(mStateMutex);
95
96     mGPollFDs.push_back({fd, conditions, 0});
97     g_source_add_poll(&mGSource, &mGPollFDs.back());
98 }
99
100 void IPCGSource::removeFD(const FileDescriptor fd)
101 {
102     Lock lock(mStateMutex);
103
104     auto it = std::find_if(mGPollFDs.begin(), mGPollFDs.end(), [fd](GPollFD gPollFD) {
105         return gPollFD.fd = fd;
106     });
107
108     if (it == mGPollFDs.end()) {
109         LOGE("No such fd");
110         return;
111     }
112     g_source_remove_poll(&mGSource, &(*it));
113     mGPollFDs.erase(it);
114     LOGI("Removed from glib FD: " << fd);
115 }
116
117 guint IPCGSource::attach(GMainContext* context)
118 {
119     LOGT("Attaching to GMainContext");
120     guint ret = g_source_attach(&mGSource, context);
121     return ret;
122 }
123
124 void IPCGSource::detach()
125 {
126     LOGT("Detaching");
127     Lock lock(mStateMutex);
128
129     for (GPollFD gPollFD : mGPollFDs) {
130         g_source_remove_poll(&mGSource, &gPollFD);
131     }
132
133     mGPollFDs.clear();
134     if (!g_source_is_destroyed(&mGSource)) {
135         LOGD("Destroying");
136         // This way finalize method will be run in glib loop's thread
137         g_source_destroy(&mGSource);
138     }
139 }
140
141 void IPCGSource::callHandler()
142 {
143     Lock lock(mStateMutex);
144
145     for (const GPollFD& gPollFD : mGPollFDs) {
146         if (gPollFD.revents & conditions) {
147             mHandlerCallback(gPollFD.fd, gPollFD.revents);
148         }
149     }
150 }
151
152 gboolean IPCGSource::onHandlerCall(gpointer userData)
153 {
154     const auto& source = utils::getCallbackFromPointer<Pointer>(userData);
155     if (source) {
156         source->callHandler();
157     }
158     return TRUE;
159 }
160
161 gboolean IPCGSource::prepare(GSource* gSource, gint* timeout)
162 {
163     if (!gSource || g_source_is_destroyed(gSource)) {
164         return FALSE;
165     }
166
167     *timeout = -1;
168
169     // TODO: Implement hasEvents() method in Client and Service and use it here as a callback:
170     // return source->hasEvents();
171     return FALSE;
172 }
173
174 gboolean IPCGSource::check(GSource* gSource)
175 {
176     if (!gSource || g_source_is_destroyed(gSource)) {
177         return FALSE;
178     }
179
180     return TRUE;
181 }
182
183 gboolean IPCGSource::dispatch(GSource* gSource,
184                               GSourceFunc callback,
185                               gpointer userData)
186 {
187     if (!gSource || g_source_is_destroyed(gSource)) {
188         // Remove the GSource from the GMainContext
189         return FALSE;
190     }
191
192     if (callback) {
193         callback(userData);
194     }
195
196     return TRUE;
197 }
198
199 void  IPCGSource::finalize(GSource* gSource)
200 {
201     if (gSource) {
202         IPCGSource* source = reinterpret_cast<IPCGSource*>(gSource);
203         source->~IPCGSource();
204     }
205 }
206
207 } // namespace ipc
208 } // namespace vasum