2 * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "wm_connection.hpp"
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"
29 #include <afb/afb-binding.h>
30 #include <systemd/sd-event.h>
44 static const char kPathConnectionConfigFile[] = "/etc/hmi-config/connection.json";
45 static const char kPathTimeoutConfigFile[] = "/etc/timeout.json";
46 static const char kDefaultIpAddr[] = "192.168.10.10";
47 static const int kDefaultPort = 4000;
48 static const uint64_t kDefaultTimes = 60000;
49 static const uint64_t kDefaultSleep = 50;
50 static struct sd_event_source *g_limit_timer_src = nullptr;
51 static struct sd_event_source *g_sleep_timer_src = nullptr;
53 static int setTimer(sd_event_source **src, uint64_t usec, void* handler, void* data)
55 int ret = sd_event_add_time(afb_daemon_get_event_loop(), src,
56 CLOCK_BOOTTIME, usec, 1, (sd_event_time_handler_t)handler, data);
60 HMI_ERROR("Colud't set timer");
66 static void updateTimer(sd_event_source *src, uint64_t usec)
68 sd_event_source_set_time(src, usec);
69 sd_event_source_set_enabled(src, SD_EVENT_ONESHOT);
72 static void stopEvent(sd_event_source *src)
74 int ret = sd_event_source_set_enabled(src, SD_EVENT_OFF);
77 HMI_ERROR("Not set SD_EVENT_OFF (%s)", strerror(-ret));
79 sd_event_source_unref(src);
82 static int onIoEventReceive(sd_event_source *src, int fd, uint32_t revents, void * data)
84 WMConnection *p_wmcon = (WMConnection*)data;
86 json_object *j_out[10];
88 int ret = p_wmcon->receive(j_out, &j_cnt, fd);
94 for(int i = 0; i < j_cnt; i++)
96 const char* rq = jh::getStringFromJson(j_out[i], "req");
97 const char* id = jh::getStringFromJson(j_out[i], "appid");
98 const char* dn = jh::getStringFromJson(j_out[i], "drawing_name");
99 const char* da = jh::getStringFromJson(j_out[i], "drawing_area");
101 HMI_DEBUG("req:%s appid:%s, drawing_name:%s, drawing_area:%s", rq, id, dn, da);
104 p_wmcon->callOnReceivedHandler(j_out[i]);
110 static int onIoEventAccept(sd_event_source *src, int fd, uint32_t revents, void * data)
112 WMConnection *p_wmcon = (WMConnection*)data;
114 p_wmcon->serverAccept(fd);
119 static int onIoEventConnected(sd_event_source *src, int fd, uint32_t revents, void * data)
121 WMConnection *p_wmcon = (WMConnection*)data;
123 int ret = p_wmcon->connectedToServer(fd);
129 ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
130 fd, EPOLLIN, onIoEventReceive, p_wmcon);
136 static int sleepTimerHandler(sd_event_source *s, uint64_t usec, void *userdata)
138 WMConnection *p_wmcon = (WMConnection*)userdata;
140 int ret = p_wmcon->connectToEcu();
145 static void limitTimerHandler(sd_event_source *s, uint64_t usec, void *userdata)
147 WMConnection *p_wmcon = (WMConnection*)userdata;
149 p_wmcon->connectionTimeLimit();
154 WMConnection::WMConnection()
156 this->end_init = false;
158 //Load timeout config file
159 this->loadTimeoutConfigFile();
161 // Load connection config file
162 this->loadConnectionConfigFile();
164 // TODO: ECU name should be decide by config file
165 this->ecu_name = this->mode;
168 int WMConnection::initialize()
171 uint64_t sleepTime, limitTime;
173 // Initialize for Master/Slave
174 ret = this->initializeServer();
176 sleepTime = getNextTimerTime(this->sleep);
180 HMI_ERROR("Cloud't get Next Timer");
181 goto connection_init_error;
184 ret = setTimer(&g_sleep_timer_src, sleepTime, (void *)sleepTimerHandler, this);
185 sd_event_source_set_enabled(g_sleep_timer_src, SD_EVENT_OFF);
187 limitTime = getNextTimerTime(this->times);
191 HMI_ERROR("Cloud't get Next Timer");
192 goto connection_init_error;
195 ret = setTimer(&g_limit_timer_src, limitTime, (void *)limitTimerHandler, this);
197 this->connectToEcu();
202 connection_init_error:
203 HMI_ERROR("Connection Initialize Failed");
207 void WMConnection::registerCallback(ReceivedHandler on_received)
209 this->onReceived = on_received;
212 int WMConnection::sendRequest(char const *req, char const *appid,
213 char const *drawing_name, char const *drawing_area)
216 json_object *j_obj = json_object_new_object();
217 json_object_object_add(j_obj, "req", json_object_new_string(req));
218 json_object_object_add(j_obj, "appid", json_object_new_string(appid));
219 json_object_object_add(j_obj, "drawing_name", json_object_new_string(drawing_name));
220 json_object_object_add(j_obj, "drawing_area", json_object_new_string(drawing_area));
222 std::string ecu_name = getAppIdToEcuName(appid);
224 HMI_DEBUG("send ecu_name %s", ecu_name.c_str());
226 ret = this->send(j_obj, ecu_name);
228 json_object_put(j_obj);
233 int WMConnection::send(struct json_object* j_in, std::string ecu_name)
235 SocketInfo *socketData = &this->wm_socket[ecu_name];
237 // Convert json_object to string to send
238 const char *buf = json_object_to_json_string(j_in);
241 HMI_ERROR("Failed to convert json_object to string");
245 int len = strlen(buf);
247 HMI_DEBUG("Send data(len:%d): %s", len, buf);
249 int n = write(socketData->connectedSocket(), buf, len);
252 HMI_ERROR("Failed to send data (%s)", strerror(errno));
259 bool WMConnection::isRemoteArea(const char* area)
266 std::string str_area = std::string(area);
272 std::vector<std::string> elements;
273 elements = parseString(str_area, '.');
275 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
277 if (itr->first == elements[0])
279 if (itr->first != this->ecu_name)
293 bool WMConnection::isRemoteEcu(std::string appid)
295 std::string appToEcuName = this->getAppIdToEcuName(appid);
297 if (appToEcuName == this->getEcuName() || appToEcuName == "")
307 bool WMConnection::isConnecting(std::string ecu_name)
309 return (0 > this->wm_socket[ecu_name].connectedSocket()) ? false : true;
312 bool WMConnection::isConnectionMode()
314 return (Mode_Connection == this->wm_mode) ? true : false;
317 std::string WMConnection::parseMasterArea(const char* area)
319 std::string ret_area = "";
320 std::vector<std::string> elements;
321 elements = parseString(std::string(area), '.');
323 if ("master" != elements[0])
325 return std::string(area);
328 for (auto itr = (elements.begin() + 1); itr != elements.end(); ++itr)
332 if ((elements.end() - 1) != itr)
340 bool WMConnection::isSyncDrawingForRemote(const char* appid)
342 if (std::string(appid) == this->syndDrawingAppId)
352 void WMConnection::startSyncDrawForRemote(const char* appid)
354 this->syndDrawingAppId = std::string(appid);
357 void WMConnection::finishSyncDrawForRemote(const char* appid)
359 if (std::string(appid) == this->syndDrawingAppId)
361 this->syndDrawingAppId = "";
365 std::string WMConnection::getAreaToEcuName(const char* area)
368 std::string str_area = std::string(area);
370 if (str_area.find('.') != std::string::npos)
372 std::vector<std::string> elements;
373 elements = parseString(str_area, '.');
374 result = elements[0];
384 std::string WMConnection::getSocketToEcuName(int socket)
386 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
388 if (socket == itr->second.connectedSocket())
397 std::string WMConnection::getMySocketToEcuName(int socket)
399 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
401 if (socket == itr->second.mySocket())
410 std::string WMConnection::getAppIdToEcuName(std::string appid)
412 if (appid2ecuName.count(appid) == 1)
414 return this->appid2ecuName[appid];
422 std::string WMConnection::getIpToEcuName(std::string ip)
424 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
426 if (ip == itr->second.ip())
435 void WMConnection::setAppIdToEcuName(std::string appid, std::string ecu_name)
437 this->appid2ecuName[appid] = ecu_name;
440 void WMConnection::setAppIdToReceivedEcuName(std::string appid)
442 this->appid2ecuName[appid] = received_ecu_name;
445 std::string WMConnection::getEcuName()
447 return this->ecu_name;
450 bool WMConnection::getEndInit()
452 return this->end_init;
455 int WMConnection::getSleepTime()
460 void WMConnection::callOnReceivedHandler(json_object *j_out)
462 this->onReceived(j_out);
465 int WMConnection::initializeServer()
468 struct sockaddr_in addr;
470 SocketInfo *socketData = &this->wm_socket[this->ecu_name];
473 socketData->setMySocket(socket(AF_INET, SOCK_STREAM, 0));
474 if (0 > socketData->mySocket())
476 HMI_ERROR("Failed to create socket (%s)", strerror(errno));
480 socketData->setConnectedSocket(socketData->mySocket());
483 addr.sin_family = AF_INET;
484 addr.sin_port = htons(socketData->wmPort());
485 addr.sin_addr.s_addr = htonl(INADDR_ANY);
487 ret = bind(socketData->mySocket(), (struct sockaddr *)&addr, sizeof(addr));
490 HMI_ERROR("Failed to bind socket (%s)", strerror(errno));
495 ret = listen(socketData->mySocket(), 1);
498 HMI_ERROR("Failed to listen connection (%s)", strerror(errno));
502 // Register callback to accept connection
503 ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
504 socketData->mySocket(), EPOLLIN,
505 onIoEventAccept, this);
508 HMI_ERROR("Failed to add I/O event accept(%s)", strerror(-ret));
515 int WMConnection::initializeClient(std::string ecu_name)
517 SocketInfo *socketData = &this->wm_socket[ecu_name];
519 if (socketData->mySocket() != -1)
521 close(socketData->mySocket());
525 int my_socket = socket(AF_INET, SOCK_STREAM, 0);
528 HMI_ERROR("Failed to create socket (%s)", strerror(errno));
532 socketData->setMySocket(my_socket);
537 int WMConnection::connectToEcu()
541 HMI_DEBUG("Start Connection");
543 if (this->wm_socket.empty())
545 HMI_DEBUG("Connection destination is not written to connection.json");
546 stopEvent(g_limit_timer_src);
547 stopEvent(g_sleep_timer_src);
549 this->end_init = true;
550 this->wm_mode = Mode_Standalone;
555 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
557 std::string ecu_name = itr->first;
558 HMI_DEBUG("ECU Names %s", ecu_name.c_str());
560 if (itr->second.connectedSocket() != -1 || !itr->second.masterMode())
563 HMI_DEBUG("Already Connected");
567 if (itr->second.masterMode())
569 HMI_DEBUG("Try Connection");
570 connectToServer(ecu_name);
574 if (cnt == (int)this->wm_socket.size())
576 HMI_DEBUG("All Connected!!");
578 stopEvent(g_sleep_timer_src);
579 stopEvent(g_limit_timer_src);
581 this->end_init = true;
582 this->wm_mode = Mode_Connection;
587 uint64_t sleepTime = getNextTimerTime(this->sleep);
588 updateTimer(g_sleep_timer_src, sleepTime);
593 void WMConnection::connectionTimeLimit()
595 HMI_DEBUG("Time Limit");
597 stopEvent(g_sleep_timer_src);
598 stopEvent(g_limit_timer_src);
600 this->wm_socket[this->ecu_name].setConnectedSocket(-1);
601 this->wm_mode = Mode_Standalone;
603 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
605 if (itr->second.connectedSocket() != -1)
607 HMI_DEBUG("Connection Mode");
608 this->wm_mode = Mode_Connection;
612 close(itr->second.mySocket());
616 if (this->wm_mode == Mode_Standalone)
618 close(this->wm_socket[this->ecu_name].mySocket());
621 this->end_init = true;
624 int WMConnection::connectToServer(std::string ecu_name)
627 struct sockaddr_in addr;
629 this->initializeClient(ecu_name);
631 SocketInfo *socketData = &wm_socket[ecu_name];
634 addr.sin_family = AF_INET;
635 addr.sin_port = htons(socketData->wmPort());
636 addr.sin_addr.s_addr = inet_addr(socketData->ip().c_str());
638 connect(socketData->mySocket(), (struct sockaddr *)&addr, sizeof(addr));
640 ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
641 socketData->mySocket(), EPOLLOUT,
642 onIoEventConnected, this);
646 HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
653 int WMConnection::connectedToServer(int socket)
657 struct sockaddr_in addr;
658 socklen_t addr_len = sizeof(addr);
660 std::string ecu_name = getMySocketToEcuName(socket);
662 ret = getpeername(socket, (struct sockaddr*)&addr, &addr_len);
666 HMI_DEBUG("Failed to connect %s (%s)", ecu_name.c_str(), strerror(errno));
670 HMI_DEBUG("Connected to %s", ecu_name.c_str());
672 SocketInfo *socketData = &this->wm_socket[ecu_name];
674 // Store connected socket
675 socketData->setConnectedSocket(socket);
680 int WMConnection::serverAccept(int socket)
682 struct sockaddr_in addr;
685 socklen_t len = sizeof(addr);
686 int my_socket = this->wm_socket[this->getEcuName()].mySocket();
687 int connected_socket = accept(my_socket, (struct sockaddr *)&addr, &len);
688 if (0 > connected_socket)
690 HMI_ERROR("Failed to accept connection (%s)", strerror(errno));
694 std::string ip = inet_ntoa(addr.sin_addr);
695 std::string ecu_name = getIpToEcuName(ip);
697 SocketInfo *socketData = &this->wm_socket[ecu_name];
699 // Store connected socket
700 socketData->setConnectedSocket(connected_socket);
702 // Register callback to receive
703 int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
704 connected_socket, EPOLLIN,
705 onIoEventReceive, this);
708 HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
715 int WMConnection::receive(json_object** j_out, int *j_cnt, int socket)
720 n = read(socket, buf, sizeof(buf));
723 HMI_ERROR("Failed to receive data (%s)", strerror(errno));
727 HMI_DEBUG("Received data length: %d", n);
728 HMI_DEBUG("Received data: %s", buf);
730 // Parse received data
731 struct json_tokener *tokener = json_tokener_new();
734 while (n >= tokener->char_offset)
736 j_out[cnt] = json_tokener_parse_ex(tokener, &buf[tokener->char_offset], n);
738 if (nullptr == j_out[cnt])
747 json_tokener_free(tokener);
749 this->received_ecu_name = this->getSocketToEcuName(socket);
750 HMI_DEBUG("received ecu name %s", this->received_ecu_name.c_str());
755 int WMConnection::loadTimeoutConfigFile()
757 // Get afm application installed dir
758 char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
759 if (!afm_app_install_dir)
761 HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
763 std::string path = std::string(afm_app_install_dir) + std::string(kPathTimeoutConfigFile);
765 // Load connection config file
766 json_object *json_obj;
767 int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
770 HMI_ERROR("Could not open %s, so use default timeout", path.c_str());
771 this->times = kDefaultTimes;
772 this->sleep = kDefaultSleep;
775 HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
777 int times = jh::getIntFromJson(json_obj, "times");
778 this->times = (0 != times) ? times : kDefaultTimes;
780 int sleep = jh::getIntFromJson(json_obj, "sleep");
781 this->sleep = (0 != sleep) ? sleep : kDefaultSleep;
783 // Release json_object
784 json_object_put(json_obj);
789 int WMConnection::loadConnectionConfigFile()
791 std::string path = std::string(kPathConnectionConfigFile);
793 // Load connection config file
794 json_object *json_obj, *json_cfg;
795 int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
798 HMI_ERROR("Could not open %s, so use default mode \"slave\"", kPathConnectionConfigFile);
799 this->wm_socket["slave"] = SocketInfo("slave", kDefaultIpAddr, kDefaultPort, false);
802 HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
804 const char* screen_name = jh::getStringFromJson(json_obj, "screen_name");
805 this->mode = (nullptr != screen_name) ? screen_name : "slave";
807 int wm_port = jh::getIntFromJson(json_obj, "wm_port");
809 this->wm_socket[screen_name] = SocketInfo(screen_name, "", wm_port, true);
812 HMI_DEBUG("screen_name:%s wm_port:%d", screen_name, wm_port);
814 if (!json_object_object_get_ex(json_obj, "connections", &json_cfg))
816 HMI_ERROR("connection.json Parse Error!!");
820 int len = json_object_array_length(json_cfg);
822 for (int i = 0; i < len; i++)
824 json_object *json_conn = json_object_array_get_idx(json_cfg, i);
826 std::string screen_name = jh::getStringFromJson(json_conn, "screen_name");
827 std::string ip = jh::getStringFromJson(json_conn, "ip");
828 int wm_port = jh::getIntFromJson(json_conn, "wm_port");
829 bool master_mode = jh::getBoolFromJson(json_conn, "master_mode");
831 this->wm_socket[screen_name] = SocketInfo(screen_name, ip, wm_port, master_mode);
833 HMI_DEBUG("screen_name:%s ip:%s port:%d server_mode:%s", screen_name.c_str(),
834 ip.c_str(), wm_port, (master_mode ? "true" : "false"));
837 // Release json_object
838 json_object_put(json_obj);
843 uint64_t WMConnection::getNextTimerTime(uint64_t msec)
847 if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0)
849 HMI_ERROR("Could't set time (clock_gettime() returns with error");
853 uint64_t timer_nsec = ((ts.tv_sec * 1000000000ULL) + (ts.tv_nsec) + (msec * 1000000));
857 HMI_ERROR("Second is 0");
861 return timer_nsec / 1000;