/
isachkov
/
crypto_server
Обзор
Документация
Войти
/
isachkov
/
crypto_server
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/server.cpp
126 строк
3 KB
Ivan Sachkov
CryptoServer
15 май 2024, 20:26
15 май 2024, 20:26
9de0f1f
Код
Авторство
О чём код?
#include <crypto_chat/server.hpp> #include <unistd.h> #include <iostream> Server::Server(Executor& executor, SSLProvider& provider) : exec_{executor}, ssl_provider_{provider} {} Server::~Server() { if(acceptor_ > 0) { close(acceptor_); } } bool Server::bind_and_listen() { if(!location_) { return false; } auto accept_socket = socket(location_->ai_family, location_->ai_socktype, location_->ai_protocol); if (accept_socket == -1) { return false; } acceptor_ = accept_socket; const auto bind_status = bind(accept_socket, location_->ai_addr, location_->ai_addrlen); if(bind_status == -1) { return false; } const auto listen_status = listen(accept_socket, listen_backlog_size_); if(listen_status == -1) { return false; } return true; } void Server::set_location(std::string address, std::string port) { address_ = std::move(address); port_ = std::move(port); } int Server::run() { // 1. Resolve our location auto location = resolve(address_.c_str(), port_.c_str()); if(!location) { std::cerr << "Could not resolve location\n"; return EXIT_FAILURE; } location_ = std::move(location); // 2. Bind the socket and listen on it const auto bind_status = bind_and_listen(); if(!bind_status) { std::cerr << "Could not bind and listen on the socket\n"; return EXIT_FAILURE; } // 3. Set listener as an io target in executor const auto is_listener_set = exec_.on_listen(acceptor_, [this](){ accept_incoming_client(); }); if(!is_listener_set) { return EXIT_FAILURE; } // 4. If we disconnect -> we simply drop a session exec_.on_disconnect([this](auto descriptor) { sessions_.erase(descriptor); }); exec_.run(); return EXIT_SUCCESS; } void Server::accept_incoming_client() { // 1. Accept the client auto client_socket = accept(acceptor_, location_->ai_addr, &location_->ai_addrlen); if(client_socket == -1) { std::cerr << "Could not accept incoming connection!\n"; return; } // 2. Make it a session auto session = std::make_unique<ClientSession>(client_socket, ssl_provider_); // 3. If the client broadcasts (e.g. this session received a message) -> send it to everybody, // except that client. Smarter solutions are wellcome for production systems. session->on_broadcast([this, client_socket](auto message_view){ for(auto& [socket_fd, session] : sessions_) { if(socket_fd == client_socket) { continue; } session->write(message_view); } }); // 4. Also add the socket as an epoll interest target const auto is_reader_set = exec_.on_read(client_socket, [this, id = client_socket](auto data){ auto iter = sessions_.find(id); if(iter == sessions_.end()) { return; } iter->second->receive(std::move(data)); }); if(!is_reader_set) { std::cerr << "Could not set epoll reader for incoming connection\n"; return; } // 5. Init the secure layer on the client session, should be performed before first client's write auto is_initialized = session->init(); if (!is_initialized) { std::cerr << "Could not init secure layer for the client session\n"; return; } // 6. Store the session, keep in mind that it's removed on disconnect sessions_.emplace(client_socket, std::move(session)); }