diff options
| author | alpine <[email protected]> | 2020-06-04 16:13:19 +0200 |
|---|---|---|
| committer | alpine <[email protected]> | 2020-06-04 16:13:19 +0200 |
| commit | 28f66dee8a9fe49aadb5c1d67de48d9232363963 (patch) | |
| tree | 00f6bfd0c2120d005c833301830d167b0753feb3 | |
| download | loader-28f66dee8a9fe49aadb5c1d67de48d9232363963.tar.xz loader-28f66dee8a9fe49aadb5c1d67de48d9232363963.zip | |
Initial commit
| -rw-r--r-- | .gitignore | 42 | ||||
| -rw-r--r-- | .gitmodules | 6 | ||||
| -rw-r--r-- | CMakeLists.txt | 31 | ||||
| -rw-r--r-- | client/CMakeLists.txt | 14 | ||||
| -rw-r--r-- | client/src/client/client.cpp | 35 | ||||
| -rw-r--r-- | client/src/client/client.h | 47 | ||||
| -rw-r--r-- | client/src/client/packet.h | 45 | ||||
| -rw-r--r-- | client/src/include.h | 63 | ||||
| -rw-r--r-- | client/src/main.cpp | 29 | ||||
| -rw-r--r-- | client/src/util/events.h | 24 | ||||
| -rw-r--r-- | client/src/util/io.cpp | 12 | ||||
| -rw-r--r-- | client/src/util/io.h | 7 | ||||
| -rw-r--r-- | server/CMakeLists.txt | 15 | ||||
| -rw-r--r-- | server/src/include.h | 41 | ||||
| -rw-r--r-- | server/src/main.cpp | 14 | ||||
| -rw-r--r-- | server/src/server/packet.h | 10 | ||||
| -rw-r--r-- | server/src/server/server.cpp | 52 | ||||
| -rw-r--r-- | server/src/server/server.h | 12 | ||||
| -rw-r--r-- | server/src/server/ssl.h | 1 | ||||
| -rw-r--r-- | server/src/util/commands.h | 21 | ||||
| -rw-r--r-- | server/src/util/events.h | 24 | ||||
| -rw-r--r-- | server/src/util/io.cpp | 41 | ||||
| -rw-r--r-- | server/src/util/io.h | 8 | ||||
| m--------- | shared/cpr | 0 | ||||
| m--------- | shared/spdlog | 0 |
25 files changed, 594 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..981986a --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +#Auto generated files +build/* +bin/* + +#Visual studio files +*.tlog + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj +*.ipch +*.suo +*.db + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app
\ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8b0d96f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "shared/spdlog"] + path = shared/spdlog + url = https://github.com/gabime/spdlog.git +[submodule "shared/cpr"] + path = shared/cpr + url = https://github.com/whoshuu/cpr.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..facc157 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.14) + +project(server-client) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +set(CMAKE_CXX_STANDARD 17) +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") + +set(USE_SYSTEM_CURL ON CACHE BOOL "" FORCE) +set(BUILD_CPR_TESTS OFF CACHE BOOL "" FORCE) +set(SPDLOG_BUILD_TESTING OFF CACHE BOOL "" FORCE) + +find_package(OpenSSL REQUIRED) + +set(OPENSSL_USE_STATIC_LIBS TRUE) + +add_subdirectory(shared/spdlog) +add_subdirectory(shared/cpr) +add_subdirectory(server) +add_subdirectory(client) + +target_include_directories(server PRIVATE ${PROJECT_SOURCE_DIR}/shared ${OPENSSL_INCLUDE_DIR} ${CPR_INCLUDE_DIRS}) +target_link_libraries(server PRIVATE spdlog ${OPENSSL_LIBRARIES} ${CPR_LIBRARIES}) + +target_include_directories(client PRIVATE ${PROJECT_SOURCE_DIR}/shared) +target_link_libraries(client PRIVATE spdlog) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt new file mode 100644 index 0000000..2eff688 --- /dev/null +++ b/client/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.10) + +project(client) + +set(source_dir "${PROJECT_SOURCE_DIR}/src") + +file(GLOB_RECURSE source_files "${source_dir}/*.cpp") +file(GLOB_RECURSE header_files "${source_dir}/*.h") + +add_executable( + client + ${source_files} + ${header_files} +) diff --git a/client/src/client/client.cpp b/client/src/client/client.cpp new file mode 100644 index 0000000..9fe2e36 --- /dev/null +++ b/client/src/client/client.cpp @@ -0,0 +1,35 @@ +#include "../include.h" +#include "client.h" + +bool tcp::client::start(const std::string_view server_ip, + const uint16_t &port) { +#ifdef WINDOWS + WSADATA data; + int res = WSAStartup(MAKEWORD(2, 2), &data); + if (res != 0) { + io::logger->error("failed to initialize WSA."); + return false; + } +#endif + + m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (m_socket == -1) { + io::logger->error("failed to create socket."); + return false; + } + + sockaddr_in server_addr; + + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = inet_addr(server_ip.data()); + server_addr.sin_port = htons(port); + + int ret = connect(m_socket, reinterpret_cast<sockaddr *>(&server_addr), + sizeof(server_addr)); + if (ret < 0) { + io::logger->error("failed to connect to server."); + return false; + } + + return true; +} diff --git a/client/src/client/client.h b/client/src/client/client.h new file mode 100644 index 0000000..8f14071 --- /dev/null +++ b/client/src/client/client.h @@ -0,0 +1,47 @@ +#pragma once +#include "../util/io.h" +#include "../util/events.h" + +namespace tcp { + +enum client_state : uint8_t { + idle = 0, + active, + standby +}; + +class client { + int m_socket; + std::atomic<uint8_t> m_state; + + event<std::string> receive_event; + + public: + client() : m_socket{-1}, m_state{0} {} + bool start(const std::string_view server_ip, const uint16_t &port); + + bool send_message(const std::string_view msg) { + int ret = send(m_socket, msg.data(), msg.size(), 0); + return ret == msg.size(); + } + + int get_socket() { return m_socket; } + bool is_active() { return m_state == client_state::active; } + void set_state(const uint8_t &state) { m_state = state; } + auto &on_recv() { return receive_event; } + + static void read(client &client) { + std::array<char, 256> buf; + while (client.is_active()) { + int ret = recv(client.get_socket(), &buf[0], buf.size(), 0); + if (ret <= 0) { + io::logger->error("connection lost."); + break; + } + + std::string msg(buf.data(), ret); + client.on_recv().call(msg); + } + } +}; +} // namespace tcp diff --git a/client/src/client/packet.h b/client/src/client/packet.h new file mode 100644 index 0000000..b61c4e2 --- /dev/null +++ b/client/src/client/packet.h @@ -0,0 +1,45 @@ +#pragma once + +namespace tcp { + constexpr size_t uid_len = 10; + struct packet_t { + std::string message; + char action; + std::array<char, uid_len> uid; + + // parse packet from server message after decryption + bool parse(const std::string msg) { + // first 10 bytes is the uid + bool res = set_uid(msg.substr(0, uid_len)); + if(!res) { + return false; + } + + action = msg[uid_len]; + const bool stream = static_cast<bool>(msg[uid_len + 1]); + if(stream) { + const size_t size = std::stoll(msg.substr(uid_len + 2)); + + // receive stream + + return true; + } + + message = msg.substr(uid_len + 2); + return true; + } + bool set_uid(const std::string_view uid_str) { + const size_t uid_str_len = uid_str_len.size(); + if(uid_str_len != uid_len) { + io::logger->error("packet uid len mismatch!"); + return false; + } + + for(size_t i = 0; i < uid_len; ++i) { + uid[i] = uid_str[i]; + } + + return true; + } + }; +}; diff --git a/client/src/include.h b/client/src/include.h new file mode 100644 index 0000000..e2c647b --- /dev/null +++ b/client/src/include.h @@ -0,0 +1,63 @@ +#pragma once + +#if defined(_WIN32) || defined(_WIN64) +#define WINDOWS +#endif + +#ifdef WINDOWS +#define _CRT_SECURE_NO_WARNINGS +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX + +#include <windows.h> +#include <stdio.h> +#include <winsock2.h> +#include <ws2tcpip.h> +#include <iphlpapi.h> + +#pragma comment( lib, "ws2_32.lib" ) +#endif + +#include <stdio.h> +#include <algorithm> +#include <array> +#include <chrono> +#include <cstring> +#include <fstream> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <system_error> +#include <thread> +#include <vector> +#include <unordered_map> +#include <optional> +#include <iomanip> +#include <map> +#include <random> +#include <list> +#include <utility> +#include <atomic> +#include <mutex> +#include <future> +#include <any> + +#ifndef WINDOWS + +#define closesocket(socket) close(socket) + +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> +#endif + +#include <spdlog/fmt/fmt.h> +#include <spdlog/spdlog.h> +#include <spdlog/sinks/basic_file_sink.h> +#include <spdlog/sinks/stdout_color_sinks.h>
\ No newline at end of file diff --git a/client/src/main.cpp b/client/src/main.cpp new file mode 100644 index 0000000..1dc9db2 --- /dev/null +++ b/client/src/main.cpp @@ -0,0 +1,29 @@ +#include "include.h" +#include "util/io.h" +#include "client/client.h" + +int main(int argc, char *argv[]) { + tcp::client client; + if (client.start("127.0.0.1", 6666)) { + io::logger->info("connected."); + client.set_state(tcp::client_state::active); + } + + client.on_recv().add([&](std::string msg) { + io::logger->info(msg); + }); + + std::thread t{tcp::client::read, std::ref(client)}; + + while (client.is_active()) { + std::string p; + getline(std::cin, p); + + bool ret = client.send_message(p); + if (!ret) { + break; + } + } + + t.join(); +} diff --git a/client/src/util/events.h b/client/src/util/events.h new file mode 100644 index 0000000..b8d7781 --- /dev/null +++ b/client/src/util/events.h @@ -0,0 +1,24 @@ +#pragma once + +template <typename... Args> +class event { + using func_type = std::function<void(Args...)>; + + std::mutex event_lock; + std::list<func_type> m_funcs; + + public: + void add(const func_type& func) { + std::lock_guard<std::mutex> lock(event_lock); + + m_funcs.push_back(std::move(func)); + } + + void call(Args... params) { + std::lock_guard<std::mutex> lock(event_lock); + + for (auto& func : m_funcs) { + if (func) func(std::forward<Args>(params)...); + } + } +};
\ No newline at end of file diff --git a/client/src/util/io.cpp b/client/src/util/io.cpp new file mode 100644 index 0000000..06d2b9a --- /dev/null +++ b/client/src/util/io.cpp @@ -0,0 +1,12 @@ +#include "../include.h" +#include "io.h" + +std::shared_ptr<spdlog::logger> io::logger; + +void io::init() { + spdlog::sink_ptr sink = + std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); + sink->set_pattern("%^~>%$ %v"); + + logger = std::make_shared<spdlog::logger>("client", sink); +} diff --git a/client/src/util/io.h b/client/src/util/io.h new file mode 100644 index 0000000..8eae321 --- /dev/null +++ b/client/src/util/io.h @@ -0,0 +1,7 @@ +#pragma once + +namespace io { +extern std::shared_ptr<spdlog::logger> logger; + +void init(); +}; // namespace io diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt new file mode 100644 index 0000000..0461d8b --- /dev/null +++ b/server/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.14) + +project(server) + +set(CMAKE_CXX_STANDARD 17) +set(source_dir "${PROJECT_SOURCE_DIR}/src") + +file(GLOB_RECURSE source_files "${source_dir}/*.cpp") +file(GLOB_RECURSE header_files "${source_dir}/*.h") + +add_executable( + server + ${source_files} + ${header_files} +)
\ No newline at end of file diff --git a/server/src/include.h b/server/src/include.h new file mode 100644 index 0000000..eb31336 --- /dev/null +++ b/server/src/include.h @@ -0,0 +1,41 @@ +#pragma once + +#include <algorithm> +#include <array> +#include <chrono> +#include <cstring> +#include <fstream> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <system_error> +#include <thread> +#include <vector> +#include <unordered_map> +#include <unordered_set> +#include <optional> +#include <map> +#include <random> +#include <list> +#include <utility> +#include <atomic> +#include <mutex> +#include <filesystem> + +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +#include <cpr/cpr.h> + +#include <spdlog/fmt/fmt.h> +#include <spdlog/spdlog.h> +#include <spdlog/sinks/basic_file_sink.h> +#include <spdlog/sinks/stdout_color_sinks.h> + +#include <openssl/ssl.h> diff --git a/server/src/main.cpp b/server/src/main.cpp new file mode 100644 index 0000000..f34c433 --- /dev/null +++ b/server/src/main.cpp @@ -0,0 +1,14 @@ +#include "include.h" +#include "util/io.h" +#include "util/commands.h" +#include "server/server.h" + +int main(int argc, char *argv[]) { + io::init(false); + + tcp::server server; + server.start("6666"); + server.start("8981"); + + std::cin.get(); +} diff --git a/server/src/server/packet.h b/server/src/server/packet.h new file mode 100644 index 0000000..02d90d1 --- /dev/null +++ b/server/src/server/packet.h @@ -0,0 +1,10 @@ +#pragma once + +namespace tcp { + constexpr uint8_t uid_len = 10; + + struct packet_t { + std::string message; + std::array<char, uid_len> uid; + } +} diff --git a/server/src/server/server.cpp b/server/src/server/server.cpp new file mode 100644 index 0000000..2f684e1 --- /dev/null +++ b/server/src/server/server.cpp @@ -0,0 +1,52 @@ +#include "../include.h" +#include "../util/io.h" +#include "server.h" + +bool tcp::server::start(const std::string_view port) { + io::logger->info("starting server on port {}...", port.data()); + + m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (m_socket < 0) { + io::logger->critical("failed to create socket."); + return false; + } + struct addrinfo hints, *addrinfo = nullptr; + + memset(&hints, 0, sizeof hints); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE; + + int ret = getaddrinfo(nullptr, port.data(), &hints, &addrinfo); + if (ret != 0) { + io::logger->critical("failed to get address info."); + close(m_socket); + return false; + } + + ret = bind(m_socket, addrinfo->ai_addr, addrinfo->ai_addrlen); + if (ret < 0) { + io::logger->critical("failed to bind port."); + close(m_socket); + return false; + } + io::logger->info("port bound."); + freeaddrinfo(addrinfo); + + ret = listen(m_socket, SOMAXCONN); + if (ret < 0) { + io::logger->critical("failed to listen on port {}.", port.data()); + close(m_socket); + return false; + } + io::logger->info("listening on {}.", port.data()); + + return true; +} + +void tcp::server::stop() { + io::logger->info("stopping server on port {}.", m_port); + close(m_socket); +}
\ No newline at end of file diff --git a/server/src/server/server.h b/server/src/server/server.h new file mode 100644 index 0000000..f848ae2 --- /dev/null +++ b/server/src/server/server.h @@ -0,0 +1,12 @@ +#pragma once + +namespace tcp { +class server { + int m_socket; + + public: + + bool start(const std::string_view port); + void stop(); +}; +}; // namespace tcp diff --git a/server/src/server/ssl.h b/server/src/server/ssl.h new file mode 100644 index 0000000..7b9637e --- /dev/null +++ b/server/src/server/ssl.h @@ -0,0 +1 @@ +#pragma once
\ No newline at end of file diff --git a/server/src/util/commands.h b/server/src/util/commands.h new file mode 100644 index 0000000..1e5ae0f --- /dev/null +++ b/server/src/util/commands.h @@ -0,0 +1,21 @@ +#pragma once + +class commands { + using func = std::function<void()>; + std::unordered_map<std::string_view, func> m_cmds; + + public: + bool parse_input(const std::string_view str) { + auto it = m_cmds.find(str); + if (it != m_cmds.end()) { + it->second(); + return true; + } + return false; + } + + void add(const std::string_view cmd, const func &cb) { + + m_cmds[cmd] = cb; + } +}; diff --git a/server/src/util/events.h b/server/src/util/events.h new file mode 100644 index 0000000..e6f053d --- /dev/null +++ b/server/src/util/events.h @@ -0,0 +1,24 @@ +#pragma once + +template <typename... Args> +class event { + using func_type = std::function<void(Args...)>; + + std::mutex event_lock; + std::list<func_type> m_funcs; + + public: + void add(const func_type& func) { + std::lock_guard<std::mutex> lock(event_lock); + + m_funcs.emplace_back(std::move(func)); + } + + void call(Args... params) { + std::lock_guard<std::mutex> lock(event_lock); + + for (auto& func : m_funcs) { + if (func) func(std::forward<Args>(params)...); + } + } +}; diff --git a/server/src/util/io.cpp b/server/src/util/io.cpp new file mode 100644 index 0000000..1f9bca6 --- /dev/null +++ b/server/src/util/io.cpp @@ -0,0 +1,41 @@ +#include "../include.h" +#include "io.h" + +std::shared_ptr<spdlog::logger> io::logger; + +void io::init(const bool &trunc) { + auto sink = + std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); + sink->set_pattern("[%R][%^%l%$] %v"); + + auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("server.log", trunc); + + std::vector<spdlog::sink_ptr> log_sinks; + log_sinks.emplace_back(sink); + log_sinks.emplace_back(file_sink); + + logger = std::make_shared<spdlog::logger>("server", log_sinks.begin(), log_sinks.end()); + spdlog::register_logger(logger); + + spdlog::flush_every(std::chrono::seconds(1)); +} + +void io::read_file(const std::string_view name, std::vector<char> &out) { + std::ifstream file(name.data()); + if (!file.good()) { + io::logger->error("failed to load {}.", name.data()); + return; + } + + file.unsetf(std::ios::skipws); + + file.seekg(0, std::ios::end); + const size_t size = file.tellg(); + file.seekg(0, std::ios::beg); + + out.resize(size); + + file.read(out.data(), size); + + file.close(); +} diff --git a/server/src/util/io.h b/server/src/util/io.h new file mode 100644 index 0000000..437b465 --- /dev/null +++ b/server/src/util/io.h @@ -0,0 +1,8 @@ +#pragma once + +namespace io { +extern std::shared_ptr<spdlog::logger> logger; + +void init(const bool &trunc); +void read_file(const std::string_view name, std::vector<char> &out); +}; // namespace io diff --git a/shared/cpr b/shared/cpr new file mode 160000 +Subproject 7e4a803fff0787b8a961527016f1060373a7ce6 diff --git a/shared/spdlog b/shared/spdlog new file mode 160000 +Subproject 22a169bc319ac06948e7ee0be6b9b0ac8138660 |