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::isConnecting(std::string ecu_name)
295 return (0 > this->wm_socket[ecu_name].connectedSocket()) ? false : true;
298 bool WMConnection::isConnectionMode()
300 return (Mode_Connection == this->wm_mode) ? true : false;
303 std::string WMConnection::parseMasterArea(const char* area)
305 std::string ret_area = "";
306 std::vector<std::string> elements;
307 elements = parseString(std::string(area), '.');
309 if ("master" != elements[0])
311 return std::string(area);
314 for (auto itr = (elements.begin() + 1); itr != elements.end(); ++itr)
318 if ((elements.end() - 1) != itr)
326 bool WMConnection::isSyncDrawingForRemote(const char* appid)
328 if (std::string(appid) == this->syndDrawingAppId)
338 void WMConnection::startSyncDrawForRemote(const char* appid)
340 this->syndDrawingAppId = std::string(appid);
343 void WMConnection::finishSyncDrawForRemote(const char* appid)
345 if (std::string(appid) == this->syndDrawingAppId)
347 this->syndDrawingAppId = "";
351 std::string WMConnection::getAreaToEcuName(const char* area)
354 std::string str_area = std::string(area);
356 if (str_area.find('.') != std::string::npos)
358 std::vector<std::string> elements;
359 elements = parseString(str_area, '.');
360 result = elements[0];
370 std::string WMConnection::getSocketToEcuName(int socket)
372 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
374 if (socket == itr->second.connectedSocket())
383 std::string WMConnection::getMySocketToEcuName(int socket)
385 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
387 if (socket == itr->second.mySocket())
396 std::string WMConnection::getAppIdToEcuName(std::string appid)
398 if (appid2ecuName.count(appid) == 1)
400 return this->appid2ecuName[appid];
408 std::string WMConnection::getIpToEcuName(std::string ip)
410 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
412 if (ip == itr->second.ip())
421 void WMConnection::setAppIdToEcuName(std::string appid, std::string ecu_name)
423 this->appid2ecuName[appid] = ecu_name;
426 void WMConnection::setAppIdToReceivedEcuName(std::string appid)
428 this->appid2ecuName[appid] = received_ecu_name;
431 std::string WMConnection::getEcuName()
433 return this->ecu_name;
436 bool WMConnection::getEndInit()
438 return this->end_init;
441 void WMConnection::callOnReceivedHandler(json_object *j_out)
443 this->onReceived(j_out);
446 int WMConnection::initializeServer()
449 struct sockaddr_in addr;
451 SocketInfo *socketData = &this->wm_socket[this->ecu_name];
454 socketData->setMySocket(socket(AF_INET, SOCK_STREAM, 0));
455 if (0 > socketData->mySocket())
457 HMI_ERROR("Failed to create socket (%s)", strerror(errno));
461 socketData->setConnectedSocket(socketData->mySocket());
464 addr.sin_family = AF_INET;
465 addr.sin_port = htons(socketData->wmPort());
466 addr.sin_addr.s_addr = htonl(INADDR_ANY);
468 ret = bind(socketData->mySocket(), (struct sockaddr *)&addr, sizeof(addr));
471 HMI_ERROR("Failed to bind socket (%s)", strerror(errno));
476 ret = listen(socketData->mySocket(), 1);
479 HMI_ERROR("Failed to listen connection (%s)", strerror(errno));
483 // Register callback to accept connection
484 ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
485 socketData->mySocket(), EPOLLIN,
486 onIoEventAccept, this);
489 HMI_ERROR("Failed to add I/O event accept(%s)", strerror(-ret));
496 int WMConnection::initializeClient(std::string ecu_name)
498 SocketInfo *socketData = &this->wm_socket[ecu_name];
500 if (socketData->mySocket() != -1)
502 close(socketData->mySocket());
506 int my_socket = socket(AF_INET, SOCK_STREAM, 0);
509 HMI_ERROR("Failed to create socket (%s)", strerror(errno));
513 socketData->setMySocket(my_socket);
518 int WMConnection::connectToEcu()
522 HMI_DEBUG("Start Connection");
524 if (this->wm_socket.empty())
526 HMI_DEBUG("Connection destination is not written to connection.json");
527 stopEvent(g_limit_timer_src);
528 stopEvent(g_sleep_timer_src);
530 this->end_init = true;
531 this->wm_mode = Mode_Standalone;
536 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
538 std::string ecu_name = itr->first;
539 HMI_DEBUG("ECU Names %s", ecu_name.c_str());
541 if (itr->second.connectedSocket() != -1 || !itr->second.masterMode())
544 HMI_DEBUG("Already Connected");
548 if (itr->second.masterMode())
550 HMI_DEBUG("Try Connection");
551 connectToServer(ecu_name);
555 if (cnt == (int)this->wm_socket.size())
557 HMI_DEBUG("All Connected!!");
559 stopEvent(g_sleep_timer_src);
560 stopEvent(g_limit_timer_src);
562 this->end_init = true;
563 this->wm_mode = Mode_Connection;
568 uint64_t sleepTime = getNextTimerTime(this->sleep);
569 updateTimer(g_sleep_timer_src, sleepTime);
574 void WMConnection::connectionTimeLimit()
576 HMI_DEBUG("Time Limit");
578 stopEvent(g_sleep_timer_src);
579 stopEvent(g_limit_timer_src);
581 this->wm_socket[this->ecu_name].setConnectedSocket(-1);
582 this->wm_mode = Mode_Standalone;
584 for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
586 if (itr->second.connectedSocket() != -1)
588 HMI_DEBUG("Connection Mode");
589 this->wm_mode = Mode_Connection;
593 close(itr->second.mySocket());
597 if (this->wm_mode == Mode_Standalone)
599 close(this->wm_socket[this->ecu_name].mySocket());
602 this->end_init = true;
605 int WMConnection::connectToServer(std::string ecu_name)
608 struct sockaddr_in addr;
610 this->initializeClient(ecu_name);
612 SocketInfo *socketData = &wm_socket[ecu_name];
615 addr.sin_family = AF_INET;
616 addr.sin_port = htons(socketData->wmPort());
617 addr.sin_addr.s_addr = inet_addr(socketData->ip().c_str());
619 connect(socketData->mySocket(), (struct sockaddr *)&addr, sizeof(addr));
621 ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
622 socketData->mySocket(), EPOLLOUT,
623 onIoEventConnected, this);
627 HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
634 int WMConnection::connectedToServer(int socket)
638 struct sockaddr_in addr;
639 socklen_t addr_len = sizeof(addr);
641 std::string ecu_name = getMySocketToEcuName(socket);
643 ret = getpeername(socket, (struct sockaddr*)&addr, &addr_len);
647 HMI_DEBUG("Failed to connect %s (%s)", ecu_name.c_str(), strerror(errno));
651 HMI_DEBUG("Connected to %s", ecu_name.c_str());
653 SocketInfo *socketData = &this->wm_socket[ecu_name];
655 // Store connected socket
656 socketData->setConnectedSocket(socket);
661 int WMConnection::serverAccept(int socket)
663 struct sockaddr_in addr;
666 socklen_t len = sizeof(addr);
667 int my_socket = this->wm_socket[this->getEcuName()].mySocket();
668 int connected_socket = accept(my_socket, (struct sockaddr *)&addr, &len);
669 if (0 > connected_socket)
671 HMI_ERROR("Failed to accept connection (%s)", strerror(errno));
675 std::string ip = inet_ntoa(addr.sin_addr);
676 std::string ecu_name = getIpToEcuName(ip);
678 SocketInfo *socketData = &this->wm_socket[ecu_name];
680 // Store connected socket
681 socketData->setConnectedSocket(connected_socket);
683 // Register callback to receive
684 int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
685 connected_socket, EPOLLIN,
686 onIoEventReceive, this);
689 HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
696 int WMConnection::receive(json_object** j_out, int *j_cnt, int socket)
701 n = read(socket, buf, sizeof(buf));
704 HMI_ERROR("Failed to receive data (%s)", strerror(errno));
708 HMI_DEBUG("Received data length: %d", n);
709 HMI_DEBUG("Received data: %s", buf);
711 // Parse received data
712 struct json_tokener *tokener = json_tokener_new();
715 while (n >= tokener->char_offset)
717 j_out[cnt] = json_tokener_parse_ex(tokener, &buf[tokener->char_offset], n);
719 if (nullptr == j_out[cnt])
728 json_tokener_free(tokener);
730 this->received_ecu_name = this->getSocketToEcuName(socket);
731 HMI_DEBUG("received ecu name %s", this->received_ecu_name.c_str());
736 int WMConnection::loadTimeoutConfigFile()
738 // Get afm application installed dir
739 char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
740 if (!afm_app_install_dir)
742 HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
744 std::string path = std::string(afm_app_install_dir) + std::string(kPathTimeoutConfigFile);
746 // Load connection config file
747 json_object *json_obj;
748 int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
751 HMI_ERROR("Could not open %s, so use default timeout", path.c_str());
752 this->times = kDefaultTimes;
753 this->sleep = kDefaultSleep;
756 HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
758 int times = jh::getIntFromJson(json_obj, "times");
759 this->times = (0 != times) ? times : kDefaultTimes;
761 int sleep = jh::getIntFromJson(json_obj, "sleep");
762 this->sleep = (0 != sleep) ? sleep : kDefaultSleep;
764 // Release json_object
765 json_object_put(json_obj);
770 int WMConnection::loadConnectionConfigFile()
772 std::string path = std::string(kPathConnectionConfigFile);
774 // Load connection config file
775 json_object *json_obj, *json_cfg;
776 int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
779 HMI_ERROR("Could not open %s, so use default mode \"slave\"", kPathConnectionConfigFile);
780 this->wm_socket["slave"] = SocketInfo("slave", kDefaultIpAddr, kDefaultPort, false);
783 HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
785 const char* screen_name = jh::getStringFromJson(json_obj, "screen_name");
786 this->mode = (nullptr != screen_name) ? screen_name : "slave";
788 int wm_port = jh::getIntFromJson(json_obj, "wm_port");
790 this->wm_socket[screen_name] = SocketInfo(screen_name, "", wm_port, true);
793 HMI_DEBUG("screen_name:%s wm_port:%d", screen_name, wm_port);
795 if (!json_object_object_get_ex(json_obj, "connections", &json_cfg))
797 HMI_ERROR("connection.json Parse Error!!");
801 int len = json_object_array_length(json_cfg);
803 for (int i = 0; i < len; i++)
805 json_object *json_conn = json_object_array_get_idx(json_cfg, i);
807 std::string screen_name = jh::getStringFromJson(json_conn, "screen_name");
808 std::string ip = jh::getStringFromJson(json_conn, "ip");
809 int wm_port = jh::getIntFromJson(json_conn, "wm_port");
810 bool master_mode = jh::getBoolFromJson(json_conn, "master_mode");
812 this->wm_socket[screen_name] = SocketInfo(screen_name, ip, wm_port, master_mode);
814 HMI_DEBUG("screen_name:%s ip:%s port:%d server_mode:%s", screen_name.c_str(),
815 ip.c_str(), wm_port, (master_mode ? "true" : "false"));
818 // Release json_object
819 json_object_put(json_obj);
824 uint64_t WMConnection::getNextTimerTime(uint64_t msec)
828 if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0)
830 HMI_ERROR("Could't set time (clock_gettime() returns with error");
834 uint64_t timer_nsec = ((ts.tv_sec * 1000000000ULL) + (ts.tv_nsec) + (msec * 1000000));
838 HMI_ERROR("Second is 0");
842 return timer_nsec / 1000;