Merge branch 'devel/tizen' into tizen
[platform/core/system/sensord.git] / src / shared / channel.cpp
1 /*
2  * sensord
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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 #include "channel.h"
21
22 #include <stdint.h>
23 #include <unistd.h>
24 #include <memory>
25
26 #include "sensor_log.h"
27 #include "channel_event_handler.h"
28
29 #define SYSTEMD_SOCK_BUF_SIZE 40000
30
31 using namespace ipc;
32
33 class send_event_handler : public event_handler
34 {
35 public:
36         send_event_handler(channel *ch, message *msg)
37         : m_ch(ch)
38         , m_msg(msg)
39         { }
40
41         bool handle(int fd, event_condition condition)
42         {
43                 if (!m_ch || !m_ch->is_connected())
44                         return false;
45
46                 if (condition & (EVENT_IN | EVENT_HUP))
47                         return false;
48
49                 if (!m_ch->send_sync(m_msg))
50                         return false;
51
52                 if (m_msg)
53                         m_msg->unref();
54
55                 return false;
56         }
57
58 private:
59         channel *m_ch;
60         message *m_msg;
61 };
62
63 class read_event_handler : public event_handler
64 {
65 public:
66         read_event_handler(channel *ch)
67         : m_ch(ch)
68         { }
69
70         bool handle(int fd, event_condition condition)
71         {
72                 message msg;
73
74                 if (!m_ch || !m_ch->is_connected())
75                         return false;
76
77                 if (condition & (EVENT_OUT | EVENT_HUP))
78                         return false;
79
80                 if (!m_ch->read_sync(msg, false))
81                         return false;
82
83                 return false;
84         }
85
86 private:
87         channel *m_ch;
88 };
89
90 channel::channel(socket *sock)
91 : m_fd(sock->get_fd())
92 , m_event_id(0)
93 , m_socket(sock)
94 , m_handler(NULL)
95 , m_loop(NULL)
96 , m_connected(false)
97 {
98 }
99
100 channel::~channel()
101 {
102         /* disconnect() should not be called here */
103 }
104
105 void channel::bind(channel_handler *handler, event_loop *loop)
106 {
107         m_handler = handler;
108         m_loop = loop;
109         m_connected.store(true);
110
111         if (m_handler)
112                 m_handler->connected(this);
113 }
114
115 void channel::bind(void)
116 {
117         ret_if(!m_loop);
118         m_event_id = m_loop->add_event(m_socket->get_fd(),
119                         (EVENT_IN | EVENT_HUP | EVENT_NVAL),
120                         dynamic_cast<channel_event_handler *>(m_handler));
121 }
122
123 bool channel::connect(channel_handler *handler, event_loop *loop)
124 {
125         if (!m_socket->connect())
126                 return false;
127
128         bind(handler, loop);
129         return true;
130 }
131
132 void channel::disconnect(void)
133 {
134         ret_if(!is_connected());
135         m_connected.store(false);
136
137         if (m_handler) {
138                 m_handler->disconnected(this);
139                 m_handler = NULL;
140         }
141
142         if (m_loop) {
143                 m_loop->remove_event(m_event_id, true);
144                 m_loop = NULL;
145                 m_event_id = 0;
146         }
147
148         if (m_socket) {
149                 delete m_socket;
150                 m_socket = NULL;
151         }
152 }
153
154 bool channel::send(message *msg)
155 {
156         retv_if(!m_loop, false);
157
158         /* TODO: check buffer size(is there any linux api for this?) */
159         int cur_buffer_size = m_socket->get_current_buffer_size();
160         retvm_if(cur_buffer_size > SYSTEMD_SOCK_BUF_SIZE, false, "Failed to send data");
161
162         send_event_handler *handler = new(std::nothrow) send_event_handler(this, msg);
163         retvm_if(!handler, false, "Failed to allocate memory");
164
165         msg->ref();
166
167         m_loop->add_event(m_socket->get_fd(),
168                         (EVENT_OUT | EVENT_HUP | EVENT_NVAL) , handler);
169
170         return true;
171 }
172
173 bool channel::send_sync(message *msg)
174 {
175         retv_if(!msg, false);
176
177         ssize_t size = 0;
178         char *buf = msg->body();
179
180         /* header */
181         size = m_socket->send(reinterpret_cast<void *>(msg->header()),
182                                    sizeof(message_header), true);
183         retv_if(size <= 0, false);
184         retv_if(msg->size() <= 0, true);
185
186         /* body */
187         size = m_socket->send(buf, msg->size(), true);
188         retv_if(size <= 0, false);
189
190         return true;
191 }
192
193 bool channel::read(void)
194 {
195         retv_if(!m_loop, false);
196
197         read_event_handler *handler = new(std::nothrow) read_event_handler(this);
198         retvm_if(!handler, false, "Failed to allocate memory");
199
200         m_loop->add_event(m_socket->get_fd(), (EVENT_IN | EVENT_HUP | EVENT_NVAL), handler);
201
202         return true;
203 }
204
205 bool channel::read_sync(message &msg, bool select)
206 {
207         message_header header;
208         ssize_t size = 0;
209         char buf[MAX_MSG_CAPACITY];
210
211         /* header */
212         size = m_socket->recv(&header, sizeof(message_header), select);
213         retv_if(size <= 0, false);
214
215         /* check error from header */
216         if (m_handler && header.err != 0) {
217                 m_handler->error_caught(this, header.err);
218                 msg.header()->err = header.err;
219                 return true;
220         }
221
222         /* body */
223         if (header.length > 0) {
224                 size = m_socket->recv(&buf, header.length, select);
225                 retv_if(size <= 0, false);
226         }
227
228         buf[header.length] = '\0';
229         msg.enclose(reinterpret_cast<const void *>(buf), header.length);
230         msg.set_type(header.type);
231         msg.header()->err = header.err;
232
233         if (m_handler)
234                 m_handler->read(this, msg);
235
236         return true;
237 }
238
239 bool channel::is_connected(void)
240 {
241         return m_connected.load();
242 }
243
244 bool channel::set_option(int type, int value)
245 {
246         switch (type) {
247         case SO_SNDBUF:
248                 m_socket->set_buffer_size(type, value);
249                 break;
250         case SO_RCVBUF:
251                 m_socket->set_buffer_size(type, value);
252                 break;
253         default:
254                 break;
255         }
256
257         return true;
258 }
259
260 bool channel::get_option(int type, int &value) const
261 {
262         switch (type) {
263         case 0:
264                 value = m_socket->get_current_buffer_size();
265                 break;
266         case SO_SNDBUF:
267                 value = m_socket->get_buffer_size(type);
268                 break;
269         case SO_RCVBUF:
270                 value = m_socket->get_buffer_size(type);
271                 break;
272         default:
273                 break;
274         }
275
276         return true;
277 }
278
279 int channel::get_fd(void) const
280 {
281         return m_fd;
282 }
283
284 void channel::set_event_id(uint64_t id)
285 {
286         m_event_id = id;
287 }