add source for ces2019
[apps/agl-service-windowmanager-2017.git] / src / wm_connection.cpp
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "wm_connection.hpp"
18 #include <string.h>
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include "json_helper.hpp"
25 #include "util.hpp"
26
27 extern "C"
28 {
29 #include <afb/afb-binding.h>
30 #include <systemd/sd-event.h>
31 }
32
33
34 /**
35  * namespace wm
36  */
37 namespace wm
38 {
39
40
41 namespace
42 {
43
44 static const char kPathConnectionConfigFile[] = "/etc/connection.json";
45 static const char kDefaultIpAddr[] = "192.168.10.10";
46 static const int  kDefaultPort     = 4000;
47
48 static int onIoEventReceive(sd_event_source *src, int fd, uint32_t revents, void * data)
49 {
50     WMConnection *p_wmcon = (WMConnection*)data;
51
52     json_object *j_out;
53     int ret = p_wmcon->receive(&j_out);
54     if (0 > ret)
55     {
56         return 0;
57     }
58
59     const char* rq = jh::getStringFromJson(j_out, "req");
60     const char* id = jh::getStringFromJson(j_out, "appid");
61     const char* dn = jh::getStringFromJson(j_out, "drawing_name");
62     const char* da = jh::getStringFromJson(j_out, "drawing_area");
63
64     HMI_DEBUG("req:%s appid:%s, drawing_name:%s, drawing_area:%s", rq, id, dn, da);
65
66     // Callback
67     p_wmcon->callOnReceivedHandler(j_out);
68
69     return 0;
70 }
71
72 static int onIoEventAccept(sd_event_source *src, int fd, uint32_t revents, void * data)
73 {
74     struct sockaddr_in addr;
75
76     WMConnection *p_wmcon = (WMConnection*)data;
77
78     // Accept connection
79     socklen_t len = sizeof(addr);
80     int my_socket = p_wmcon->getMySocket();
81     int connected_socket = accept(my_socket, (struct sockaddr *)&addr, &len);
82     if (0 > connected_socket)
83     {
84         HMI_ERROR("Failed to accept connection (%s)", strerror(errno));
85         return -1;
86     }
87
88     // Store connected socket
89     p_wmcon->setConnectedSocket(connected_socket);
90
91     // Register callback to receive
92     int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
93                           connected_socket, EPOLLIN,
94                           onIoEventReceive, p_wmcon);
95     if (0 > ret)
96     {
97         HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
98         return -1;
99     }
100
101     return 0;
102 }
103
104 } // namespace
105
106 WMConnection::WMConnection()
107 {
108     // Load connection config file
109     this->loadConnectionConfigFile();
110
111     // TODO: ECU name should be decide by config file
112     this->ecu_name = this->mode;
113 }
114
115 int WMConnection::initialize()
116 {
117     int ret;
118
119     // Initialize for Master/Slave
120     if (this->isMasterMode())
121     {
122         ret = this->initializeMaster();
123     }
124     else
125     {
126         ret = this->initializeSlave();
127     }
128
129     return ret;
130 }
131
132 void WMConnection::registerCallback(ReceivedHandler on_received)
133 {
134     this->onReceived = on_received;
135 }
136
137 int WMConnection::sendRequest(char const *req, char const *appid,
138                               char const *drawing_name, char const *drawing_area)
139 {
140     int ret;
141     json_object *j_obj = json_object_new_object();
142     json_object_object_add(j_obj, "req",          json_object_new_string(req));
143     json_object_object_add(j_obj, "appid",        json_object_new_string(appid));
144     json_object_object_add(j_obj, "drawing_name", json_object_new_string(drawing_name));
145     json_object_object_add(j_obj, "drawing_area", json_object_new_string(drawing_area));
146
147     ret = this->send(j_obj);
148
149     json_object_put(j_obj);
150
151     return ret;
152 }
153
154 int WMConnection::send(struct json_object* j_in)
155 {
156     // Convert json_object to string to send
157     const char *buf = json_object_to_json_string(j_in);
158     if (nullptr == buf)
159     {
160         HMI_ERROR("Failed to convert json_object to string");
161         return -1;
162     }
163
164     int len = strlen(buf);
165
166     HMI_DEBUG("Send data(len:%d): %s", len, buf);
167
168     int n = write(this->connected_socket, buf, len);
169     if(0 > n)
170     {
171         HMI_ERROR("Failed to send data (%s)", strerror(errno));
172         return -1;
173     }
174
175     return 0;
176 }
177
178 bool WMConnection::isMasterMode()
179 {
180     if ("master" == this->mode)
181     {
182         return true;
183     }
184     else
185     {
186         return false;
187     }
188 }
189
190 bool WMConnection::isMasterArea(const char* area)
191 {
192     if (nullptr == area)
193     {
194         return false;
195     }
196
197     std::string str_area = std::string(area);
198     if ("" == str_area)
199     {
200         return false;
201     }
202
203     std::vector<std::string> elements;
204     elements = parseString(str_area, '.');
205
206     if ("master" == elements[0])
207     {
208         return true;
209     }
210     else
211     {
212         return false;
213     }
214 }
215
216 bool WMConnection::isConnecting()
217 {
218     return (0 > this->connected_socket) ? false : true;
219 }
220
221 std::string WMConnection::parseMasterArea(const char* area)
222 {
223     std::string ret_area = "";
224     std::vector<std::string> elements;
225     elements = parseString(std::string(area), '.');
226
227     if ("master" != elements[0])
228     {
229         return std::string(area);
230     }
231
232     for (auto itr = (elements.begin() + 1); itr != elements.end(); ++itr)
233     {
234         ret_area += *itr;
235
236         if ((elements.end() - 1) != itr)
237         {
238             ret_area += ".";
239         }
240     }
241     return ret_area;
242 }
243
244 bool WMConnection::isSyncDrawingForRemote(const char* appid)
245 {
246     if (std::string(appid) == this->syndDrawingAppId)
247     {
248         return true;
249     }
250     else
251     {
252         return false;
253     }
254 }
255
256 void WMConnection::startSyncDrawForRemote(const char* appid)
257 {
258     this->syndDrawingAppId = std::string(appid);
259 }
260
261 void WMConnection::finishSyncDrawForRemote(const char* appid)
262 {
263     if (std::string(appid) == this->syndDrawingAppId)
264     {
265         this->syndDrawingAppId = "";
266     }
267 }
268
269 int WMConnection::getMySocket()
270 {
271     return this->my_socket;
272 }
273
274 int WMConnection::getConnectedSocket()
275 {
276     return this->connected_socket;
277 }
278
279 void WMConnection::setConnectedSocket(int connected_socket)
280 {
281     this->connected_socket = connected_socket;
282 }
283
284 std::string WMConnection::getEcuName()
285 {
286     return this->ecu_name;
287 }
288
289 void WMConnection::callOnReceivedHandler(json_object *j_out)
290 {
291     this->onReceived(j_out);
292 }
293
294 int WMConnection::initializeMaster()
295 {
296     int ret = 0;
297     struct sockaddr_in addr;
298
299     // Create socket
300     this->my_socket = socket(AF_INET, SOCK_STREAM, 0);
301     if (0 > this->my_socket)
302     {
303         HMI_ERROR("Failed to create socket (%s)", strerror(errno));
304         return -1;
305     }
306
307     // Bind socket
308     addr.sin_family = AF_INET;
309     addr.sin_port = htons(this->port);
310     addr.sin_addr.s_addr = htonl(INADDR_ANY);
311
312     ret = bind(this->my_socket, (struct sockaddr *)&addr, sizeof(addr));
313     if (0 > ret)
314     {
315         HMI_ERROR("Failed to bind socket (%s)", strerror(errno));
316         return -1;
317     }
318
319     // Listen connection
320     ret = listen(this->my_socket, 1);
321     if (0 > ret)
322     {
323         HMI_ERROR("Failed to listen connection (%s)", strerror(errno));
324         return -1;
325     }
326
327     // Register callback to accept connection
328     ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
329                           this->my_socket, EPOLLIN,
330                           onIoEventAccept, this);
331     if (0 > ret)
332     {
333         HMI_ERROR("Failed to add I/O event accept(%s)", strerror(-ret));
334         return -1;
335     }
336
337     return ret;
338 }
339
340 int WMConnection::initializeSlave()
341 {
342     // Create socket
343     this->my_socket = socket(AF_INET, SOCK_STREAM, 0);
344     if (0 > this->my_socket)
345     {
346         HMI_ERROR("Failed to create socket (%s)", strerror(errno));
347         return -1;
348     }
349
350     return 0;
351 }
352
353 int WMConnection::connectToMaster()
354 {
355     int ret = 0;
356     struct sockaddr_in addr;
357
358     // Connect to master
359     addr.sin_family = AF_INET;
360     addr.sin_port = htons(this->port);
361     addr.sin_addr.s_addr = inet_addr(this->ip.c_str());
362
363     ret = connect(this->my_socket, (struct sockaddr *)&addr, sizeof(addr));
364     if (0 > ret)
365     {
366         HMI_ERROR("Failed to connect to master (%s)", strerror(errno));
367         return ret;
368     }
369
370     HMI_DEBUG("Connected to master");
371
372     // Store connected socket
373     this->connected_socket = this->my_socket;
374
375     // Register callback to receive
376     ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
377                           this->connected_socket, EPOLLIN,
378                           onIoEventReceive, this);
379     if (0 > ret)
380     {
381         HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
382         return -1;
383     }
384
385     return ret;
386 }
387
388 int WMConnection::receive(struct json_object** j_out)
389 {
390     char buf[1024];
391     int n;
392
393     n = read(this->connected_socket, buf, sizeof(buf));
394     if(0 > n)
395     {
396         HMI_ERROR("Failed to receive data (%s)", strerror(errno));
397         return -1;
398     }
399
400     HMI_DEBUG("Received data length: %d", n);
401     HMI_DEBUG("Received data: %s", buf);
402
403     // Parse received data
404     struct json_tokener *tokener = json_tokener_new();
405     *j_out = json_tokener_parse_ex(tokener, buf, n);
406     if (nullptr == *j_out)
407     {
408         HMI_DEBUG("Failed to parse received data");
409         return -1;
410     }
411
412     return 0;
413 }
414
415 int WMConnection::loadConnectionConfigFile()
416 {
417     // Get afm application installed dir
418     char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
419     if (!afm_app_install_dir)
420     {
421         HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
422     }
423     std::string path = std::string(afm_app_install_dir) + std::string(kPathConnectionConfigFile);
424
425     // Load connection config file
426     json_object* json_obj;
427     int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
428     if (0 > ret)
429     {
430         HMI_ERROR("Could not open %s, so use default mode \"slave\"", kPathConnectionConfigFile);
431         this->mode = "slave";
432         this->ip   = kDefaultIpAddr;
433         this->port = kDefaultPort;
434         return 0;
435     }
436     HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
437
438     const char* mode = jh::getStringFromJson(json_obj, "mode");
439     this->mode = (nullptr != mode) ? mode : "slave";
440
441     const char* ip = jh::getStringFromJson(json_obj, "master_ip");
442     this->ip = (nullptr != ip) ? ip : kDefaultIpAddr;
443
444     int port = jh::getIntFromJson(json_obj, "master_port");
445     this->port = (0 != port) ? port : kDefaultPort;
446
447     // Check
448     HMI_DEBUG("mode:%s master_ip:%s master_port:%d", mode, ip, port);
449
450     // Release json_object
451     json_object_put(json_obj);
452
453     return 0;
454 }
455
456
457 } // namespace wm