109 lines
2.7 KiB
C++
109 lines
2.7 KiB
C++
#include "Network/Server/Server.h"
|
|
#include <arpa/inet.h>
|
|
#include <unistd.h>
|
|
#include <cstring>
|
|
#include <iostream>
|
|
#include "Metrics/Host.h"
|
|
|
|
namespace Network
|
|
{
|
|
|
|
Server::Server(uint16_t port, Model::HostRegistry ®istry)
|
|
: port_(port), registry_(registry), running_(false)
|
|
{
|
|
|
|
sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (sockfd_ < 0)
|
|
throw std::runtime_error("Failed to create UDP socket");
|
|
|
|
sockaddr_in addr{};
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
addr.sin_port = htons(port_);
|
|
|
|
if (bind(sockfd_, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) < 0)
|
|
{
|
|
throw std::runtime_error("Failed to bind UDP socket");
|
|
}
|
|
}
|
|
|
|
Server::~Server()
|
|
{
|
|
stop();
|
|
close(sockfd_);
|
|
}
|
|
|
|
void Server::start()
|
|
{
|
|
running_ = true;
|
|
serverThread_ = std::thread(&Server::run, this);
|
|
}
|
|
|
|
void Server::stop()
|
|
{
|
|
running_ = false;
|
|
if (serverThread_.joinable())
|
|
serverThread_.join();
|
|
}
|
|
|
|
void Server::run()
|
|
{
|
|
constexpr size_t BUF_SIZE = 4096;
|
|
uint8_t buffer[BUF_SIZE];
|
|
|
|
while (running_)
|
|
{
|
|
fd_set readfds;
|
|
FD_ZERO(&readfds);
|
|
FD_SET(sockfd_, &readfds);
|
|
|
|
timeval tv{};
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 500 * 1000; // 500 ms
|
|
|
|
int ret = select(sockfd_ + 1, &readfds, nullptr, nullptr, &tv);
|
|
|
|
if (ret < 0)
|
|
{
|
|
if (errno == EINTR)
|
|
continue;
|
|
perror("select");
|
|
break;
|
|
}
|
|
|
|
if (ret == 0)
|
|
{
|
|
// timeout — просто проверяем running_
|
|
continue;
|
|
}
|
|
|
|
if (FD_ISSET(sockfd_, &readfds))
|
|
{
|
|
sockaddr_in clientAddr{};
|
|
socklen_t addrLen = sizeof(clientAddr);
|
|
ssize_t len = recvfrom(
|
|
sockfd_,
|
|
buffer,
|
|
BUF_SIZE,
|
|
0,
|
|
reinterpret_cast<sockaddr *>(&clientAddr),
|
|
&addrLen);
|
|
|
|
if (len <= 0)
|
|
continue;
|
|
|
|
try
|
|
{
|
|
std::vector<uint8_t> data(buffer, buffer + len);
|
|
auto metrics = Metrics::Host::deserialize(data);
|
|
registry_.update(metrics.hostname, metrics);
|
|
}
|
|
catch (const std::exception &e)
|
|
{
|
|
std::cerr << "UDP parse error: " << e.what() << std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace Network
|