aboutsummaryrefslogtreecommitdiffstats
path: root/src/wm_connection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wm_connection.cpp')
-rw-r--r--src/wm_connection.cpp457
1 files changed, 457 insertions, 0 deletions
diff --git a/src/wm_connection.cpp b/src/wm_connection.cpp
new file mode 100644
index 0000000..10ecc3b
--- /dev/null
+++ b/src/wm_connection.cpp
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wm_connection.hpp"
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "json_helper.hpp"
+#include "util.hpp"
+
+extern "C"
+{
+#include <afb/afb-binding.h>
+#include <systemd/sd-event.h>
+}
+
+
+/**
+ * namespace wm
+ */
+namespace wm
+{
+
+
+namespace
+{
+
+static const char kPathConnectionConfigFile[] = "/etc/connection.json";
+static const char kDefaultIpAddr[] = "192.168.10.10";
+static const int kDefaultPort = 4000;
+
+static int onIoEventReceive(sd_event_source *src, int fd, uint32_t revents, void * data)
+{
+ WMConnection *p_wmcon = (WMConnection*)data;
+
+ json_object *j_out;
+ int ret = p_wmcon->receive(&j_out);
+ if (0 > ret)
+ {
+ return 0;
+ }
+
+ const char* rq = jh::getStringFromJson(j_out, "req");
+ const char* id = jh::getStringFromJson(j_out, "appid");
+ const char* dn = jh::getStringFromJson(j_out, "drawing_name");
+ const char* da = jh::getStringFromJson(j_out, "drawing_area");
+
+ HMI_DEBUG("req:%s appid:%s, drawing_name:%s, drawing_area:%s", rq, id, dn, da);
+
+ // Callback
+ p_wmcon->callOnReceivedHandler(j_out);
+
+ return 0;
+}
+
+static int onIoEventAccept(sd_event_source *src, int fd, uint32_t revents, void * data)
+{
+ struct sockaddr_in addr;
+
+ WMConnection *p_wmcon = (WMConnection*)data;
+
+ // Accept connection
+ socklen_t len = sizeof(addr);
+ int my_socket = p_wmcon->getMySocket();
+ int connected_socket = accept(my_socket, (struct sockaddr *)&addr, &len);
+ if (0 > connected_socket)
+ {
+ HMI_ERROR("Failed to accept connection (%s)", strerror(errno));
+ return -1;
+ }
+
+ // Store connected socket
+ p_wmcon->setConnectedSocket(connected_socket);
+
+ // Register callback to receive
+ int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
+ connected_socket, EPOLLIN,
+ onIoEventReceive, p_wmcon);
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+} // namespace
+
+WMConnection::WMConnection()
+{
+ // Load connection config file
+ this->loadConnectionConfigFile();
+
+ // TODO: ECU name should be decide by config file
+ this->ecu_name = this->mode;
+}
+
+int WMConnection::initialize()
+{
+ int ret;
+
+ // Initialize for Master/Slave
+ if (this->isMasterMode())
+ {
+ ret = this->initializeMaster();
+ }
+ else
+ {
+ ret = this->initializeSlave();
+ }
+
+ return ret;
+}
+
+void WMConnection::registerCallback(ReceivedHandler on_received)
+{
+ this->onReceived = on_received;
+}
+
+int WMConnection::sendRequest(char const *req, char const *appid,
+ char const *drawing_name, char const *drawing_area)
+{
+ int ret;
+ json_object *j_obj = json_object_new_object();
+ json_object_object_add(j_obj, "req", json_object_new_string(req));
+ json_object_object_add(j_obj, "appid", json_object_new_string(appid));
+ json_object_object_add(j_obj, "drawing_name", json_object_new_string(drawing_name));
+ json_object_object_add(j_obj, "drawing_area", json_object_new_string(drawing_area));
+
+ ret = this->send(j_obj);
+
+ json_object_put(j_obj);
+
+ return ret;
+}
+
+int WMConnection::send(struct json_object* j_in)
+{
+ // Convert json_object to string to send
+ const char *buf = json_object_to_json_string(j_in);
+ if (nullptr == buf)
+ {
+ HMI_ERROR("Failed to convert json_object to string");
+ return -1;
+ }
+
+ int len = strlen(buf);
+
+ HMI_DEBUG("Send data(len:%d): %s", len, buf);
+
+ int n = write(this->connected_socket, buf, len);
+ if(0 > n)
+ {
+ HMI_ERROR("Failed to send data (%s)", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+bool WMConnection::isMasterMode()
+{
+ if ("master" == this->mode)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool WMConnection::isMasterArea(const char* area)
+{
+ if (nullptr == area)
+ {
+ return false;
+ }
+
+ std::string str_area = std::string(area);
+ if ("" == str_area)
+ {
+ return false;
+ }
+
+ std::vector<std::string> elements;
+ elements = parseString(str_area, '.');
+
+ if ("master" == elements[0])
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool WMConnection::isConnecting()
+{
+ return (0 > this->connected_socket) ? false : true;
+}
+
+std::string WMConnection::parseMasterArea(const char* area)
+{
+ std::string ret_area = "";
+ std::vector<std::string> elements;
+ elements = parseString(std::string(area), '.');
+
+ if ("master" != elements[0])
+ {
+ return std::string(area);
+ }
+
+ for (auto itr = (elements.begin() + 1); itr != elements.end(); ++itr)
+ {
+ ret_area += *itr;
+
+ if ((elements.end() - 1) != itr)
+ {
+ ret_area += ".";
+ }
+ }
+ return ret_area;
+}
+
+bool WMConnection::isSyncDrawingForRemote(const char* appid)
+{
+ if (std::string(appid) == this->syndDrawingAppId)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void WMConnection::startSyncDrawForRemote(const char* appid)
+{
+ this->syndDrawingAppId = std::string(appid);
+}
+
+void WMConnection::finishSyncDrawForRemote(const char* appid)
+{
+ if (std::string(appid) == this->syndDrawingAppId)
+ {
+ this->syndDrawingAppId = "";
+ }
+}
+
+int WMConnection::getMySocket()
+{
+ return this->my_socket;
+}
+
+int WMConnection::getConnectedSocket()
+{
+ return this->connected_socket;
+}
+
+void WMConnection::setConnectedSocket(int connected_socket)
+{
+ this->connected_socket = connected_socket;
+}
+
+std::string WMConnection::getEcuName()
+{
+ return this->ecu_name;
+}
+
+void WMConnection::callOnReceivedHandler(json_object *j_out)
+{
+ this->onReceived(j_out);
+}
+
+int WMConnection::initializeMaster()
+{
+ int ret = 0;
+ struct sockaddr_in addr;
+
+ // Create socket
+ this->my_socket = socket(AF_INET, SOCK_STREAM, 0);
+ if (0 > this->my_socket)
+ {
+ HMI_ERROR("Failed to create socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ // Bind socket
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(this->port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ ret = bind(this->my_socket, (struct sockaddr *)&addr, sizeof(addr));
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to bind socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ // Listen connection
+ ret = listen(this->my_socket, 1);
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to listen connection (%s)", strerror(errno));
+ return -1;
+ }
+
+ // Register callback to accept connection
+ ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
+ this->my_socket, EPOLLIN,
+ onIoEventAccept, this);
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to add I/O event accept(%s)", strerror(-ret));
+ return -1;
+ }
+
+ return ret;
+}
+
+int WMConnection::initializeSlave()
+{
+ // Create socket
+ this->my_socket = socket(AF_INET, SOCK_STREAM, 0);
+ if (0 > this->my_socket)
+ {
+ HMI_ERROR("Failed to create socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int WMConnection::connectToMaster()
+{
+ int ret = 0;
+ struct sockaddr_in addr;
+
+ // Connect to master
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(this->port);
+ addr.sin_addr.s_addr = inet_addr(this->ip.c_str());
+
+ ret = connect(this->my_socket, (struct sockaddr *)&addr, sizeof(addr));
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to connect to master (%s)", strerror(errno));
+ return ret;
+ }
+
+ HMI_DEBUG("Connected to master");
+
+ // Store connected socket
+ this->connected_socket = this->my_socket;
+
+ // Register callback to receive
+ ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
+ this->connected_socket, EPOLLIN,
+ onIoEventReceive, this);
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
+ return -1;
+ }
+
+ return ret;
+}
+
+int WMConnection::receive(struct json_object** j_out)
+{
+ char buf[1024];
+ int n;
+
+ n = read(this->connected_socket, buf, sizeof(buf));
+ if(0 > n)
+ {
+ HMI_ERROR("Failed to receive data (%s)", strerror(errno));
+ return -1;
+ }
+
+ HMI_DEBUG("Received data length: %d", n);
+ HMI_DEBUG("Received data: %s", buf);
+
+ // Parse received data
+ struct json_tokener *tokener = json_tokener_new();
+ *j_out = json_tokener_parse_ex(tokener, buf, n);
+ if (nullptr == *j_out)
+ {
+ HMI_DEBUG("Failed to parse received data");
+ return -1;
+ }
+
+ return 0;
+}
+
+int WMConnection::loadConnectionConfigFile()
+{
+ // Get afm application installed dir
+ char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
+ if (!afm_app_install_dir)
+ {
+ HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
+ }
+ std::string path = std::string(afm_app_install_dir) + std::string(kPathConnectionConfigFile);
+
+ // Load connection config file
+ json_object* json_obj;
+ int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
+ if (0 > ret)
+ {
+ HMI_ERROR("Could not open %s, so use default mode \"slave\"", kPathConnectionConfigFile);
+ this->mode = "slave";
+ this->ip = kDefaultIpAddr;
+ this->port = kDefaultPort;
+ return 0;
+ }
+ HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
+
+ const char* mode = jh::getStringFromJson(json_obj, "mode");
+ this->mode = (nullptr != mode) ? mode : "slave";
+
+ const char* ip = jh::getStringFromJson(json_obj, "master_ip");
+ this->ip = (nullptr != ip) ? ip : kDefaultIpAddr;
+
+ int port = jh::getIntFromJson(json_obj, "master_port");
+ this->port = (0 != port) ? port : kDefaultPort;
+
+ // Check
+ HMI_DEBUG("mode:%s master_ip:%s master_port:%d", mode, ip, port);
+
+ // Release json_object
+ json_object_put(json_obj);
+
+ return 0;
+}
+
+
+} // namespace wm