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->first == this->ecu_name)
563 HMI_DEBUG("Already Connected");
567 if (itr->second.masterMode())
569 HMI_DEBUG("Try Connection");
570 connectToServer(ecu_name);
573 HMI_DEBUG("Wait Connection");
577 if (cnt == (int)this->wm_socket.size())
579 HMI_DEBUG("All Connected!!");
581 stopEvent(g_sleep_timer_src);
582 stopEvent(g_limit_timer_src);
584 this->end_init = true;
585 this->wm_mode = Mode_Connection;
590 uint64_t sleepTime = getNextTimerTime(this->sleep);
591 updateTimer(g_sleep_timer_src, sleepTime);
596 void WMConnection::connectionTimeLimit()
598 HMI_DEBUG("Time Limit");
600 stopEvent(g_sleep_timer_src);
601 stopEvent(g_limit_timer_src);
603 this->wm_socket[this->ecu_name].setConnectedSocket(-1);
604 this->wm_mode = Mode_Standalone;
606 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
608 if (itr->second.connectedSocket() != -1)
610 HMI_DEBUG("Connection Mode");
611 this->wm_mode = Mode_Connection;
615 close(itr->second.mySocket());
619 if (this->wm_mode == Mode_Standalone)
621 close(this->wm_socket[this->ecu_name].mySocket());
624 this->end_init = true;
627 int WMConnection::connectToServer(std::string ecu_name)
630 struct sockaddr_in addr;
632 this->initializeClient(ecu_name);
634 SocketInfo *socketData = &wm_socket[ecu_name];
637 addr.sin_family = AF_INET;
638 addr.sin_port = htons(socketData->wmPort());
639 addr.sin_addr.s_addr = inet_addr(socketData->ip().c_str());
641 connect(socketData->mySocket(), (struct sockaddr *)&addr, sizeof(addr));
643 ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
644 socketData->mySocket(), EPOLLOUT,
645 onIoEventConnected, this);
649 HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
656 int WMConnection::connectedToServer(int socket)
660 struct sockaddr_in addr;
661 socklen_t addr_len = sizeof(addr);
663 std::string ecu_name = getMySocketToEcuName(socket);
665 ret = getpeername(socket, (struct sockaddr*)&addr, &addr_len);
669 HMI_DEBUG("Failed to connect %s (%s)", ecu_name.c_str(), strerror(errno));
673 HMI_DEBUG("Connected to %s", ecu_name.c_str());
675 SocketInfo *socketData = &this->wm_socket[ecu_name];
677 // Store connected socket
678 socketData->setConnectedSocket(socket);
683 int WMConnection::serverAccept(int socket)
685 struct sockaddr_in addr;
688 socklen_t len = sizeof(addr);
689 int my_socket = this->wm_socket[this->getEcuName()].mySocket();
690 int connected_socket = accept(my_socket, (struct sockaddr *)&addr, &len);
691 if (0 > connected_socket)
693 HMI_ERROR("Failed to accept connection (%s)", strerror(errno));
697 std::string ip = inet_ntoa(addr.sin_addr);
698 std::string ecu_name = getIpToEcuName(ip);
700 SocketInfo *socketData = &this->wm_socket[ecu_name];
702 // Store connected socket
703 socketData->setConnectedSocket(connected_socket);
705 // Register callback to receive
706 int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
707 connected_socket, EPOLLIN,
708 onIoEventReceive, this);
711 HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
718 int WMConnection::receive(json_object** j_out, int *j_cnt, int socket)
723 n = read(socket, buf, sizeof(buf));
726 HMI_ERROR("Failed to receive data (%s)", strerror(errno));
730 HMI_DEBUG("Received data length: %d", n);
731 HMI_DEBUG("Received data: %s", buf);
733 // Parse received data
734 struct json_tokener *tokener = json_tokener_new();
737 while (n >= tokener->char_offset)
739 j_out[cnt] = json_tokener_parse_ex(tokener, &buf[tokener->char_offset], n);
741 if (nullptr == j_out[cnt])
750 json_tokener_free(tokener);
752 this->received_ecu_name = this->getSocketToEcuName(socket);
753 HMI_DEBUG("received ecu name %s", this->received_ecu_name.c_str());
758 int WMConnection::loadTimeoutConfigFile()
760 // Get afm application installed dir
761 char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
762 if (!afm_app_install_dir)
764 HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
766 std::string path = std::string(afm_app_install_dir) + std::string(kPathTimeoutConfigFile);
768 // Load connection config file
769 json_object *json_obj;
770 int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
773 HMI_ERROR("Could not open %s, so use default timeout", path.c_str());
774 this->times = kDefaultTimes;
775 this->sleep = kDefaultSleep;
778 HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
780 int times = jh::getIntFromJson(json_obj, "times");
781 this->times = (0 != times) ? times : kDefaultTimes;
783 int sleep = jh::getIntFromJson(json_obj, "sleep");
784 this->sleep = (0 != sleep) ? sleep : kDefaultSleep;
786 // Release json_object
787 json_object_put(json_obj);
792 int WMConnection::loadConnectionConfigFile()
794 std::string path = std::string(kPathConnectionConfigFile);
796 // Load connection config file
797 json_object *json_obj, *json_cfg;
798 int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
801 HMI_ERROR("Could not open %s, so use default mode \"slave\"", kPathConnectionConfigFile);
802 this->wm_socket["slave"] = SocketInfo("slave", kDefaultIpAddr, kDefaultPort, false);
805 HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
807 const char* screen_name = jh::getStringFromJson(json_obj, "screen_name");
808 this->mode = (nullptr != screen_name) ? screen_name : "slave";
810 int wm_port = jh::getIntFromJson(json_obj, "wm_port");
812 this->wm_socket[screen_name] = SocketInfo(screen_name, "", wm_port, true);
815 HMI_DEBUG("screen_name:%s wm_port:%d", screen_name, wm_port);
817 if (!json_object_object_get_ex(json_obj, "connections", &json_cfg))
819 HMI_ERROR("connection.json Parse Error!!");
823 int len = json_object_array_length(json_cfg);
825 for (int i = 0; i < len; i++)
827 json_object *json_conn = json_object_array_get_idx(json_cfg, i);
829 std::string screen_name = jh::getStringFromJson(json_conn, "screen_name");
830 std::string ip = jh::getStringFromJson(json_conn, "ip");
831 int wm_port = jh::getIntFromJson(json_conn, "wm_port");
832 bool master_mode = jh::getBoolFromJson(json_conn, "master_mode");
834 this->wm_socket[screen_name] = SocketInfo(screen_name, ip, wm_port, master_mode);
836 HMI_DEBUG("screen_name:%s ip:%s port:%d server_mode:%s", screen_name.c_str(),
837 ip.c_str(), wm_port, (master_mode ? "true" : "false"));
840 // Release json_object
841 json_object_put(json_obj);
846 uint64_t WMConnection::getNextTimerTime(uint64_t msec)
850 if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0)
852 HMI_ERROR("Could't set time (clock_gettime() returns with error");
856 uint64_t timer_nsec = ((ts.tv_sec * 1000000000ULL) + (ts.tv_nsec) + (msec * 1000000));
860 HMI_ERROR("Second is 0");
864 return timer_nsec / 1000;