Aggie Student Toolkit — Load Balancer CSCE 412 Project 4
Arnav Fotedar · Fall 2026 · C++ load balancer simulation
Loading...
Searching...
No Matches
Config.cpp
Go to the documentation of this file.
1
6
7#include "Config.h"
8
9#include <istream>
10#include <ostream>
11#include <random>
12#include <sstream>
13#include <type_traits>
14
15#include "Firewall.h"
16
17namespace {
18
20template <typename T>
21bool parseNumber(const std::string& text, T& value) {
22 if (text.empty() || (std::is_unsigned<T>::value && text[0] == '-')) {
23 return false;
24 }
25 std::istringstream stream(text);
26 T parsed{};
27 stream >> parsed;
28 if (!stream || !stream.eof()) {
29 return false;
30 }
31 value = parsed;
32 return true;
33}
34
36template <typename T>
37void ask(std::istream& in, std::ostream& out, const std::string& question, T& value) {
38 while (true) {
39 out << question << " [" << value << "]: " << std::flush;
40 std::string line;
41 if (!std::getline(in, line) || line.empty()) {
42 return;
43 }
44 if (parseNumber(line, value)) {
45 return;
46 }
47 out << " Please enter a number.\n";
48 }
49}
50
51void askYesNo(std::istream& in, std::ostream& out, const std::string& question, bool& value) {
52 out << question << " [" << (value ? "y" : "n") << "]: " << std::flush;
53 std::string line;
54 if (std::getline(in, line) && !line.empty()) {
55 value = line[0] == 'y' || line[0] == 'Y';
56 }
57}
58
59} // namespace
60
61void printUsage(std::ostream& out, const std::string& program) {
62 out << "Usage: " << program << " [options]\n"
63 << "Run with no options to be asked for the main settings.\n\n"
64 << "Run settings\n"
65 << " --servers N initial web servers (default 20)\n"
66 << " --cycles N clock cycles to simulate (default 100000)\n"
67 << " --seed N|random random seed (default 412)\n"
68 << " --verbose print every event in color\n"
69 << " --quiet print only status lines and the summary (default)\n"
70 << " --status-every N cycles between status lines (default: cycles/20, 100 if verbose)\n"
71 << " --log FILE write the summary (and events in verbose mode) to FILE\n"
72 << " --switch bonus: route P and S jobs to two load balancers\n"
73 << " --interactive ask for the main settings, then apply the options given\n"
74 << " --no-color disable ANSI colors\n\n"
75 << "Traffic\n"
76 << " --min-task N shortest task time in cycles (default 10)\n"
77 << " --max-task N longest task time in cycles (default 100)\n"
78 << " --arrival-rate X average new requests per cycle (default 0.45)\n"
79 << " --wave-amplitude X traffic wave size 0-1; rate swings by +/- X (default 0.6)\n"
80 << " --wave-period N cycles per busy/quiet traffic wave, 0 = steady (default cycles/4)\n"
81 << " --streaming-share X fraction of streaming jobs, 0-1 (default 0.35)\n"
82 << " --queue-per-server N initial queue = servers x N (default 100)\n\n"
83 << "Scaling and protection\n"
84 << " --upper X add a server when queue > X x servers (default 80)\n"
85 << " --lower X remove a server when queue < X x servers (default 50)\n"
86 << " --cooldown N cycles between scaling checks (default 10)\n"
87 << " --min-servers N fewest active servers (default 1)\n"
88 << " --max-servers N most live servers (default 100)\n"
89 << " --max-queue N queue capacity, extra requests are discarded (default 0 = unlimited)\n"
90 << " --block CIDR block a source range (repeatable), e.g. 203.0.113.0/24\n"
91 << " --no-default-blocks clear the default blocked ranges 45.0.0.0/8 and 103.0.0.0/8\n"
92 << " --help show this message\n";
93}
94
95bool parseArguments(int argc, char* argv[], Config& config, std::string& error) {
96 bool keepDefaultBlocks = true;
97 bool sawSetting = false; // any option other than display flags such as --no-color
98 std::vector<std::string> extraBlocks;
99 for (int i = 1; i < argc; ++i) {
100 const std::string option = argv[i];
101 const auto needValue = [&](std::string& value) {
102 if (i + 1 >= argc) {
103 error = option + " needs a value";
104 return false;
105 }
106 value = argv[++i];
107 return true;
108 };
109 const auto number = [&](auto& target) {
110 std::string value;
111 if (!needValue(value)) {
112 return false;
113 }
114 if (!parseNumber(value, target)) {
115 error = "invalid value for " + option + ": " + value;
116 return false;
117 }
118 return true;
119 };
120
121 if (option != "--no-color") {
122 sawSetting = true;
123 }
124 if (option == "--help" || option == "-h") {
125 config.showHelp = true;
126 } else if (option == "--servers") {
127 if (!number(config.servers)) return false;
128 } else if (option == "--cycles") {
129 if (!number(config.cycles)) return false;
130 } else if (option == "--seed") {
131 std::string value;
132 if (!needValue(value)) return false;
133 if (value == "random") {
134 config.seed = std::random_device{}();
135 } else if (!parseNumber(value, config.seed)) {
136 error = "invalid value for --seed: " + value;
137 return false;
138 }
139 } else if (option == "--verbose" || option == "-v") {
140 config.verbose = true;
141 } else if (option == "--quiet" || option == "-q") {
142 config.verbose = false;
143 } else if (option == "--status-every") {
144 if (!number(config.statusEvery)) return false;
145 } else if (option == "--log") {
146 if (!needValue(config.logPath)) return false;
147 } else if (option == "--switch") {
148 config.useSwitch = true;
149 } else if (option == "--interactive" || option == "-i") {
150 config.interactive = true;
151 } else if (option == "--no-color") {
152 config.color = false;
153 } else if (option == "--min-task") {
154 if (!number(config.minTask)) return false;
155 } else if (option == "--max-task") {
156 if (!number(config.maxTask)) return false;
157 } else if (option == "--arrival-rate") {
158 if (!number(config.arrivalRate)) return false;
159 } else if (option == "--wave-amplitude") {
160 if (!number(config.waveAmplitude)) return false;
161 } else if (option == "--wave-period") {
162 if (!number(config.wavePeriod)) return false;
163 config.autoWavePeriod = false;
164 } else if (option == "--streaming-share") {
165 if (!number(config.streamingShare)) return false;
166 } else if (option == "--queue-per-server") {
167 if (!number(config.queuePerServer)) return false;
168 } else if (option == "--upper") {
169 if (!number(config.upperFactor)) return false;
170 } else if (option == "--lower") {
171 if (!number(config.lowerFactor)) return false;
172 } else if (option == "--cooldown") {
173 if (!number(config.cooldown)) return false;
174 } else if (option == "--min-servers") {
175 if (!number(config.minServers)) return false;
176 } else if (option == "--max-servers") {
177 if (!number(config.maxServers)) return false;
178 } else if (option == "--max-queue") {
179 if (!number(config.maxQueue)) return false;
180 } else if (option == "--block") {
181 std::string range;
182 if (!needValue(range)) return false;
183 extraBlocks.push_back(range);
184 } else if (option == "--no-default-blocks") {
185 keepDefaultBlocks = false;
186 } else {
187 error = "unknown option: " + option + " (use --help)";
188 return false;
189 }
190 }
191 if (!sawSetting) {
192 config.interactive = true;
193 }
194 if (!keepDefaultBlocks) {
195 config.blockedRanges.clear();
196 }
197 config.blockedRanges.insert(config.blockedRanges.end(), extraBlocks.begin(), extraBlocks.end());
198 return true;
199}
200
201void promptForSettings(Config& config, std::istream& in, std::ostream& out) {
202 out << "Load balancer setup (press Enter to keep the value in brackets)\n";
203 ask(in, out, " Number of initial web servers", config.servers);
204 ask(in, out, " Clock cycles to run", config.cycles);
205 ask(in, out, " Shortest task time (cycles)", config.minTask);
206 ask(in, out, " Longest task time (cycles)", config.maxTask);
207 ask(in, out, " Average new requests per cycle", config.arrivalRate);
208 ask(in, out, " Random seed", config.seed);
209 askYesNo(in, out, " Verbose output (y/n)", config.verbose);
210 askYesNo(in, out, " Use the bonus switch for P/S jobs (y/n)", config.useSwitch);
211 out << '\n';
212}
213
214bool validateConfig(const Config& config, std::string& error) {
215 if (config.servers == 0) {
216 error = "the number of servers must be at least 1";
217 } else if (config.useSwitch && config.servers < 2) {
218 error = "switch mode needs at least 2 servers (one per load balancer)";
219 } else if (config.cycles == 0) {
220 error = "the number of clock cycles must be at least 1";
221 } else if (config.minTask == 0 || config.maxTask < config.minTask) {
222 error = "task times need 1 <= min-task <= max-task";
223 } else if (config.arrivalRate < 0.0 || config.arrivalRate > 1000.0) {
224 error = "arrival rate must be between 0 and 1000 requests per cycle";
225 } else if (config.waveAmplitude < 0.0 || config.waveAmplitude > 1.0) {
226 error = "wave amplitude must be between 0 and 1";
227 } else if (config.streamingShare < 0.0 || config.streamingShare > 1.0) {
228 error = "streaming share must be between 0 and 1";
229 } else if (config.lowerFactor < 0.0 || config.upperFactor <= config.lowerFactor) {
230 error = "scaling thresholds need 0 <= lower < upper";
231 } else if (config.cooldown == 0) {
232 error = "cooldown must be at least 1 cycle";
233 } else if (config.minServers == 0 || config.maxServers < config.minServers) {
234 error = "server limits need 1 <= min-servers <= max-servers";
235 } else if (config.servers > config.maxServers) {
236 error = "initial servers cannot exceed max-servers";
237 } else {
238 Firewall firewall;
239 for (const std::string& range : config.blockedRanges) {
240 if (!firewall.addRange(range)) {
241 error = "invalid blocked range: " + range;
242 return false;
243 }
244 }
245 return true;
246 }
247 return false;
248}
void promptForSettings(Config &config, std::istream &in, std::ostream &out)
Asks the user for the main settings, keeping the current value when the answer is blank.
Definition Config.cpp:201
bool validateConfig(const Config &config, std::string &error)
Checks that the settings are consistent.
Definition Config.cpp:214
void printUsage(std::ostream &out, const std::string &program)
Prints the list of command-line options.
Definition Config.cpp:61
bool parseArguments(int argc, char *argv[], Config &config, std::string &error)
Reads command-line options into a Config.
Definition Config.cpp:95
Declares the Config structure and the command-line and interactive input functions.
Declares the Firewall class, an IPv4 range blocker used before requests are queued.
Rejects requests whose source address falls in a blocked IPv4 range.
Definition Firewall.h:22
bool addRange(const std::string &cidr)
Adds a blocked range.
Definition Firewall.cpp:44
Every user-adjustable setting for one simulation run.
Definition Config.h:21
unsigned int queuePerServer
Initial queue size = servers x queuePerServer.
Definition Config.h:31
double arrivalRate
Average new requests per cycle.
Definition Config.h:26
std::string logPath
File for the run summary (and events in verbose mode).
Definition Config.h:46
double lowerFactor
Scale down when queue < lowerFactor x servers.
Definition Config.h:33
unsigned int servers
Initial number of web servers.
Definition Config.h:22
bool useSwitch
Bonus: route P and S jobs to two load balancers.
Definition Config.h:42
unsigned long cycles
Clock cycles to simulate.
Definition Config.h:23
unsigned int maxTask
Longest task time, in cycles.
Definition Config.h:25
bool verbose
Print every event instead of only status lines.
Definition Config.h:40
double waveAmplitude
Traffic wave size, 0 (steady) to 1.
Definition Config.h:27
double streamingShare
Fraction of requests that are streaming ('S') jobs.
Definition Config.h:30
std::uint32_t seed
Random seed (logged so a run can be repeated).
Definition Config.h:38
unsigned int cooldown
Cycles between scaling checks.
Definition Config.h:34
unsigned long statusEvery
Cycles between status lines; 0 chooses automatically.
Definition Config.h:45
std::size_t maxQueue
Queue capacity; 0 means unlimited.
Definition Config.h:37
unsigned int minServers
Lower bound on active servers.
Definition Config.h:35
bool color
Use ANSI colors on a terminal.
Definition Config.h:41
unsigned long wavePeriod
Cycles per traffic wave; 0 disables the wave.
Definition Config.h:28
unsigned int minTask
Shortest task time, in cycles.
Definition Config.h:24
bool showHelp
Print usage and exit.
Definition Config.h:44
double upperFactor
Scale up when queue > upperFactor x servers.
Definition Config.h:32
std::vector< std::string > blockedRanges
Firewall CIDR ranges.
Definition Config.h:39
bool interactive
Ask for the main settings on standard input.
Definition Config.h:43
bool autoWavePeriod
Use cycles / 4 (four busy/quiet waves) unless –wave-period is given.
Definition Config.h:29
unsigned int maxServers
Upper bound on live servers.
Definition Config.h:36