Merge "sensord: delete batch latency/attribute when client is terminated unexpectedly...
[platform/core/system/sensord.git] / src / server / external_sensor_worker.cpp
1 /*
2  * sensord
3  *
4  * Copyright (c) 2015 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 <sensor_common.h>
21 #include <command_common.h>
22 #include <external_sensor_worker.h>
23 #include <external_client_manager.h>
24 #include <external_sensor.h>
25 #include <external_sensor_service.h>
26
27 using std::string;
28
29 external_sensor_worker::cmd_handler_t external_sensor_worker::m_cmd_handlers[];
30
31 external_sensor_worker::external_sensor_worker(const csocket& socket)
32 : m_client_id(CLIENT_ID_INVALID)
33 , m_socket(socket)
34 , m_sensor(NULL)
35 , m_sensor_id(UNKNOWN_SENSOR)
36 {
37         static bool init = false;
38
39         if (!init) {
40                 init_cmd_handlers();
41                 init = true;
42         }
43
44         m_worker.set_context(this);
45         m_worker.set_working(working);
46         m_worker.set_stopped(stopped);
47 }
48
49 external_sensor_worker::~external_sensor_worker()
50 {
51         m_socket.close();
52 }
53
54 bool external_sensor_worker::start(void)
55 {
56         return m_worker.start();
57 }
58
59 void external_sensor_worker::init_cmd_handlers(void)
60 {
61         m_cmd_handlers[CMD_EXT_GET_ID]          = &external_sensor_worker::cmd_get_id;
62         m_cmd_handlers[CMD_EXT_CONNECT]         = &external_sensor_worker::cmd_connect;
63         m_cmd_handlers[CMD_EXT_DISCONNECT]      = &external_sensor_worker::cmd_disconnect;
64         m_cmd_handlers[CMD_EXT_POST]            = &external_sensor_worker::cmd_post;
65 }
66
67 bool external_sensor_worker::working(void *ctx)
68 {
69         bool ret;
70         external_sensor_worker *inst = (external_sensor_worker *)ctx;
71
72         packet_header header;
73         char *payload;
74
75         if (inst->m_socket.recv(&header, sizeof(header)) <= 0) {
76                 string info;
77                 inst->get_info(info);
78                 _D("%s failed to receive header", info.c_str());
79                 return false;
80         }
81
82         retvm_if(header.size == 0, false, "Invalid header size");
83
84         payload = new(std::nothrow) char[header.size];
85         retvm_if(!payload, false, "Failed to allocate memory");
86
87         if (inst->m_socket.recv(payload, header.size) <= 0) {
88                 string info;
89                 inst->get_info(info);
90                 _D("%s failed to receive data of packet", info.c_str());
91                 delete[] payload;
92                 return false;
93         }
94
95         ret = inst->dispatch_command(header.cmd, payload);
96
97         delete[] payload;
98
99         return ret;
100 }
101
102 bool external_sensor_worker::stopped(void *ctx)
103 {
104         string info;
105         external_sensor_worker *inst = (external_sensor_worker *)ctx;
106
107         inst->get_info(info);
108         _I("%s is stopped", info.c_str());
109
110         if (inst->m_client_id != CLIENT_ID_INVALID) {
111                 _I("Client:%d leaves without disconnecting", inst->m_client_id);
112                 if (get_client_manager().has_sensor_record(inst->m_client_id, inst->m_sensor_id)) {
113                         _I("Removing sensor[%#x] record for client_id[%d]", inst->m_sensor_id, inst->m_client_id);
114                         get_client_manager().remove_sensor_record(inst->m_client_id, inst->m_sensor_id);
115
116                         if (inst->m_sensor)
117                                 inst->m_sensor->set_source_connected(false);
118                 }
119         }
120
121         delete inst;
122         return true;
123 }
124
125 bool external_sensor_worker::dispatch_command(int cmd, void* payload)
126 {
127         int ret = false;
128
129         if (!(cmd > 0 && cmd < CMD_EXT_CNT)) {
130                 _E("Unknown command: %d", cmd);
131         } else {
132                 cmd_handler_t cmd_handler;
133                 cmd_handler = external_sensor_worker::m_cmd_handlers[cmd];
134                 if (cmd_handler)
135                         ret = (this->*cmd_handler)(payload);
136         }
137
138         return ret;
139 }
140
141 bool external_sensor_worker::send_cmd_done(long value)
142 {
143         cpacket* ret_packet;
144         cmd_ext_done_t *cmd_ext_done;
145
146         ret_packet = new(std::nothrow) cpacket(sizeof(cmd_ext_done_t));
147         retvm_if(!ret_packet, false, "Failed to allocate memory");
148
149         ret_packet->set_cmd(CMD_EXT_DONE);
150
151         cmd_ext_done = (cmd_ext_done_t*)ret_packet->data();
152         cmd_ext_done->value = value;
153
154         if (m_socket.send(ret_packet->packet(), ret_packet->size()) <= 0) {
155                 _E("Failed to send a cmd_done to client_id [%d] with value [%ld]", m_client_id, value);
156                 delete ret_packet;
157                 return false;
158         }
159
160         delete ret_packet;
161         return true;
162 }
163
164 bool external_sensor_worker::send_cmd_get_id_done(int client_id)
165 {
166         cpacket* ret_packet;
167         cmd_ext_get_id_done_t *cmd_ext_get_id_done;
168
169         ret_packet = new(std::nothrow) cpacket(sizeof(cmd_ext_get_id_done_t));
170         retvm_if(!ret_packet, false, "Failed to allocate memory");
171
172         ret_packet->set_cmd(CMD_EXT_GET_ID);
173
174         cmd_ext_get_id_done = (cmd_ext_get_id_done_t*)ret_packet->data();
175         cmd_ext_get_id_done->client_id = client_id;
176
177         if (m_socket.send(ret_packet->packet(), ret_packet->size()) <= 0) {
178                 _E("Failed to send a cmd_get_id_done with client_id [%d]", client_id);
179                 delete ret_packet;
180                 return false;
181         }
182
183         delete ret_packet;
184         return true;
185 }
186
187 bool external_sensor_worker::send_cmd_connect_done(sensor_id_t sensor_id)
188 {
189         cpacket* ret_packet;
190         cmd_ext_connect_done_t *cmd_ext_connect_done;
191
192         ret_packet = new(std::nothrow) cpacket(sizeof(cmd_ext_connect_done_t));
193         retvm_if(!ret_packet, false, "Failed to allocate memory");
194
195         ret_packet->set_cmd(CMD_EXT_CONNECT);
196
197         cmd_ext_connect_done = (cmd_ext_connect_done_t*)ret_packet->data();
198         cmd_ext_connect_done->sensor_id = sensor_id;
199
200         if (m_socket.send(ret_packet->packet(), ret_packet->size()) <= 0) {
201                 _E("Failed to send a cmd_connect done");
202                 delete ret_packet;
203                 return false;
204         }
205
206         delete ret_packet;
207         return true;
208 }
209
210 bool external_sensor_worker::cmd_get_id(void *payload)
211 {
212         cmd_ext_get_id_t *cmd = static_cast<cmd_ext_get_id_t *>(payload);
213         int client_id;
214         struct ucred cr;
215         socklen_t opt_len = sizeof(cr);
216
217         if (getsockopt(m_socket.get_socket_fd(), SOL_SOCKET, SO_PEERCRED, &cr, &opt_len)) {
218                 _E("Failed to get socket option with SO_PEERCRED");
219                 return false;
220         }
221
222         client_id = get_client_manager().create_client_record();
223
224         if (client_id != MAX_HANDLE_REACHED) {
225                 get_client_manager().set_client_info(client_id, cr.pid, cmd->name);
226                 _I("New client id [%d] created", client_id);
227         }
228
229         if (!send_cmd_get_id_done(client_id))
230                 _E("Failed to send cmd_done to a client");
231
232         return true;
233 }
234
235 bool external_sensor_worker::cmd_connect(void *payload)
236 {
237         cmd_ext_connect_t *cmd = static_cast<cmd_ext_connect_t *>(payload);
238         m_client_id = cmd->client_id;
239
240         external_sensor *sensor;
241         sensor = external_sensor_service::get_instance().get_sensor(string(cmd->key));
242         if (!sensor) {
243                 _E("No matched external sensor with key: %s", cmd->key);
244                 goto out;
245         }
246
247         if (!sensor->set_source_connected(true)) {
248                 _E("External sensor(%s) is already connected", cmd->key);
249                 goto out;
250         }
251
252         m_sensor = sensor;
253         m_sensor_id = sensor->get_id();
254
255         if (!get_client_manager().create_sensor_record(m_client_id, m_sensor_id)) {
256                 _E("Failed to create sensor record for client: %d, sensor_id: %d", m_client_id, m_sensor_id);
257                 m_sensor_id = UNKNOWN_SENSOR;
258                 goto out;
259         }
260
261 out:
262         if (!send_cmd_connect_done(m_sensor_id))
263                 _E("Failed to send cmd_connect_done to a client : %d", m_client_id);
264
265         return true;
266 }
267
268 bool external_sensor_worker::cmd_disconnect(void *payload)
269 {
270         long ret_value = OP_ERROR;
271
272         if (!m_sensor) {
273                 _E("External sensor is not connected");
274                 ret_value = OP_ERROR;
275                 goto out;
276         }
277
278         if (!get_client_manager().remove_sensor_record(m_client_id, m_sensor_id)) {
279                 _E("Failed to remove sensor record for client [%d]", m_client_id);
280                 ret_value = OP_ERROR;
281                 goto out;
282         }
283
284         m_sensor->set_source_connected(false);
285
286         m_sensor = NULL;
287         m_client_id = CLIENT_ID_INVALID;
288         m_sensor_id = UNKNOWN_SENSOR;
289         ret_value = OP_SUCCESS;
290 out:
291         if (!send_cmd_done(ret_value))
292                 _E("Failed to send cmd_done to a client");
293
294         if (ret_value == OP_SUCCESS)
295                 return false;
296
297         return true;
298 }
299
300 bool external_sensor_worker::cmd_post(void *payload)
301 {
302         long ret_value = OP_SUCCESS;
303         cmd_ext_post_t *cmd = static_cast<cmd_ext_post_t *>(payload);
304
305         m_sensor->on_receive(cmd->timestamp, cmd->data, cmd->data_cnt);
306
307         if (!send_cmd_done(ret_value))
308                 _E("Failed to send cmd_done to a client");
309
310         return true;
311 }
312
313 external_client_manager& external_sensor_worker::get_client_manager(void)
314 {
315         return external_client_manager::get_instance();
316 }
317
318 void external_sensor_worker::get_info(string &info)
319 {
320         const char *client_info = NULL;
321
322         if (m_client_id != CLIENT_ID_INVALID)
323                 client_info = get_client_manager().get_client_info(m_client_id);
324
325         info = string("Command worker for ") + (client_info ? string(client_info) : string("Unknown"));
326 }