diff --git a/.gitea/.workflows/build-and-deploy.yaml b/.gitea/.workflows/build-and-deploy.yaml new file mode 100644 index 0000000..1dac8fa --- /dev/null +++ b/.gitea/.workflows/build-and-deploy.yaml @@ -0,0 +1,2 @@ + +# placeholder diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 5d7b908..f4e1ef0 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -2,6 +2,7 @@ add_executable(accordion-client src/main.cpp # other client source files go here + src/TcpClient.cpp ) message(STATUS ${ROOT_DIR}) diff --git a/client/config/main.cfg b/client/config/main.cfg index 1cc0b78..e4c5dd0 100644 --- a/client/config/main.cfg +++ b/client/config/main.cfg @@ -19,3 +19,12 @@ Logger = ( FileName = "app.log"; } ); + +TcpClient = ( + { + Id = "main"; + + Hostname = "127.0.0.1"; + Port = 39500; + } +); diff --git a/client/src/TcpClient.cpp b/client/src/TcpClient.cpp new file mode 100644 index 0000000..d2b267b --- /dev/null +++ b/client/src/TcpClient.cpp @@ -0,0 +1,83 @@ + +#include "TcpClient.hpp" + +TcpClient::TcpClient(ConfigService* config, LoggerService* logger) : config_(config), logger_(logger) { + + if(!(config->getConfig("TcpClient", "main", &configuration_))) { + logger_->log("TcpClient", LogFlag::Error, "Failed to get configuration"); + return; + } + + if(init() == ErrorCode::Success) { + logger_->log("TcpClient", LogFlag::Info, "TcpClient initialized."); + } else { + logger_->log("TcpClient", LogFlag::Error, "TcpClient failed to initialize."); + } + +} + +TcpClient::~TcpClient() { + // close port +} + +ErrorCode TcpClient::init() { + logger_->log("TcpClient", LogFlag::Debug, "Initializing TcpClient..."); + + // keeping everything in here for now + int socketFd; + int sendBytes; + int receiveBytes; + char buffer[1024]; + + struct hostent* host; + struct sockaddr_in serverAddress; + struct timeval timestamp; + struct timeval timestampEnd; + + host = gethostbyname(configuration_.hostname.c_str()); + if(host == NULL) { + logger_->log("TcpClient", LogFlag::Debug, "Unable to parse hostname."); + return ErrorCode::Error; + } + + socketFd = socket(AF_INET, SOCK_STREAM, 0); + if(socketFd < 0) { + logger_->log("TcpClient", LogFlag::Debug, "Unable to open client socket."); + return ErrorCode::Error; + } + + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(configuration_.port); + serverAddress.sin_addr = *((struct in_addr*)host->h_addr); + memset(&serverAddress.sin_zero, 0, sizeof(serverAddress.sin_zero)); + + if(connect(socketFd, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr)) < 0) { + logger_->log("TcpClient", LogFlag::Debug, "Unable to connect to server."); + return ErrorCode::Error; + } + + memset(buffer, 0x67, sizeof(buffer)); + gettimeofday(×tamp, NULL); + + sendBytes = send(socketFd, buffer, sizeof(buffer), 0); + if(sendBytes < 0) { + logger_->log("TcpClient", LogFlag::Debug, "Unable to send to server."); + return ErrorCode::Error; + } + + gettimeofday(×tampEnd, NULL); + + memset(buffer, 0x00, sizeof(buffer)); + receiveBytes = recv(socketFd, buffer, sizeof(buffer), 0); + if(receiveBytes < 0) { + logger_->log("TcpClient", LogFlag::Debug, "Unable to receive from server."); + return ErrorCode::Error; + } + + std::string msg = "Received " + std::to_string(receiveBytes) + " bytes back from server."; + logger_->log("TcpClient", LogFlag::Debug, msg); + + close(socketFd); + + return ErrorCode::Success; +} diff --git a/client/src/TcpClient.hpp b/client/src/TcpClient.hpp new file mode 100644 index 0000000..780307d --- /dev/null +++ b/client/src/TcpClient.hpp @@ -0,0 +1,31 @@ + +#pragma once + +#include +#include +#include +#include +#include +#include // TODO replace with chrono + +#include "common/config/ConfigService.hpp" +#include "common/LoggerService.hpp" +#include "common/ErrorCodes.hpp" +#include "config/ClientConfig.hpp" + +class TcpClient { + +public: + + TcpClient(ConfigService* config, LoggerService* logger); + ~TcpClient(); + +private: + + ErrorCode init(); + + LoggerService* logger_; + ConfigService* config_; + ClientParams configuration_; + +}; diff --git a/client/src/config/ClientConfig.hpp b/client/src/config/ClientConfig.hpp new file mode 100644 index 0000000..0d191ee --- /dev/null +++ b/client/src/config/ClientConfig.hpp @@ -0,0 +1,31 @@ + +#pragma once + +#include "common/config/IConfig.hpp" + +struct ClientParams { + std::string id; + + std::string hostname; + uint32_t port; +}; + +class ClientConfig : public IConfig { + +public: + + using IConfig::IConfig; + + bool parseConfig(const libconfig::Setting& setting) override { + + if (!setting.lookupValue("Id", params_->id)) { + return false; + } + + setting.lookupValue("Hostname", params_->hostname); + setting.lookupValue("Port", params_->port); + + return true; + } + +}; diff --git a/client/src/main.cpp b/client/src/main.cpp index 4a52f21..ffddb53 100644 --- a/client/src/main.cpp +++ b/client/src/main.cpp @@ -2,14 +2,24 @@ #include #include "common/config/ConfigService.hpp" -#include "common/config/LoggerConfig.hpp" #include "common/LoggerService.hpp" +#include "TcpClient.hpp" + int main(int argc, char* argv[]) { - ConfigService config {"client/config/main.cfg"}; // TODO: main config file should be the foremost cli argument + std::string centralConfigPath = "client/config/main.cfg"; // default path + if(argc > 1) { + centralConfigPath = std::string(argv[1]); + } + + ConfigService config { centralConfigPath }; LoggerService logger {&config, "main"}; logger.log("main", LogFlag::Debug, "hello world from the client!"); + TcpClient client {&config, &logger}; + + return 0; + } diff --git a/common/ErrorCodes.hpp b/common/ErrorCodes.hpp new file mode 100644 index 0000000..4824fa0 --- /dev/null +++ b/common/ErrorCodes.hpp @@ -0,0 +1,10 @@ + +#pragma once + +enum class ErrorCode : int { + + Success = 0, + Error = -1, + // ... + +}; diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 019810d..4631bfb 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -2,6 +2,7 @@ add_executable(accordion-server src/main.cpp # other server source files go here + src/TcpServer.cpp ) target_include_directories(accordion-server PRIVATE diff --git a/lib/.gitkeep b/server/Dockerfile similarity index 100% rename from lib/.gitkeep rename to server/Dockerfile diff --git a/server/config/main.cfg b/server/config/main.cfg index 0ddef13..7833c19 100644 --- a/server/config/main.cfg +++ b/server/config/main.cfg @@ -19,3 +19,11 @@ Logger = ( FileName = "app.log"; } ); + +TcpServer = ( + { + Id = "main"; + + Port = 39500; + } +); diff --git a/server/docker-compose.yaml b/server/docker-compose.yaml new file mode 100644 index 0000000..e69de29 diff --git a/server/src/TcpServer.cpp b/server/src/TcpServer.cpp new file mode 100644 index 0000000..fd39bef --- /dev/null +++ b/server/src/TcpServer.cpp @@ -0,0 +1,95 @@ + +#include "TcpServer.hpp" + +TcpServer::TcpServer(ConfigService* config, LoggerService* logger) : config_(config), logger_(logger) { + + if(!(config->getConfig("TcpServer", "main", &configuration_))) { + logger_->log("TcpServer", LogFlag::Error, "Failed to get configuration"); + return; + } + + if(init() == ErrorCode::Success) { + logger_->log("TcpServer", LogFlag::Info, "TcpServer initialized."); + } else { + logger_->log("TcpServer", LogFlag::Error, "TcpServer failed to initialize."); + } + +} + +TcpServer::~TcpServer() { + // close port +} + +ErrorCode TcpServer::init() { + logger_->log("TcpServer", LogFlag::Debug, "Initializing TcpServer..."); + + // keeping everything in here for now + int socketFd; + int clientFd; + char buffer[1024]; + int receiveBytes; + int sendBytes; + + struct sockaddr_in serverAddress; + struct sockaddr_in clientAddress; + + socketFd = socket(AF_INET, SOCK_STREAM, 0); + if(socketFd < 0) { + logger_->log("TcpServer", LogFlag::Error, "Unable to open Server socket."); + return ErrorCode::Error; + } + + int on = 1; + setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(configuration_.port); + serverAddress.sin_addr.s_addr = INADDR_ANY; + memset(&serverAddress.sin_zero, 0, sizeof(serverAddress.sin_zero)); + + if(bind(socketFd, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr)) < 0) { + logger_->log("TcpServer", LogFlag::Error, "Unable to bind server socket."); + return ErrorCode::Error; + } + + memset(buffer, 0x0, sizeof(buffer)); + listen(socketFd, 10); + logger_->log("TcpServer", LogFlag::Debug, "Server listening..."); + + unsigned int sinSize = sizeof(struct sockaddr); + clientFd = accept(socketFd, (struct sockaddr*)&clientAddress, &sinSize); + if(clientFd < 0) { + logger_->log("TcpServer", LogFlag::Error, "Unable to accept client socket."); + return ErrorCode::Error; + } + + struct sockaddr_in peerAddress; + unsigned int len = sizeof(peerAddress); + char serverIp[20]; + std::string msg = "Accept socket... Client address: " + std::string(inet_ntoa(clientAddress.sin_addr)) + " Port: " + std::to_string(ntohs(clientAddress.sin_port)); + logger_->log("TcpServer", LogFlag::Debug, msg); + getsockname(clientFd, (struct sockaddr*)&peerAddress, &len); + inet_ntop(AF_INET, &peerAddress, serverIp, sizeof(serverIp)); + msg = "Accept socket... Server address: " + std::string(serverIp); + logger_->log("TcpServer", LogFlag::Debug, msg); + + receiveBytes = recv(clientFd, buffer, sizeof(buffer), 0); + if(receiveBytes < 0) { + logger_->log("TcpServer", LogFlag::Error, "Unable to receive from client."); + return ErrorCode::Error; + } + msg = "Received " + std::to_string(receiveBytes) + " bytes from client: " + std::to_string(buffer[2]); + logger_->log("TcpClient", LogFlag::Debug, msg); + + // echo back + sendBytes = send(clientFd, buffer, sizeof(buffer), 0); + if(sendBytes < 0) { + logger_->log("TcpServer", LogFlag::Error, "Unable to send to client."); + return ErrorCode::Error; + } + msg = "Echoed " + std::to_string(sendBytes) + " bytes back to client."; + + close(socketFd); + + return ErrorCode::Success; +} diff --git a/server/src/TcpServer.hpp b/server/src/TcpServer.hpp new file mode 100644 index 0000000..db28d32 --- /dev/null +++ b/server/src/TcpServer.hpp @@ -0,0 +1,32 @@ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include // TODO replace with chrono + +#include "common/config/ConfigService.hpp" +#include "common/LoggerService.hpp" +#include "common/ErrorCodes.hpp" +#include "config/ServerConfig.hpp" + +class TcpServer { + +public: + + TcpServer(ConfigService* config, LoggerService* logger); + ~TcpServer(); + +private: + + ErrorCode init(); + + LoggerService* logger_; + ConfigService* config_; + ServerParams configuration_; + +}; diff --git a/server/src/config/ServerConfig.hpp b/server/src/config/ServerConfig.hpp new file mode 100644 index 0000000..d8d227b --- /dev/null +++ b/server/src/config/ServerConfig.hpp @@ -0,0 +1,29 @@ + +#pragma once + +#include "common/config/IConfig.hpp" + +struct ServerParams { + std::string id; + + uint32_t port; +}; + +class ServerConfig : public IConfig { + +public: + + using IConfig::IConfig; + + bool parseConfig(const libconfig::Setting& setting) override { + + if (!setting.lookupValue("Id", params_->id)) { + return false; + } + + setting.lookupValue("Port", params_->port); + + return true; + } + +}; diff --git a/server/src/main.cpp b/server/src/main.cpp index db0a94b..913265b 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -2,14 +2,24 @@ #include #include "common/config/ConfigService.hpp" -#include "common/config/LoggerConfig.hpp" #include "common/LoggerService.hpp" +#include "TcpServer.hpp" + int main(int argc, char* argv[]) { - ConfigService config {"server/config/main.cfg"}; // TODO: main config file should be the foremost cli argument + std::string centralConfigPath = "server/config/main.cfg"; // default path + if(argc > 1) { + centralConfigPath = std::string(argv[1]); + } + + ConfigService config { centralConfigPath }; LoggerService logger {&config, "main"}; - logger.log("main", LogFlag::Debug, "hello world from the server!"); + logger.log("main", LogFlag::Debug, "hello world from the Server!"); + + TcpServer server {&config, &logger}; + + return 0; }