-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbackend_server.cpp
More file actions
157 lines (130 loc) · 4.72 KB
/
backend_server.cpp
File metadata and controls
157 lines (130 loc) · 4.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Author: Suchismita Bose (psychomita)
// Year: 2025
// License: MIT
// This file is part of the HTTP Load Balancer project.
// You may use, modify, and distribute this file under the terms of the MIT License.
#include "backend_server.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <cstring>
#include <iostream>
BackendServer::BackendServer(const std::string& ip, int port, int weight, int max_connections)
: ip_(ip), port_(port), active_connections_(0), healthy_(true),
max_connections_(max_connections), weight_(weight) {
last_health_check_ = std::chrono::steady_clock::now();
}
BackendServer::BackendServer(BackendServer&& other) noexcept
: ip_(std::move(other.ip_)), port_(other.port_),
active_connections_(other.active_connections_.load()),
healthy_(other.healthy_.load()),
last_health_check_(other.last_health_check_),
max_connections_(other.max_connections_),
weight_(other.weight_) {
}
BackendServer& BackendServer::operator=(BackendServer&& other) noexcept {
if (this != &other) {
ip_ = std::move(other.ip_);
port_ = other.port_;
active_connections_.store(other.active_connections_.load());
healthy_.store(other.healthy_.load());
last_health_check_ = other.last_health_check_;
max_connections_ = other.max_connections_;
weight_ = other.weight_;
}
return *this;
}
int BackendServer::connect_to_server() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
std::cerr << "[ERROR] Failed to create socket for " << to_string() << std::endl;
return -1;
}
// Set connection timeout
struct timeval timeout;
timeout.tv_sec = 5; // 5 second timeout
timeout.tv_usec = 0;
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0 ||
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
std::cerr << "[WARNING] Failed to set socket timeout for " << to_string() << std::endl;
}
struct sockaddr_in backend_addr;
memset(&backend_addr, 0, sizeof(backend_addr));
backend_addr.sin_family = AF_INET;
backend_addr.sin_port = htons(port_);
if (inet_pton(AF_INET, ip_.c_str(), &backend_addr.sin_addr) <= 0) {
std::cerr << "[ERROR] Invalid IP address: " << ip_ << std::endl;
close(sock);
return -1;
}
if (connect(sock, (struct sockaddr*)&backend_addr, sizeof(backend_addr)) < 0) {
std::cerr << "[ERROR] Failed to connect to " << to_string() << ": " << strerror(errno) << std::endl;
close(sock);
set_health_status(false);
return -1;
}
set_health_status(true);
return sock;
}
void BackendServer::increment_connections() {
active_connections_++;
}
void BackendServer::decrement_connections() {
int current = active_connections_.load();
if (current > 0) {
active_connections_--;
}
}
bool BackendServer::is_healthy() const {
return healthy_.load();
}
void BackendServer::set_health_status(bool healthy) {
bool was_healthy = healthy_.exchange(healthy);
if (was_healthy != healthy) {
std::cout << "[HEALTH] Server " << to_string()
<< " status changed to " << (healthy ? "HEALTHY" : "UNHEALTHY") << std::endl;
}
}
void BackendServer::update_last_health_check() {
last_health_check_ = std::chrono::steady_clock::now();
}
const std::string& BackendServer::get_ip() const {
return ip_;
}
int BackendServer::get_port() const {
return port_;
}
int BackendServer::get_active_connections() const {
return active_connections_.load();
}
int BackendServer::get_max_connections() const {
return max_connections_;
}
int BackendServer::get_weight() const {
return weight_;
}
std::string BackendServer::to_string() const {
return ip_ + ":" + std::to_string(port_);
}
double BackendServer::get_load_score() const {
if (!is_healthy()) {
return std::numeric_limits<double>::max();
}
// Weighted least connections: connections / weight
// Lower score means less loaded
return static_cast<double>(get_active_connections()) / static_cast<double>(weight_);
}
bool BackendServer::can_accept_connection() const {
return is_healthy() && (get_active_connections() < max_connections_);
}
bool BackendServer::needs_health_check(int interval_seconds) const {
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - last_health_check_);
return elapsed.count() >= interval_seconds;
}
std::chrono::steady_clock::time_point BackendServer::get_last_health_check() const {
return last_health_check_;
}