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/connection.json";
45 static const char kDefaultIpAddr[] = "192.168.10.10";
46 static const int kDefaultPort = 4000;
48 static int onIoEventReceive(sd_event_source *src, int fd, uint32_t revents, void * data)
50 WMConnection *p_wmcon = (WMConnection*)data;
53 int ret = p_wmcon->receive(&j_out);
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");
64 HMI_DEBUG("req:%s appid:%s, drawing_name:%s, drawing_area:%s", rq, id, dn, da);
67 p_wmcon->callOnReceivedHandler(j_out);
72 static int onIoEventAccept(sd_event_source *src, int fd, uint32_t revents, void * data)
74 struct sockaddr_in addr;
76 WMConnection *p_wmcon = (WMConnection*)data;
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)
84 HMI_ERROR("Failed to accept connection (%s)", strerror(errno));
88 // Store connected socket
89 p_wmcon->setConnectedSocket(connected_socket);
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);
97 HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
106 WMConnection::WMConnection()
108 // Load connection config file
109 this->loadConnectionConfigFile();
111 // TODO: ECU name should be decide by config file
112 this->ecu_name = this->mode;
115 int WMConnection::initialize()
119 // Initialize for Master/Slave
120 if (this->isMasterMode())
122 ret = this->initializeMaster();
126 ret = this->initializeSlave();
132 void WMConnection::registerCallback(ReceivedHandler on_received)
134 this->onReceived = on_received;
137 int WMConnection::sendRequest(char const *req, char const *appid,
138 char const *drawing_name, char const *drawing_area)
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));
147 ret = this->send(j_obj);
149 json_object_put(j_obj);
154 int WMConnection::send(struct json_object* j_in)
156 // Convert json_object to string to send
157 const char *buf = json_object_to_json_string(j_in);
160 HMI_ERROR("Failed to convert json_object to string");
164 int len = strlen(buf);
166 HMI_DEBUG("Send data(len:%d): %s", len, buf);
168 int n = write(this->connected_socket, buf, len);
171 HMI_ERROR("Failed to send data (%s)", strerror(errno));
178 bool WMConnection::isMasterMode()
180 if ("master" == this->mode)
190 bool WMConnection::isMasterArea(const char* area)
197 std::string str_area = std::string(area);
203 std::vector<std::string> elements;
204 elements = parseString(str_area, '.');
206 if ("master" == elements[0])
216 bool WMConnection::isConnecting()
218 return (0 > this->connected_socket) ? false : true;
221 std::string WMConnection::parseMasterArea(const char* area)
223 std::string ret_area = "";
224 std::vector<std::string> elements;
225 elements = parseString(std::string(area), '.');
227 if ("master" != elements[0])
229 return std::string(area);
232 for (auto itr = (elements.begin() + 1); itr != elements.end(); ++itr)
236 if ((elements.end() - 1) != itr)
244 bool WMConnection::isSyncDrawingForRemote(const char* appid)
246 if (std::string(appid) == this->syndDrawingAppId)
256 void WMConnection::startSyncDrawForRemote(const char* appid)
258 this->syndDrawingAppId = std::string(appid);
261 void WMConnection::finishSyncDrawForRemote(const char* appid)
263 if (std::string(appid) == this->syndDrawingAppId)
265 this->syndDrawingAppId = "";
269 int WMConnection::getMySocket()
271 return this->my_socket;
274 int WMConnection::getConnectedSocket()
276 return this->connected_socket;
279 void WMConnection::setConnectedSocket(int connected_socket)
281 this->connected_socket = connected_socket;
284 std::string WMConnection::getEcuName()
286 return this->ecu_name;
289 void WMConnection::callOnReceivedHandler(json_object *j_out)
291 this->onReceived(j_out);
294 int WMConnection::initializeMaster()
297 struct sockaddr_in addr;
300 this->my_socket = socket(AF_INET, SOCK_STREAM, 0);
301 if (0 > this->my_socket)
303 HMI_ERROR("Failed to create socket (%s)", strerror(errno));
308 addr.sin_family = AF_INET;
309 addr.sin_port = htons(this->port);
310 addr.sin_addr.s_addr = htonl(INADDR_ANY);
312 ret = bind(this->my_socket, (struct sockaddr *)&addr, sizeof(addr));
315 HMI_ERROR("Failed to bind socket (%s)", strerror(errno));
320 ret = listen(this->my_socket, 1);
323 HMI_ERROR("Failed to listen connection (%s)", strerror(errno));
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);
333 HMI_ERROR("Failed to add I/O event accept(%s)", strerror(-ret));
340 int WMConnection::initializeSlave()
343 this->my_socket = socket(AF_INET, SOCK_STREAM, 0);
344 if (0 > this->my_socket)
346 HMI_ERROR("Failed to create socket (%s)", strerror(errno));
353 int WMConnection::connectToMaster()
356 struct sockaddr_in addr;
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());
363 ret = connect(this->my_socket, (struct sockaddr *)&addr, sizeof(addr));
366 HMI_ERROR("Failed to connect to master (%s)", strerror(errno));
370 HMI_DEBUG("Connected to master");
372 // Store connected socket
373 this->connected_socket = this->my_socket;
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);
381 HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
388 int WMConnection::receive(struct json_object** j_out)
393 n = read(this->connected_socket, buf, sizeof(buf));
396 HMI_ERROR("Failed to receive data (%s)", strerror(errno));
400 HMI_DEBUG("Received data length: %d", n);
401 HMI_DEBUG("Received data: %s", buf);
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)
408 HMI_DEBUG("Failed to parse received data");
415 int WMConnection::loadConnectionConfigFile()
417 // Get afm application installed dir
418 char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
419 if (!afm_app_install_dir)
421 HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
423 std::string path = std::string(afm_app_install_dir) + std::string(kPathConnectionConfigFile);
425 // Load connection config file
426 json_object* json_obj;
427 int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
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;
436 HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
438 const char* mode = jh::getStringFromJson(json_obj, "mode");
439 this->mode = (nullptr != mode) ? mode : "slave";
441 const char* ip = jh::getStringFromJson(json_obj, "master_ip");
442 this->ip = (nullptr != ip) ? ip : kDefaultIpAddr;
444 int port = jh::getIntFromJson(json_obj, "master_port");
445 this->port = (0 != port) ? port : kDefaultPort;
448 HMI_DEBUG("mode:%s master_ip:%s master_port:%d", mode, ip, port);
450 // Release json_object
451 json_object_put(json_obj);