diff --git a/CMakeLists.txt b/CMakeLists.txt index 922f571..795800d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,7 @@ AUX_SOURCE_DIRECTORY(controllers CTL_SRC) AUX_SOURCE_DIRECTORY(filters FILTER_SRC) AUX_SOURCE_DIRECTORY(plugins PLUGIN_SRC) AUX_SOURCE_DIRECTORY(models MODEL_SRC) +AUX_SOURCE_DIRECTORY(helpers HELPER_SRC) include_directories(/usr/local/include) @@ -103,4 +104,4 @@ foreach(cspFile ${SCP_LIST}) endforeach() include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -add_executable(emgauwa-core ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${PLUGIN_SRC} ${MODEL_SRC}) +add_executable(emgauwa-core ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${PLUGIN_SRC} ${MODEL_SRC} ${HELPER_SRC}) diff --git a/config.cc b/config.cc new file mode 100644 index 0000000..f819d3d --- /dev/null +++ b/config.cc @@ -0,0 +1,8 @@ +#include "config.h" + +namespace config +{ + int discover_max_client_backlog = 20; + int discover_port_dev = 4420; + int discover_port = 4419; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..cae0bf4 --- /dev/null +++ b/config.h @@ -0,0 +1,11 @@ +#ifndef EMGAUWA_CORE_CONFIG_H +#define EMGAUWA_CORE_CONFIG_H + +namespace config +{ + extern int discover_max_client_backlog; + extern int discover_port_dev; + extern int discover_port; +} + +#endif //EMGAUWA_CORE_CONFIG_H diff --git a/controllers/api_v1_Devices.cc b/controllers/api_v1_Devices.cc deleted file mode 100644 index 114494b..0000000 --- a/controllers/api_v1_Devices.cc +++ /dev/null @@ -1,43 +0,0 @@ -#include "api_v1_Devices.h" -using namespace api::v1; -//add definition of your processing function here - -void Devices::get_all(const HttpRequestPtr &req, std::function &&callback) -{ - - std::cout << "Get All\n"; - - auto resp=HttpResponse::newHttpResponse(); - callback(resp); -} - -void Devices::get_one(const HttpRequestPtr &req, std::function &&callback, - std::string device_id) -{ - std::cout << "Get One: " << device_id << "\n"; - - auto resp=HttpResponse::newHttpResponse(); - callback(resp); -} - -void Devices::get_relays_all(const HttpRequestPtr &req, std::function &&callback, - std::string device_id) -{ - std::cout << "Get Relays All: " << device_id << "\n"; - - auto resp=HttpResponse::newHttpResponse(); - callback(resp); -} - -void Devices::get_relays_one(const HttpRequestPtr &req, std::function &&callback, - std::string device_id, std::string relay_id) -{ - std::cout << "Get Relays One: " << device_id << "; " << relay_id << "\n"; - - Json::Value ret; - ret["result"] = "ok"; - ret["device_id"] = device_id; - ret["relay_id"] = relay_id; - auto resp = HttpResponse::newHttpJsonResponse(ret); - callback(resp); -} diff --git a/controllers/api_v1_Devices.h b/controllers/api_v1_Devices.h deleted file mode 100644 index 1c247b9..0000000 --- a/controllers/api_v1_Devices.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include -using namespace drogon; -namespace api -{ - namespace v1 - { - class Devices:public drogon::HttpController - { - public: - METHOD_LIST_BEGIN - METHOD_ADD(Devices::get_all,"/",Get); - METHOD_ADD(Devices::get_one,"/{1}",Get); - METHOD_ADD(Devices::get_relays_all,"/{1}/relays",Get); - METHOD_ADD(Devices::get_relays_one,"/{1}/relays/{2}",Get); - METHOD_LIST_END - - void get_all(const HttpRequestPtr& req,std::function &&callback); - void get_one(const HttpRequestPtr& req,std::function &&callback,std::string device_id); - void get_relays_all(const HttpRequestPtr& req,std::function &&callback,std::string device_id); - void get_relays_one(const HttpRequestPtr& req,std::function &&callback,std::string device_id,std::string relay_id); - }; - } -} diff --git a/controllers/api_v1_devices.cc b/controllers/api_v1_devices.cc new file mode 100644 index 0000000..3d5948e --- /dev/null +++ b/controllers/api_v1_devices.cc @@ -0,0 +1,4 @@ +#include +#include "api_v1_devices.h" +using namespace api::v1; + diff --git a/controllers/api_v1_devices.h b/controllers/api_v1_devices.h new file mode 100644 index 0000000..9737152 --- /dev/null +++ b/controllers/api_v1_devices.h @@ -0,0 +1,26 @@ +#pragma once +#include +using namespace drogon; +namespace api +{ + namespace v1 + { + class devices:public drogon::HttpController + { + public: + METHOD_LIST_BEGIN + METHOD_ADD(devices::post_discover, "/discover", Post); + //METHOD_ADD(Devices::get_all,"/",Get); + //METHOD_ADD(Devices::get_one,"/{1}",Get); + //METHOD_ADD(Devices::get_relays_all,"/{1}/relays",Get); + //METHOD_ADD(Devices::get_relays_one,"/{1}/relays/{2}",Get); + METHOD_LIST_END + + void post_discover(const HttpRequestPtr& req,std::function &&callback); + //void get_all(const HttpRequestPtr& req,std::function &&callback); + //void get_one(const HttpRequestPtr& req,std::function &&callback,std::string device_id); + //void get_relays_all(const HttpRequestPtr& req,std::function &&callback,std::string device_id); + //void get_relays_one(const HttpRequestPtr& req,std::function &&callback,std::string device_id,std::string relay_id); + }; + } +} diff --git a/controllers/api_v1_devices_discover.cc b/controllers/api_v1_devices_discover.cc new file mode 100644 index 0000000..c3a2297 --- /dev/null +++ b/controllers/api_v1_devices_discover.cc @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include "api_v1_devices.h" +using namespace api::v1; + +void devices::post_discover(const HttpRequestPtr &req, std::function &&callback) +{ + LOG_DEBUG << "Discovering"; + auto resp = HttpResponse::newHttpResponse(); + + int discovery_server_socket = helpers::bind_tcp_server("0.0.0.0", "0", config::discover_max_client_backlog); + int discover_server_port = helpers::get_server_port(discovery_server_socket); + + if(discover_server_port == -1) + { + resp->setStatusCode(k500InternalServerError); + callback(resp); + return; + } + + Json::Value payload; + payload["port"] = discover_server_port; + + Json::StreamWriterBuilder wbuilder; + + helpers::send_udp_broadcast("255.255.255.255", config::discover_port_dev, Json::writeString(wbuilder, payload).c_str()); + + close(discovery_server_socket); + + callback(resp); +} + diff --git a/globals.cc b/globals.cc index 439442e..773f4c3 100644 --- a/globals.cc +++ b/globals.cc @@ -1,7 +1,3 @@ -// -// Created by tobias on 11/07/19. -// - #include #include "globals.h" diff --git a/globals.h b/globals.h index 4c4069d..299a1a6 100644 --- a/globals.h +++ b/globals.h @@ -1,7 +1,3 @@ -// -// Created by tobias on 11/07/19. -// - #ifndef EMGAUWA_CORE_GLOBALS_H #define EMGAUWA_CORE_GLOBALS_H diff --git a/helpers.h b/helpers.h new file mode 100644 index 0000000..016efc1 --- /dev/null +++ b/helpers.h @@ -0,0 +1,16 @@ +#ifndef EMGAUWA_CORE_HELPERS_H +#define EMGAUWA_CORE_HELPERS_H + +namespace helpers +{ + int + bind_tcp_server(const char *addr, const char *port, int max_client_backlog); + + int + get_server_port(int fd); + + int + send_udp_broadcast(const char *addr, int port, const char* message); +} + +#endif //EMGAUWA_CORE_HELPERS_H diff --git a/helpers/bind_tcp_server.cc b/helpers/bind_tcp_server.cc new file mode 100644 index 0000000..e3b3913 --- /dev/null +++ b/helpers/bind_tcp_server.cc @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "config.h" + +int +helpers::bind_tcp_server(const char *addr, const char *port, int max_client_backlog) +{ + struct addrinfo hints, *res; + int fd; + int status; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + if ((status = getaddrinfo(addr, port, &hints, &res)) != 0) + { + LOG_ERROR << "Error getting address info: " << gai_strerror(status); + } + + fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + + if ((status = bind(fd, res->ai_addr, res->ai_addrlen)) == -1) + { + LOG_ERROR << "Error binding socket. " << status; + freeaddrinfo(res); + return -1; + } + + if ((status = listen(fd, max_client_backlog)) == -1) + { + LOG_ERROR << "Error setting up listener. " << status; + freeaddrinfo(res); + return -1; + } + + freeaddrinfo(res); + + return fd; +} diff --git a/helpers/get_server_port.cc b/helpers/get_server_port.cc new file mode 100644 index 0000000..1008968 --- /dev/null +++ b/helpers/get_server_port.cc @@ -0,0 +1,18 @@ +#include +#include + +int +helpers::get_server_port(int fd) +{ + if(fd == -1) + { + return -1; + } + struct sockaddr_in sin; + socklen_t addrlen = sizeof(sin); + if(getsockname(fd, (struct sockaddr *)&sin, &addrlen) == 0) + { + return sin.sin_port; + } + return -1; +} \ No newline at end of file diff --git a/helpers/send_udp_broadcast.cc b/helpers/send_udp_broadcast.cc new file mode 100644 index 0000000..f2fd12b --- /dev/null +++ b/helpers/send_udp_broadcast.cc @@ -0,0 +1,40 @@ +#include +#include +#include +#include "config.h" +#include +#include + +int +helpers::send_udp_broadcast(const char *addr, int port, const char* message) +{ + struct sockaddr_in their_addr; + int fd; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + { + LOG_ERROR << "Error creating socket"; + return -1; + } + + int broadcast = 1; + if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast) < 0) + { + LOG_ERROR << "Error setting broadcast"; + return -1; + } + + memset(&their_addr, 0, sizeof(their_addr)); + their_addr.sin_family = AF_INET; + their_addr.sin_port = htons(port); + their_addr.sin_addr.s_addr = inet_addr(addr); + + if(sendto(fd, message, strlen(message), 0, (struct sockaddr *)&their_addr, sizeof(their_addr)) < 0) + { + LOG_ERROR << "Error sending broadcast " << errno << " " << strerror(errno); + return -1; + } + close(fd); + + return 0; +} diff --git a/main.cc b/main.cc index 1e5f766..78e2dca 100644 --- a/main.cc +++ b/main.cc @@ -15,8 +15,6 @@ int main() { if( rc ) { fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(globals::db)); return 1; - } else { - fprintf(stderr, "Opened database successfully\n"); } device_dbo test; @@ -25,7 +23,7 @@ int main() { strcpy(test.ip, "192.168.1.68"); test.active = true; - test.save(); + //test.save(); //Load config file diff --git a/models/device_dbo.cc b/models/device_dbo.cc index b809af7..7268760 100644 --- a/models/device_dbo.cc +++ b/models/device_dbo.cc @@ -11,8 +11,8 @@ bool device_dbo::save() int rc; sqlite3_stmt *stmt; - //sqlite3_prepare_v2(db, "INSERT INTO devices(id, name, ip, active) values (?1, ?2, ?3, ?4);", -1, &stmt, nullptr); - sqlite3_prepare_v2(globals::db, "UPDATE devices set name = ?2, ip = ?3, active = ?4 WHERE id = ?1;", -1, &stmt, nullptr); + sqlite3_prepare_v2(globals::db, "INSERT INTO devices(id, name, ip, active) values (?1, ?2, ?3, ?4);", -1, &stmt, nullptr); + //sqlite3_prepare_v2(globals::db, "UPDATE devices set name = ?2, ip = ?3, active = ?4 WHERE id = ?1;", -1, &stmt, nullptr); sqlite3_bind_text(stmt, 1, this->id, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, this->name, -1, SQLITE_STATIC);