From dfb96a785373a7e730eb55b414042d9576ba7b5e Mon Sep 17 00:00:00 2001 From: study-faraphel Date: Fri, 3 Jan 2025 11:21:27 +0100 Subject: [PATCH] separated managers functions and improved error messages --- CMakeLists.txt | 8 +- source/Context.cpp | 17 ++- source/Context.hpp | 7 +- source/Manager.cpp | 210 ----------------------------- source/Manager.hpp | 35 ----- source/main.cpp | 10 +- source/managers/Manager.cpp | 112 +++++++++++++++ source/managers/Manager.hpp | 32 +++++ source/managers/ReceiveManager.cpp | 101 ++++++++++++++ source/managers/ReceiveManager.hpp | 29 ++++ source/managers/SendManager.cpp | 52 +++++++ source/managers/SendManager.hpp | 30 +++++ source/test.cpp | 31 ++++- 13 files changed, 413 insertions(+), 261 deletions(-) delete mode 100644 source/Manager.cpp delete mode 100644 source/Manager.hpp create mode 100644 source/managers/Manager.cpp create mode 100644 source/managers/Manager.hpp create mode 100644 source/managers/ReceiveManager.cpp create mode 100644 source/managers/ReceiveManager.hpp create mode 100644 source/managers/SendManager.cpp create mode 100644 source/managers/SendManager.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cce616..3837d74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,8 +11,8 @@ add_executable(M2-PT-DRP source/packets/audio/AudioPacketData.hpp source/utils/audio/audio.cpp source/utils/audio/audio.hpp - source/Manager.cpp - source/Manager.hpp + source/managers/Manager.cpp + source/managers/Manager.hpp source/packets/base/Packet.hpp source/behavior/events/types.hpp source/packets/base/Packet.cpp @@ -66,6 +66,10 @@ add_executable(M2-PT-DRP source/packets/audio/AudioPacketData.cpp source/packets/info/InfoPacketData.cpp source/packets/search/SearchPacketData.cpp + source/managers/SendManager.cpp + source/managers/ReceiveManager.cpp + source/managers/ReceiveManager.hpp + source/managers/SendManager.hpp ) target_include_directories(M2-PT-DRP PRIVATE source diff --git a/source/Context.cpp b/source/Context.cpp index d365f1f..6b9ea93 100644 --- a/source/Context.cpp +++ b/source/Context.cpp @@ -3,15 +3,20 @@ #include "utils/crypto/rsa/RsaKeyPair.hpp" -Context::Context() { +Context::Context(const int socket, addrinfo* broadcastAddressInfo) { const auto keyPair = drp::util::crypto::RsaKeyPair(2048); - this->me = Peer(keyPair.getPublicKey()); - this->cryptoRsaPrivateKey = keyPair.getPrivateKey(); - - this->socket = -1; - this->broadcastAddressInfo = nullptr; + // communication + this->socket = socket; + this->broadcastAddressInfo = broadcastAddressInfo; this->server = nullptr; + // ourselves + this->me = Peer(keyPair.getPublicKey()); + + // others this->latestPeerDiscovery = std::chrono::high_resolution_clock::now(); + + // crytography + this->cryptoRsaPrivateKey = keyPair.getPrivateKey(); } diff --git a/source/Context.hpp b/source/Context.hpp index f900649..d1ed2db 100644 --- a/source/Context.hpp +++ b/source/Context.hpp @@ -16,16 +16,21 @@ */ class Context { public: - explicit Context(); + explicit Context(int socket, addrinfo* broadcastAddressInfo); + // communication int socket; /// current socket file descriptor, used to communicate addrinfo* broadcastAddressInfo; /// address used to broadcast messages std::shared_ptr server; /// peer currently used as the server + // ourselves Peer me; /// information about our own machine + + // others std::list> remotePeers {}; /// information about other machines std::chrono::high_resolution_clock::time_point latestPeerDiscovery; /// time of the latest discovered machine + // cryptography drp::util::crypto::RsaPrivateKey cryptoRsaPrivateKey {}; /// the RSA private key drp::util::crypto::AesKey256 cryptoAesKey = {}; /// the AES secret key }; diff --git a/source/Manager.cpp b/source/Manager.cpp deleted file mode 100644 index 1a69589..0000000 --- a/source/Manager.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#include "Manager.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "behavior/events/types.hpp" -#include "behavior/events/audio/AudioEvent.hpp" -#include "behavior/events/info/InfoEvent.hpp" -#include "behavior/events/pong/PongEvent.hpp" -#include "behavior/events/search/SearchEvent.hpp" -#include "packets/base/Packet.hpp" -#include "behavior/tasks/client/ClientTask.hpp" -#include "behavior/tasks/server/ServerTask.hpp" -#include "behavior/tasks/undefined/UndefinedTask.hpp" -#include "utils/crypto/aes/AesKey.hpp" -#include "utils/crypto/rsa/RsaKeyPair.hpp" - - -Manager::Manager(const std::string& address, const std::string& port, const bool useIpv6) { - std::cout << "Broadcast address: " << address << ":" << port << " (" << (useIpv6 ? "IPv6" : "IPv4") << ")" << std::endl; - - this->context = std::make_shared(); - - // register the different events type - this->eventRegistry = { - {drp::event::EventType::PONG, std::make_shared()}, - {drp::event::EventType::SEARCH, std::make_shared()}, - {drp::event::EventType::INFO, std::make_shared()}, - {drp::event::EventType::AUDIO, std::make_shared()}, - }; - - // register the different tasks type - this->taskRegistry = { - {drp::task::TaskType::UNDEFINED, std::make_shared()}, - {drp::task::TaskType::CLIENT, std::make_shared()}, - {drp::task::TaskType::SERVER, std::make_shared()}, - }; - - // hints for the communication - addrinfo broadcastAddressHints {}; - broadcastAddressHints.ai_family = useIpv6 ? AF_INET6 : AF_INET; - broadcastAddressHints.ai_socktype = SOCK_DGRAM; - broadcastAddressHints.ai_protocol = IPPROTO_UDP; - - // create the client socket - this->context->socket = socket( - broadcastAddressHints.ai_family, - broadcastAddressHints.ai_socktype, - broadcastAddressHints.ai_protocol - ); - - if (this->context->socket < 0) - throw std::runtime_error("Could not create the socket: " + std::string(strerror(errno))); - - // allow IPv6 multicast loopback so that we can receive our own messages. - constexpr int socketLoopback = 1; - if (setsockopt( - context->socket, - IPPROTO_IPV6, - IPV6_MULTICAST_LOOP, - &socketLoopback, - sizeof(socketLoopback) - ) < 0) { - std::cerr << "Failed to set IPV6_MULTICAST_LOOP: " << strerror(errno) << std::endl; - } - - // get the information for the broadcast local-link address - if(const int error = getaddrinfo( - address.c_str(), - port.c_str(), - &broadcastAddressHints, - &context->broadcastAddressInfo - ) != 0) - throw std::runtime_error("Could not get the broadcast address: " + std::string(gai_strerror(error))); - - // hints for the bind address - addrinfo anyAddressHints {}; - anyAddressHints.ai_family = useIpv6 ? AF_INET6 : AF_INET; - anyAddressHints.ai_flags = AI_PASSIVE; - anyAddressHints.ai_socktype = SOCK_DGRAM; - anyAddressHints.ai_protocol = IPPROTO_UDP; - - // get the information for the broadcast local-link address - addrinfo *anyAddressInfo; - if(const int error = getaddrinfo( - nullptr, - port.c_str(), - &anyAddressHints, - &anyAddressInfo - ) != 0) - throw std::runtime_error("Could not get the any address: " + std::string(gai_strerror(error))); - - // bind the socket to the address - if (bind( - this->context->socket, - anyAddressInfo->ai_addr, - anyAddressInfo->ai_addrlen - ) < 0) - throw std::runtime_error("Could not bind to the address: " + std::string(strerror(errno))); - - // TODO(Faraphel): should only be enabled in specific case. - this->context->me.serverEnabled = true; -} - - -void Manager::loop() { - // run an event receiver and sender - this->senderThread = std::thread(&Manager::loopSender, this); - this->receiverThread = std::thread(&Manager::loopReceiver, this); - - this->senderThread.join(); - this->receiverThread.join(); - - freeaddrinfo(this->context->broadcastAddressInfo); -} - - -void Manager::loopSender() const { - while (true) { - std::cout << "[Sender] Handling status: " + std::to_string(static_cast(this->context->me.status)) << std::endl; - - // get the corresponding task class - std::shared_ptr task; - try { - task = this->taskRegistry.at(this->context->me.status); - } catch (const std::out_of_range& exception) { - std::cerr << "[Sender] Unsupported status." << std::endl; - continue; - } - - // ask the task class to handle the task - task->handle(*this->context); - } -} - - -void Manager::loopReceiver() const { - // prepare space for the sender address - sockaddr_storage fromAddress {}; - socklen_t fromAddressLength = sizeof(fromAddress); - - std::array buffer {}; - - // client loop - while (true) { - // receive new data - const ssize_t size = recvfrom( - this->context->socket, - buffer.data(), - buffer.size(), - 0, - reinterpret_cast(&fromAddress), - &fromAddressLength - ); - if (size == -1) - throw std::runtime_error("[Receiver] Could not receive the packet: " + std::string(strerror(errno))); - - // deserialize the packet - std::vector data(buffer.begin(), buffer.end()); - const auto packet = drp::packet::base::Packet::deserialize(data); - - // if the packet channel is neither 0 (all) nor the current one, ignore it - if (packet.channel != 0 && packet.channel != this->context->me.channel) - continue; - - // decrypt the packet - // TODO(Faraphel): handle exception ? - drp::packet::base::PacketContent packetContent = packet.getContent(*this->context); - - // look for a saved peer with the same address - auto remotePeer = std::ranges::find_if( - this->context->remotePeers, - [&](const std::shared_ptr& remotePeer) { return - remotePeer->addressLength == fromAddressLength and - std::memcmp(&fromAddress, &remotePeer->address, fromAddressLength) == 0; - } - ); - // if found, update the latest connection date - if (remotePeer != this->context->remotePeers.end()) { - (*remotePeer)->latestConnection = std::chrono::high_resolution_clock::now(); - } - - // get the corresponding event class - std::shared_ptr event; - try { - event = this->eventRegistry.at(packetContent.eventType); - } catch (const std::out_of_range& exception) { - std::cerr << "[Receiver] Unsupported event type." << std::endl; - continue; - } - - std::cout << "[Receiver] handling event: " << static_cast(packetContent.eventType) << std::endl; - - // ask the event class to handle the event - event->handle( - *this->context, - packetContent.data, - fromAddress, - fromAddressLength - ); - } -} diff --git a/source/Manager.hpp b/source/Manager.hpp deleted file mode 100644 index 4a6edac..0000000 --- a/source/Manager.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "Context.hpp" -#include "behavior/events/types.hpp" -#include "behavior/events/base/BaseEvent.hpp" -#include "behavior/tasks/types.hpp" -#include "behavior/tasks/base/BaseTask.hpp" - - -/** - * The Manager. - * Manage how should the program behave depending on its current state, or the message it receive. - */ -// TODO(Faraphel): could be split in two part. -class Manager { -public: - Manager(const std::string& address, const std::string& port, bool useIpv6 = false); - - void loop(); - void loopSender() const; - void loopReceiver() const; - -private: - std::thread senderThread; /// the thread sending communication - std::thread receiverThread; /// the thread receiving communication - - std::map> eventRegistry; /// hold the event to call depending on the event type - std::map> taskRegistry; /// hold the task to call depending on the server status - - std::shared_ptr context; /// context used between the events types -}; diff --git a/source/main.cpp b/source/main.cpp index 03f6542..4df621b 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -2,10 +2,10 @@ #include #include #include "argparse/argparse.hpp" -#include "Manager.hpp" +#include "managers/Manager.hpp" -int main(int argc, char* argv[]) { +int main(const int argc, char* argv[]) { // initialize the mpg123 library if (mpg123_init() != MPG123_OK) throw std::runtime_error("Error while initializing mpg123."); @@ -26,14 +26,14 @@ int main(int argc, char* argv[]) { return EXIT_FAILURE; } - auto eventManager = Manager( + auto manager = drp::managers::Manager( parser.get("--host"), parser.get("--port"), parser.get("-6") ); - eventManager.loop(); + manager.loop(); - // terminate the libraries + // close the libraries Pa_Terminate(); mpg123_exit(); diff --git a/source/managers/Manager.cpp b/source/managers/Manager.cpp new file mode 100644 index 0000000..5db4bd0 --- /dev/null +++ b/source/managers/Manager.cpp @@ -0,0 +1,112 @@ +#include "Manager.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "behavior/events/audio/AudioEvent.hpp" +#include "behavior/tasks/server/ServerTask.hpp" +#include "utils/crypto/aes/AesKey.hpp" +#include "utils/crypto/rsa/RsaKeyPair.hpp" + + +namespace drp::managers { + + +Manager::Manager(const std::string& address, const std::string& port, const bool useIpv6) { + std::cout << "Broadcast address: " << address << ":" << port << " (" << (useIpv6 ? "IPv6" : "IPv4") << ")" << std::endl; + + // hints for the communication + addrinfo broadcastAddressHints {}; + broadcastAddressHints.ai_family = useIpv6 ? AF_INET6 : AF_INET; + broadcastAddressHints.ai_socktype = SOCK_DGRAM; + broadcastAddressHints.ai_protocol = IPPROTO_UDP; + + // create the client socket + const int sock = socket( + broadcastAddressHints.ai_family, + broadcastAddressHints.ai_socktype, + broadcastAddressHints.ai_protocol + ); + if (sock < 0) + throw std::runtime_error("Could not create the socket: " + std::string(strerror(errno))); + + // allow IPv6 multicast loopback so that we can receive our own messages. + constexpr int socketLoopback = 1; + if (setsockopt( + sock, + IPPROTO_IPV6, + IPV6_MULTICAST_LOOP, + &socketLoopback, + sizeof(socketLoopback) + ) < 0) { + std::cerr << "Failed to set IPV6_MULTICAST_LOOP: " << strerror(errno) << std::endl; + } + + // get the information for the broadcast local-link address + addrinfo* broadcastAddressInfo = nullptr; + if (const int error = getaddrinfo( + address.c_str(), + port.c_str(), + &broadcastAddressHints, + &broadcastAddressInfo + ) != 0) + throw std::runtime_error("Could not get the broadcast address: " + std::string(gai_strerror(error))); + + // hints for the bind address + addrinfo anyAddressHints {}; + anyAddressHints.ai_family = useIpv6 ? AF_INET6 : AF_INET; + anyAddressHints.ai_flags = AI_PASSIVE; + anyAddressHints.ai_socktype = SOCK_DGRAM; + anyAddressHints.ai_protocol = IPPROTO_UDP; + + // get the information for the broadcast local-link address + addrinfo *anyAddressInfo; + if (const int error = getaddrinfo( + nullptr, + port.c_str(), + &anyAddressHints, + &anyAddressInfo + ) != 0) + throw std::runtime_error("Could not get the any address: " + std::string(gai_strerror(error))); + + // bind the socket to the address + if (bind( + sock, + anyAddressInfo->ai_addr, + anyAddressInfo->ai_addrlen + ) < 0) + throw std::runtime_error("Could not bind to the address: " + std::string(strerror(errno))); + + // create the context + this->context = std::make_shared(sock, broadcastAddressInfo); + // TODO(Faraphel): should only be enabled if it can really emit sound. + this->context->me.serverEnabled = true; + + // create the sub-managers. + this->sendManager = std::make_unique(context); + this->receiveManager = std::make_unique(context); +} + +Manager::~Manager() { + freeaddrinfo(this->context->broadcastAddressInfo); +} + + +void Manager::loop() { + // run an event receiver and sender + std::thread senderThread(&SendManager::loop, this->sendManager.get()); + std::thread receiverThread(&ReceiveManager::loop, this->receiveManager.get()); + + senderThread.join(); + receiverThread.join(); +} + + +} \ No newline at end of file diff --git a/source/managers/Manager.hpp b/source/managers/Manager.hpp new file mode 100644 index 0000000..08c5ed4 --- /dev/null +++ b/source/managers/Manager.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "Context.hpp" +#include "managers/ReceiveManager.hpp" +#include "managers/SendManager.hpp" + + +namespace drp::managers { + + +/** + * The Manager. + * serve as the mainloop of the program. + */ +class Manager { +public: + Manager(const std::string& address, const std::string& port, bool useIpv6 = false); + ~Manager(); + + void loop(); + +private: + std::shared_ptr context; /// context used between the events types + + std::unique_ptr sendManager; + std::unique_ptr receiveManager; +}; + + +} \ No newline at end of file diff --git a/source/managers/ReceiveManager.cpp b/source/managers/ReceiveManager.cpp new file mode 100644 index 0000000..ed81f9e --- /dev/null +++ b/source/managers/ReceiveManager.cpp @@ -0,0 +1,101 @@ +#include "ReceiveManager.hpp" + +#include +#include + +#include "behavior/events/audio/AudioEvent.hpp" +#include "behavior/events/info/InfoEvent.hpp" +#include "behavior/events/pong/PongEvent.hpp" +#include "behavior/events/search/SearchEvent.hpp" + + +namespace drp::managers { + + +ReceiveManager::ReceiveManager(const std::shared_ptr& context) { + this->context = context; + + // register the different events type + this->registry = { + {event::EventType::PONG, std::make_shared()}, + {event::EventType::SEARCH, std::make_shared()}, + {event::EventType::INFO, std::make_shared()}, + {event::EventType::AUDIO, std::make_shared()}, + }; +} + + +void ReceiveManager::run() const { + // prepare space for the sender address + sockaddr_storage fromAddress {}; + socklen_t fromAddressLength = sizeof(fromAddress); + + std::array buffer {}; + + // receive new data + const ssize_t size = recvfrom( + this->context->socket, + buffer.data(), + buffer.size(), + 0, + reinterpret_cast(&fromAddress), + &fromAddressLength + ); + if (size == -1) + throw std::runtime_error("[Receiver] Could not receive the packet: " + std::string(strerror(errno))); + + // deserialize the packet + std::vector data(buffer.begin(), buffer.end()); + const auto packet = drp::packet::base::Packet::deserialize(data); + + // if the packet channel is neither 0 (all) nor the current one, ignore it + if (packet.channel != 0 && packet.channel != this->context->me.channel) + return; + + // decrypt the packet + // TODO(Faraphel): handle exception ? + drp::packet::base::PacketContent packetContent = packet.getContent(*this->context); + + // look for a saved peer with the same address + auto remotePeer = std::ranges::find_if( + this->context->remotePeers, + [&](const std::shared_ptr& remotePeer) { return + remotePeer->addressLength == fromAddressLength and + std::memcmp(&fromAddress, &remotePeer->address, fromAddressLength) == 0; + } + ); + // if found, update the latest connection date + if (remotePeer != this->context->remotePeers.end()) + (*remotePeer)->latestConnection = std::chrono::high_resolution_clock::now(); + + // get the corresponding event class + std::shared_ptr event; + try { + event = this->registry.at(packetContent.eventType); + } catch (const std::out_of_range& exception) { + std::cerr << "[Receiver] Unsupported event type: " << std::to_string(static_cast(packetContent.eventType)) << std::endl; + return; + } + + std::cout << "[Receiver] handling event: " << std::to_string(static_cast(packetContent.eventType)) << std::endl; + + // ask the event class to handle the event + try { + event->handle( + *this->context, + packetContent.data, + fromAddress, + fromAddressLength + ); + } catch (const std::exception& exception) { + std::cerr << "[Receiver] Unhandled exception: " << exception.what() << std::endl; + } +} + +void ReceiveManager::loop() const { + while (true) + this->run(); +} + + +} diff --git a/source/managers/ReceiveManager.hpp b/source/managers/ReceiveManager.hpp new file mode 100644 index 0000000..68308c4 --- /dev/null +++ b/source/managers/ReceiveManager.hpp @@ -0,0 +1,29 @@ +#pragma once +#include +#include + +#include "behavior/events/types.hpp" +#include "behavior/events/base/BaseEvent.hpp" + + +namespace drp::managers { + + +/** + * The ReceiveManager class. + * Handle everything related to receiving messages. + */ +class ReceiveManager { +public: + explicit ReceiveManager(const std::shared_ptr& context); + + void run() const; + [[noreturn]] void loop() const; + +private: + std::shared_ptr context; + std::map> registry; +}; + + +} diff --git a/source/managers/SendManager.cpp b/source/managers/SendManager.cpp new file mode 100644 index 0000000..d3356b5 --- /dev/null +++ b/source/managers/SendManager.cpp @@ -0,0 +1,52 @@ +#include "SendManager.hpp" + +#include + +#include "behavior/tasks/client/ClientTask.hpp" +#include "behavior/tasks/server/ServerTask.hpp" +#include "behavior/tasks/undefined/UndefinedTask.hpp" + + +namespace drp::managers { + + +SendManager::SendManager(const std::shared_ptr& context) { + this->context = context; + + // register the different tasks type + this->registry = { + {task::TaskType::UNDEFINED, std::make_shared()}, + {task::TaskType::CLIENT, std::make_shared()}, + {task::TaskType::SERVER, std::make_shared()}, + }; +} + + +void SendManager::run() const { + std::cout << "[Sender] Handling status: " + std::to_string(static_cast(this->context->me.status)) << std::endl; + + // get the corresponding task class + std::shared_ptr task; + try { + task = this->registry.at(this->context->me.status); + } catch (const std::out_of_range& exception) { + std::cerr << "[Sender] Unsupported status: " << std::to_string(static_cast(this->context->me.status)) << std::endl; + return; + } + + // ask the task class to handle the task + try { + task->handle(*this->context); + } catch (const std::exception& exception) { + std::cerr << "[Sender] Unhandled exception: " << exception.what() << std::endl; + } +} + + +void SendManager::loop() const { + while (true) + this->run(); +} + + +} diff --git a/source/managers/SendManager.hpp b/source/managers/SendManager.hpp new file mode 100644 index 0000000..5ef3e5c --- /dev/null +++ b/source/managers/SendManager.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include + +#include "behavior/tasks/types.hpp" +#include "behavior/tasks/base/BaseTask.hpp" + + +namespace drp::managers { + +/** + * The SendManager class. + * Handle everything related to sending messages. + */ +class SendManager { +public: + explicit SendManager(const std::shared_ptr& context); + + void run() const; + [[noreturn]] void loop() const; + +private: + std::shared_ptr context; + std::map> registry; +}; + + +} \ No newline at end of file diff --git a/source/test.cpp b/source/test.cpp index 212fcf0..55c16a8 100644 --- a/source/test.cpp +++ b/source/test.cpp @@ -95,7 +95,15 @@ int mainSerialize() { int mainRsaSerialize() { + // create a key pair + drp::util::crypto::RsaKeyPair keyPair(2048); + + // create an object Peer peer; + peer.channel = 7; + peer.id = 253; + + // serialize it auto serializedPeer = peer.serialize(); std::cout << "serialized: "; @@ -103,7 +111,26 @@ int mainRsaSerialize() { std::cout << std::to_string(byte) << "-"; std::cout << std::endl; - const auto deserializedPeer = Peer::deserialize(serializedPeer); + // encrypt it + const std::vector encryptedSerializedPeer = keyPair.getPublicKey().encrypt(serializedPeer); + + std::cout << "encrypted: "; + for (const auto& byte : encryptedSerializedPeer) + std::cout << std::to_string(byte) << "-"; + std::cout << std::endl; + + // decrypt it + std::vector decryptedSerializedPeer = keyPair.getPrivateKey().decrypt(encryptedSerializedPeer); + + std::cout << "decrypted: "; + for (const auto& byte : decryptedSerializedPeer) + std::cout << std::to_string(byte) << "-"; + std::cout << std::endl; + + const auto deserializedPeer = Peer::deserialize(decryptedSerializedPeer); + + std::cout << "peer id: " << std::to_string(deserializedPeer.id) << std::endl; + std::cout << "peer channel: " << std::to_string(deserializedPeer.channel) << std::endl; return 0; } @@ -113,7 +140,7 @@ int main_test() { // mainAes(); // mainRsa(); // mainSerialize(); - // mainRsaSerialize(); + mainRsaSerialize(); return 0; } \ No newline at end of file