Ran through clang-format.

This commit is contained in:
Robert J. Hansen
2019-09-02 21:34:54 -04:00
parent fc85da96bf
commit 6c38288246
4 changed files with 398 additions and 423 deletions

View File

@@ -14,151 +14,145 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "main.h"
#include <iostream>
#include <algorithm>
#include <exception>
#include <vector>
#include <sstream>
#include <boost/tokenizer.hpp>
#include <exception>
#include <iostream>
#include <sstream>
#include <vector>
#include "main.h"
using std::string;
using std::transform;
using std::vector;
using std::exception;
using std::binary_search;
using std::pair;
using std::back_inserter;
using std::getline;
using std::stringstream;
using std::to_string;
using boost::asio::ip::tcp;
using boost::char_separator;
using boost::tokenizer;
using boost::asio::ip::tcp;
using std::back_inserter;
using std::binary_search;
using std::exception;
using std::getline;
using std::pair;
using std::string;
using std::stringstream;
using std::to_string;
using std::transform;
using std::vector;
// defined in main.cc
extern const vector<pair64>& hashes;
namespace {
enum class Command {
Version = 0,
Bye = 1,
Status = 2,
Query = 3,
Upshift = 4,
Downshift = 5,
Unknown = 6
Version = 0,
Bye = 1,
Status = 2,
Query = 3,
Upshift = 4,
Downshift = 5,
Unknown = 6
};
auto tokenize(const string& line)
{
vector<string> rv;
char_separator<char> sep(" ");
tokenizer<char_separator<char>> tokens(line, sep);
for (const auto& t : tokens) {
rv.emplace_back(t);
}
return rv;
auto tokenize(const string& line) {
vector<string> rv;
char_separator<char> sep(" ");
tokenizer<char_separator<char>> tokens(line, sep);
for (const auto& t : tokens) {
rv.emplace_back(t);
}
return rv;
}
bool is_present_in_hashes(const string& hash)
{
return binary_search(hashes.cbegin(), hashes.cend(), to_pair64(hash));
bool is_present_in_hashes(const string& hash) {
return binary_search(hashes.cbegin(), hashes.cend(), to_pair64(hash));
}
auto getCommand(const string& cmdstring)
{
string localcmd = "";
transform(cmdstring.cbegin(), cmdstring.cend(), back_inserter(localcmd), ::toupper);
auto getCommand(const string& cmdstring) {
string localcmd = "";
transform(cmdstring.cbegin(), cmdstring.cend(), back_inserter(localcmd),
::toupper);
auto cmd = Command::Unknown;
auto cmd = Command::Unknown;
if (localcmd == "VERSION:")
cmd = Command::Version;
else if (localcmd == "BYE")
cmd = Command::Bye;
else if (localcmd == "STATUS")
cmd = Command::Status;
else if (localcmd == "QUERY")
cmd = Command::Query;
else if (localcmd == "UPSHIFT")
cmd = Command::Upshift;
else if (localcmd == "DOWNSHIFT")
cmd = Command::Downshift;
return cmd;
}
if (localcmd == "VERSION:")
cmd = Command::Version;
else if (localcmd == "BYE")
cmd = Command::Bye;
else if (localcmd == "STATUS")
cmd = Command::Status;
else if (localcmd == "QUERY")
cmd = Command::Query;
else if (localcmd == "UPSHIFT")
cmd = Command::Upshift;
else if (localcmd == "DOWNSHIFT")
cmd = Command::Downshift;
return cmd;
}
} // namespace
void handle_client(tcp::iostream& stream)
{
const string ipaddr = stream.socket().remote_endpoint().address().to_string();
unsigned long long queries = 0;
try {
while (stream) {
string line;
getline(stream, line);
if (line.size() == 0) return;
void handle_client(tcp::iostream& stream) {
const string ipaddr = stream.socket().remote_endpoint().address().to_string();
unsigned long long queries = 0;
try {
while (stream) {
string line;
getline(stream, line);
if (line.size() == 0) return;
// trim leading/following whitespace
auto end_ws = line.find_last_not_of("\t\n\v\f\r ");
if (end_ws != string::npos) {
line.erase(end_ws + 1);
}
auto front_ws = line.find_first_not_of("\t\n\v\f\r ");
if (front_ws > 0) {
line.erase(0, front_ws);
}
// trim leading/following whitespace
auto end_ws = line.find_last_not_of("\t\n\v\f\r ");
if (end_ws != string::npos) {
line.erase(end_ws + 1);
}
auto front_ws = line.find_first_not_of("\t\n\v\f\r ");
if (front_ws > 0) {
line.erase(0, front_ws);
}
auto commands = tokenize(line);
switch (getCommand(commands.at(0))) {
case Command::Version:
stream << "OK\r\n";
break;
auto commands = tokenize(line);
switch (getCommand(commands.at(0))) {
case Command::Version:
stream << "OK\r\n";
break;
case Command::Bye:
return;
case Command::Bye:
return;
case Command::Status:
stream << "NOT SUPPORTED\r\n";
break;
case Command::Status:
stream << "NOT SUPPORTED\r\n";
break;
case Command::Query:
{
stringstream rv;
rv << "OK ";
for (size_t idx = 1 ; idx < commands.size(); ++idx)
rv << (is_present_in_hashes(commands.at(idx)) ? "1" : "0");
rv << "\r\n";
queries += (commands.size() - 1);
stream << rv.str();
break;
}
case Command::Upshift:
stream << "NOT OK\r\n";
break;
case Command::Downshift:
stream << "NOT OK\r\n";
break;
case Command::Unknown:
stream << "NOT OK\r\n";
return;
}
case Command::Query: {
stringstream rv;
rv << "OK ";
for (size_t idx = 1; idx < commands.size(); ++idx)
rv << (is_present_in_hashes(commands.at(idx)) ? "1" : "0");
rv << "\r\n";
queries += (commands.size() - 1);
stream << rv.str();
break;
}
}
catch (std::exception& e) {
log(LogLevel::ALERT, string("Error: ") + e.what());
// swallow the exception: we'll close the connection
// automagically on exit
//
// fall-through here to function returb
}
stringstream status_msg;
status_msg << ipaddr << " closed session after " << queries
<< " queries";
log(LogLevel::ALERT, status_msg.str());
case Command::Upshift:
stream << "NOT OK\r\n";
break;
case Command::Downshift:
stream << "NOT OK\r\n";
break;
case Command::Unknown:
stream << "NOT OK\r\n";
return;
}
}
} catch (std::exception& e) {
log(LogLevel::ALERT, string("Error: ") + e.what());
// swallow the exception: we'll close the connection
// automagically on exit
//
// fall-through here to function returb
}
stringstream status_msg;
status_msg << ipaddr << " closed session after " << queries << " queries";
log(LogLevel::ALERT, status_msg.str());
}

View File

@@ -15,277 +15,272 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "main.h"
#include <algorithm>
#include <boost/program_options.hpp>
#include <boost/asio.hpp>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <errno.h>
#include <exception>
#include <fstream>
#include <iostream>
#include <limits.h>
#include <regex>
#include <signal.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <algorithm>
#include <boost/asio.hpp>
#include <boost/program_options.hpp>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <fstream>
#include <iostream>
#include <regex>
#include <vector>
using std::string;
using std::transform;
using std::ifstream;
using boost::asio::ip::tcp;
using boost::program_options::notify;
using boost::program_options::options_description;
using boost::program_options::parse_command_line;
using boost::program_options::store;
using boost::program_options::value;
using boost::program_options::variables_map;
using std::cerr;
using std::cout;
using std::vector;
using std::sort;
using std::fill;
using std::getline;
using std::ifstream;
using std::pair;
using std::regex;
using std::sort;
using std::stoi;
using std::string;
using std::to_string;
using std::getline;
using std::fill;
using boost::program_options::options_description;
using boost::program_options::variables_map;
using boost::program_options::store;
using boost::program_options::parse_command_line;
using boost::program_options::notify;
using boost::program_options::value;
using boost::asio::ip::tcp;
using std::transform;
using std::vector;
namespace {
vector<pair64> hash_set;
string hashes_location{ PKGDATADIR "/hashes.txt" };
uint16_t port{ 9120 };
bool dry_run{ false };
string hashes_location{PKGDATADIR "/hashes.txt"};
uint16_t port{9120};
bool dry_run{false};
/** Attempts to load a set of MD5 hashes from disk.
* Each line must be either blank or 32 hexadecimal digits. If the
* file doesn't conform to this, nsrlsvr will abort and display an
* error message to the log.
*/
void load_hashes()
{
const regex md5_re{ "^[A-Fa-f0-9]{32}$" };
uint32_t hash_count{ 0 };
ifstream infile{ hashes_location.c_str() };
* Each line must be either blank or 32 hexadecimal digits. If the
* file doesn't conform to this, nsrlsvr will abort and display an
* error message to the log.
*/
void load_hashes() {
const regex md5_re{"^[A-Fa-f0-9]{32}$"};
uint32_t hash_count{0};
ifstream infile{hashes_location.c_str()};
// As of this writing, the full RDS had about 45 million entries.
// When a vector needs to grow, it normally does so by doubling
// the former allocation -- so after this, the next stop is a
// 100 million allocation (@ 16 bytes per, or 1.6 GB). If you're
// maintaining this code, try to keep the reserve a few million
// larger than the RDS currently is, to give yourself room to
// grow without a vector realloc.
//
// Failure to reserve this block of memory is non-recoverable.
// Don't even try. Just log the error and bail out. Let the end
// user worry about installing more RAM.
try {
hash_set.reserve(50000000);
} catch (std::bad_alloc&) {
log(LogLevel::ALERT, "couldn't reserve enough memory");
exit(EXIT_FAILURE);
}
if (not infile) {
log(LogLevel::ALERT, "couldn't open hashes file " + hashes_location);
exit(EXIT_FAILURE);
}
while (infile) {
string line;
getline(infile, line);
transform(line.begin(), line.end(), line.begin(), ::toupper);
if (0 == line.size()) continue;
if (!regex_match(line.cbegin(), line.cend(), md5_re)) {
log(LogLevel::ALERT, "hash file appears corrupt! Loading no hashes.");
log(LogLevel::ALERT, "offending line is: " + line);
log(LogLevel::ALERT, "shutting down!");
exit(EXIT_FAILURE);
}
// As of this writing, the full RDS had about 65 million entries.
// When a vector needs to grow, it normally does so by doubling
// the former allocation -- so after this, the next stop is a
// 100 million allocation (@ 16 bytes per, or 1.6 GB). If you're
// maintaining this code, try to keep the reserve a few million
// larger than the RDS currently is, to give yourself room to
// grow without a vector realloc.
//
// Failure to reserve this block of memory is non-recoverable.
// Don't even try. Just log the error and bail out. Let the end
// user worry about installing more RAM.
try {
hash_set.reserve(50000000);
// .emplace_back is the C++11 improvement over the old
// vector.push_back. It has the benefit of not needing
// to construct a temporary to hold the value; it can
// just construct-in-place. For 40 million values, that
// can be significant.
//
// Note that if the vector runs out of reserved room it
// will attempt to make a new allocation double the size
// of the last. That means the application will at least
// briefly need *three times* the expected RAM -- one for
// the data set and two for the newly-allocated chunk.
// Given we're talking about multiple gigs of RAM, this
// .emplace_back needs to consider the possibility of a
// RAM allocation failure.
hash_set.emplace_back(to_pair64(line));
hash_count += 1;
if (0 == hash_count % 1000000) {
string howmany{to_string(hash_count / 1000000)};
log(LogLevel::INFO, "loaded " + howmany + " million hashes");
}
} catch (std::bad_alloc&) {
log(LogLevel::ALERT, "couldn't reserve enough memory");
log(LogLevel::ALERT, "couldn't allocate enough memory");
exit(EXIT_FAILURE);
}
}
string howmany{to_string(hash_count)};
log(LogLevel::INFO, "read in " + howmany + " hashes");
infile.close();
sort(hash_set.begin(), hash_set.end());
if (hash_set.size() > 1) {
log(LogLevel::INFO, "ensuring no duplicates");
for (auto iter = (hash_set.cbegin() + 1); iter != hash_set.cend(); ++iter) {
if (*(iter - 1) == *iter) {
log(LogLevel::ALERT,
"hash file contains duplicates -- "
"shutting down!");
exit(EXIT_FAILURE);
}
}
}
if (not infile) {
log(LogLevel::ALERT, "couldn't open hashes file " + hashes_location);
exit(EXIT_FAILURE);
}
while (infile) {
string line;
getline(infile, line);
transform(line.begin(), line.end(), line.begin(), ::toupper);
if (0 == line.size())
continue;
if (!regex_match(line.cbegin(), line.cend(), md5_re)) {
log(LogLevel::ALERT, "hash file appears corrupt! Loading no hashes.");
log(LogLevel::ALERT, "offending line is: " + line);
log(LogLevel::ALERT, "shutting down!");
exit(EXIT_FAILURE);
}
try {
// .emplace_back is the C++11 improvement over the old
// vector.push_back. It has the benefit of not needing
// to construct a temporary to hold the value; it can
// just construct-in-place. For 40 million values, that
// can be significant.
//
// Note that if the vector runs out of reserved room it
// will attempt to make a new allocation double the size
// of the last. That means the application will at least
// briefly need *three times* the expected RAM -- one for
// the data set and two for the newly-allocated chunk.
// Given we're talking about multiple gigs of RAM, this
// .emplace_back needs to consider the possibility of a
// RAM allocation failure.
hash_set.emplace_back(to_pair64(line));
hash_count += 1;
if (0 == hash_count % 1000000) {
string howmany{ to_string(hash_count / 1000000) };
log(LogLevel::INFO, "loaded " + howmany + " million hashes");
}
} catch (std::bad_alloc&) {
log(LogLevel::ALERT, "couldn't allocate enough memory");
exit(EXIT_FAILURE);
}
}
string howmany{ to_string(hash_count) };
log(LogLevel::INFO, "read in " + howmany + " hashes");
infile.close();
sort(hash_set.begin(), hash_set.end());
if (hash_set.size() > 1) {
log(LogLevel::INFO, "ensuring no duplicates");
for (auto iter = (hash_set.cbegin() + 1); iter != hash_set.cend(); ++iter) {
if (*(iter - 1) == *iter) {
log(LogLevel::ALERT, "hash file contains duplicates -- "
"shutting down!");
exit(EXIT_FAILURE);
}
}
}
log(LogLevel::INFO, "successfully loaded hashes");
log(LogLevel::INFO, "successfully loaded hashes");
}
/** Converts this process into a well-behaved UNIX daemon.*/
void daemonize()
{
/* Nothing in here should be surprising. If it is, then please
check the standard literature to ensure you understand how a
daemon is supposed to work. */
const auto pid = fork();
if (0 > pid) {
log(LogLevel::WARN, "couldn't fork!");
exit(EXIT_FAILURE);
} else if (0 < pid) {
exit(EXIT_SUCCESS);
}
log(LogLevel::INFO, "daemon started");
void daemonize() {
/* Nothing in here should be surprising. If it is, then please
check the standard literature to ensure you understand how a
daemon is supposed to work. */
const auto pid = fork();
if (0 > pid) {
log(LogLevel::WARN, "couldn't fork!");
exit(EXIT_FAILURE);
} else if (0 < pid) {
exit(EXIT_SUCCESS);
}
log(LogLevel::INFO, "daemon started");
umask(0);
umask(0);
if (0 > setsid()) {
log(LogLevel::WARN, "couldn't set sid");
exit(EXIT_FAILURE);
}
if (0 > setsid()) {
log(LogLevel::WARN, "couldn't set sid");
exit(EXIT_FAILURE);
}
if (0 > chdir("/")) {
log(LogLevel::WARN, "couldn't chdir to root");
exit(EXIT_FAILURE);
}
if (0 > chdir("/")) {
log(LogLevel::WARN, "couldn't chdir to root");
exit(EXIT_FAILURE);
}
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
/** Parse command-line options.
@param argc argc from main()
@param argv argv from main()
*/
void parse_options(int argc, char* argv[])
{
std::array<char, PATH_MAX> filename_buffer;
char* filepath{ &filename_buffer[0] };
fill(filename_buffer.begin(), filename_buffer.end(), 0);
options_description options{ "nsrlsvr options" };
options.add_options()("help,h", "Help screen")("version,v",
"Display package version")(
"bug-report,b", "Display bug reporting information")(
"file,f", value<string>()->default_value(PKGDATADIR "/hashes.txt"),
"hash file")(
"port,p", value<uint16_t>()->default_value(9120), "port")(
"dry-run", "test configuration");
variables_map vm;
store(parse_command_line(argc, argv, options), vm);
void parse_options(int argc, char* argv[]) {
std::array<char, PATH_MAX> filename_buffer;
char* filepath{&filename_buffer[0]};
fill(filename_buffer.begin(), filename_buffer.end(), 0);
options_description options{"nsrlsvr options"};
options.add_options()("help,h", "Help screen")("version,v",
"Display package version")(
"bug-report,b", "Display bug reporting information")(
"file,f", value<string>()->default_value(PKGDATADIR "/hashes.txt"),
"hash file")("port,p", value<uint16_t>()->default_value(9120), "port")(
"dry-run", "test configuration");
variables_map vm;
store(parse_command_line(argc, argv, options), vm);
dry_run = vm.count("dry-run") ? true : false;
dry_run = vm.count("dry-run") ? true : false;
if (vm.count("help")) {
cout << options << "\n";
exit(EXIT_SUCCESS);
}
if (vm.count("version")) {
cout << "nsrlsvr version " << PACKAGE_VERSION
<< "\n\n"
"This program is released under the ISC License.\n";
exit(EXIT_SUCCESS);
}
if (vm.count("bug-report")) {
cout << "To file a bug report, visit "
"https://github.com/rjhansen/nsrlsvr/issues\n";
exit(EXIT_SUCCESS);
}
port = vm["port"].as<uint16_t>();
string relpath = vm["file"].as<string>();
if (nullptr == (filepath = realpath(relpath.c_str(), filepath))) {
switch (errno) {
case EACCES:
cerr << "Could not access file path " << relpath
<< "\n(Do you have read privileges?)\n";
break;
case EINVAL:
cerr << "Somehow, the system believes the file path passed to it\n"
"is null. This is weird and probably a bug. Please report\n"
"it!\n";
break;
case EIO:
cerr << "An I/O error occurred while reading " << relpath << "\n";
break;
case ELOOP:
cerr << "Too many symbolic links were found while translating "
<< relpath << " into an absolute path.\n";
break;
case ENAMETOOLONG:
cerr << "The file path " << relpath << " is too long.\n";
break;
case ENOENT:
cerr << "The file " << relpath << " could not be found.\n";
break;
case ENOMEM:
cerr << "Strangely, the system ran out of memory while processing\n"
"your request. This is probably a bug in nsrlsvr.\n";
break;
case ENOTDIR:
cerr << "A component of the file path " << relpath
<< " is not a directory.";
break;
default:
cerr << "... wtfbbq? This should never trip. It's an nsrlsvr bug.\n";
break;
}
exit(EXIT_FAILURE);
}
hashes_location = string(filepath);
if (not ifstream(hashes_location.c_str())) {
cerr << "Could not open " + hashes_location + " for reading.\n";
exit(EXIT_FAILURE);
if (vm.count("help")) {
cout << options << "\n";
exit(EXIT_SUCCESS);
}
if (vm.count("version")) {
cout << "nsrlsvr version " << PACKAGE_VERSION
<< "\n\n"
"This program is released under the ISC License.\n";
exit(EXIT_SUCCESS);
}
if (vm.count("bug-report")) {
cout << "To file a bug report, visit "
"https://github.com/rjhansen/nsrlsvr/issues\n";
exit(EXIT_SUCCESS);
}
port = vm["port"].as<uint16_t>();
string relpath = vm["file"].as<string>();
if (nullptr == (filepath = realpath(relpath.c_str(), filepath))) {
switch (errno) {
case EACCES:
cerr << "Could not access file path " << relpath
<< "\n(Do you have read privileges?)\n";
break;
case EINVAL:
cerr << "Somehow, the system believes the file path passed to it\n"
"is null. This is weird and probably a bug. Please report\n"
"it!\n";
break;
case EIO:
cerr << "An I/O error occurred while reading " << relpath << "\n";
break;
case ELOOP:
cerr << "Too many symbolic links were found while translating "
<< relpath << " into an absolute path.\n";
break;
case ENAMETOOLONG:
cerr << "The file path " << relpath << " is too long.\n";
break;
case ENOENT:
cerr << "The file " << relpath << " could not be found.\n";
break;
case ENOMEM:
cerr << "Strangely, the system ran out of memory while processing\n"
"your request. This is probably a bug in nsrlsvr.\n";
break;
case ENOTDIR:
cerr << "A component of the file path " << relpath
<< " is not a directory.";
break;
default:
cerr << "... wtfbbq? This should never trip. It's an nsrlsvr bug.\n";
break;
}
exit(EXIT_FAILURE);
}
hashes_location = string(filepath);
if (not ifstream(hashes_location.c_str())) {
cerr << "Could not open " + hashes_location + " for reading.\n";
exit(EXIT_FAILURE);
}
}
}
} // namespace
/** The set of all loaded hashes, represented as a const reference. */
const vector<pair64>& hashes{ hash_set };
const vector<pair64>& hashes{hash_set};
/** Writes to syslog with the given priority level.
@param level The priority of the message
@param msg The message to write
*/
void log(const LogLevel level, const string&& msg)
{
if (dry_run)
cerr << msg << "\n";
else
syslog(LOG_MAKEPRI(LOG_USER, static_cast<int>(level)), "%s", msg.c_str());
void log(const LogLevel level, const string&& msg) {
if (dry_run)
cerr << msg << "\n";
else
syslog(LOG_MAKEPRI(LOG_USER, static_cast<int>(level)), "%s", msg.c_str());
}
/** Entry point for the application.
@@ -293,49 +288,46 @@ void log(const LogLevel level, const string&& msg)
@param argc The number of command-line arguments
@param argv Command-line arguments
*/
int main(int argc, char* argv[])
{
static_assert(sizeof(unsigned long long) == 8,
"wait, what kind of system is this?");
parse_options(argc, argv);
int main(int argc, char* argv[]) {
static_assert(sizeof(unsigned long long) == 8,
"wait, what kind of system is this?");
parse_options(argc, argv);
if (!dry_run)
daemonize();
if (!dry_run) daemonize();
load_hashes();
load_hashes();
// The following line helps avoid zombie processes. Normally parents
// need to reap their children in order to prevent zombie processes;
// if SIGCHLD is set to SIG_IGN, though, the processes can terminate
// normally.
signal(SIGCHLD, SIG_IGN);
// The following line helps avoid zombie processes. Normally parents
// need to reap their children in order to prevent zombie processes;
// if SIGCHLD is set to SIG_IGN, though, the processes can terminate
// normally.
signal(SIGCHLD, SIG_IGN);
if (dry_run)
return EXIT_SUCCESS;
boost::asio::io_service io_service;
tcp::endpoint endpoint(tcp::v4(), port);
tcp::acceptor acceptor(io_service, endpoint);
if (dry_run) return EXIT_SUCCESS;
while (true) {
tcp::iostream stream;
boost::system::error_code error;
acceptor.accept(*stream.rdbuf(), error);
if (error) {
continue;
}
string ipaddr = stream.socket().remote_endpoint().address().to_string();
log(LogLevel::ALERT, string("accepted a client: ") + ipaddr);
boost::asio::io_service io_service;
tcp::endpoint endpoint(tcp::v4(), port);
tcp::acceptor acceptor(io_service, endpoint);
if (0 == fork()) {
log(LogLevel::ALERT, "calling handle_client");
handle_client(stream);
return 0;
}
while (true) {
tcp::iostream stream;
boost::system::error_code error;
acceptor.accept(*stream.rdbuf(), error);
if (error) {
continue;
}
string ipaddr = stream.socket().remote_endpoint().address().to_string();
log(LogLevel::ALERT, string("accepted a client: ") + ipaddr);
// Note that as is normal for daemons, the exit point is never
// reached. This application does not normally terminate.
return EXIT_SUCCESS;
if (0 == fork()) {
log(LogLevel::ALERT, "calling handle_client");
handle_client(stream);
return 0;
}
}
// Note that as is normal for daemons, the exit point is never
// reached. This application does not normally terminate.
return EXIT_SUCCESS;
}

View File

@@ -17,18 +17,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#ifndef MAIN_H
#define MAIN_H
#include <utility>
#include <string>
#include <syslog.h>
#include <cstdint>
#include <boost/asio.hpp>
#include <cstdint>
#include <string>
#include <utility>
// Note: C++11 guarantees an unsigned long long will be at least 64 bits.
// A compile-time assert in main.cc guarantees it will ONLY be 64 bits.
using pair64 = std::pair<unsigned long long, unsigned long long>;
enum class LogLevel
{
enum class LogLevel {
INFO = LOG_INFO,
WARN = LOG_WARNING,
DEBUG = LOG_DEBUG,

View File

@@ -14,65 +14,55 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "main.h"
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <regex>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include "main.h"
using std::pair;
using std::string;
using std::hex;
using std::invalid_argument;
using std::make_pair;
using std::pair;
using std::regex;
using std::regex_match;
using std::invalid_argument;
using std::stringstream;
using std::setw;
using std::setfill;
using std::hex;
using std::setw;
using std::string;
using std::stringstream;
string
from_pair64(const pair64& input)
{
stringstream stream;
stream << setfill('0')
<< setw(sizeof(unsigned long long) * 2)
<< hex
<< input.first
<< input.second;
return string(stream.str());
string from_pair64(const pair64& input) {
stringstream stream;
stream << setfill('0') << setw(sizeof(unsigned long long) * 2) << hex
<< input.first << input.second;
return string(stream.str());
}
pair64
to_pair64(const string& input)
{
static const regex md5_re{ "^[A-Fa-f0-9]{32}$" };
pair64 to_pair64(const string& input) {
static const regex md5_re{"^[A-Fa-f0-9]{32}$"};
if (!regex_match(input.cbegin(), input.cend(), md5_re))
throw invalid_argument("not a hash");
auto first = string(input.cbegin(), input.cbegin() + 16);
auto second = string(input.cbegin() + 16, input.cend());
auto left = std::strtoull(first.c_str(), nullptr, 16);
auto right = std::strtoull(second.c_str(), nullptr, 16);
if (!regex_match(input.cbegin(), input.cend(), md5_re))
throw invalid_argument("not a hash");
return make_pair(left, right);
auto first = string(input.cbegin(), input.cbegin() + 16);
auto second = string(input.cbegin() + 16, input.cend());
auto left = std::strtoull(first.c_str(), nullptr, 16);
auto right = std::strtoull(second.c_str(), nullptr, 16);
return make_pair(left, right);
}
bool operator<(const pair64& lhs, const pair64& rhs)
{
return (lhs.first < rhs.first) or
(lhs.first == rhs.first and lhs.second < rhs.second);
bool operator<(const pair64& lhs, const pair64& rhs) {
return (lhs.first < rhs.first) or
(lhs.first == rhs.first and lhs.second < rhs.second);
}
bool operator==(const pair64& lhs, const pair64& rhs)
{
return (lhs.first == rhs.first) and (lhs.second == rhs.second);
bool operator==(const pair64& lhs, const pair64& rhs) {
return (lhs.first == rhs.first) and (lhs.second == rhs.second);
}
bool operator>(const pair64& lhs, const pair64& rhs)
{
return ((!(lhs < rhs)) and (!(lhs == rhs)));
bool operator>(const pair64& lhs, const pair64& rhs) {
return ((!(lhs < rhs)) and (!(lhs == rhs)));
}