Add C/C++ template
This commit is contained in:
parent
cd0392d6d2
commit
d52d4fc3a9
82
template_cpp/.gitignore
vendored
Normal file
82
template_cpp/.gitignore
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/c,c++
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=c,c++
|
||||||
|
#
|
||||||
|
|
||||||
|
bin/da_proc
|
||||||
|
target/
|
||||||
|
|
||||||
|
### C ###
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Object files
|
||||||
|
*.o
|
||||||
|
*.ko
|
||||||
|
*.obj
|
||||||
|
*.elf
|
||||||
|
|
||||||
|
# Linker output
|
||||||
|
*.ilk
|
||||||
|
*.map
|
||||||
|
*.exp
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# Shared objects (inc. Windows DLLs)
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.i*86
|
||||||
|
*.x86_64
|
||||||
|
*.hex
|
||||||
|
|
||||||
|
# Debug files
|
||||||
|
*.dSYM/
|
||||||
|
*.su
|
||||||
|
*.idb
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Kernel Module Compile Results
|
||||||
|
*.mod*
|
||||||
|
*.cmd
|
||||||
|
.tmp_versions/
|
||||||
|
modules.order
|
||||||
|
Module.symvers
|
||||||
|
Mkfile.old
|
||||||
|
dkms.conf
|
||||||
|
|
||||||
|
### C++ ###
|
||||||
|
# Prerequisites
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/c,c++
|
72
template_cpp/CMakeLists.txt
Normal file
72
template_cpp/CMakeLists.txt
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.9)
|
||||||
|
project(da_project)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
string(CONCAT CMAKE_CXX_FLAGS_COMMON_STR ""
|
||||||
|
"-Werror -Wall -Wconversion -Wfloat-equal "
|
||||||
|
"-Wpedantic -Wpointer-arith -Wswitch-default "
|
||||||
|
"-Wpacked -Wextra -Winvalid-pch "
|
||||||
|
"-Wmissing-field-initializers "
|
||||||
|
"-Wunreachable-code -Wcast-align -Wcast-qual "
|
||||||
|
"-Wdisabled-optimization -Wformat=2 "
|
||||||
|
"-Wformat-nonliteral -Wuninitialized "
|
||||||
|
"-Wformat-security -Wformat-y2k -Winit-self "
|
||||||
|
"-Wmissing-declarations -Wmissing-include-dirs "
|
||||||
|
"-Wredundant-decls -Wstrict-overflow=5 -Wundef "
|
||||||
|
"-Wno-unused -Wctor-dtor-privacy -Wsign-promo "
|
||||||
|
"-Woverloaded-virtual -Wold-style-cast")
|
||||||
|
|
||||||
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
|
string(CONCAT CMAKE_CXX_FLAGS_STR "${CMAKE_CXX_FLAGS_COMMON_STR} "
|
||||||
|
"-Wlogical-op -Wstrict-null-sentinel -Wnoexcept")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_STR}")
|
||||||
|
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
string(CONCAT CMAKE_CXX_FLAGS_STR "${CMAKE_CXX_FLAGS_COMMON_STR} ")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_STR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(CONCAT CMAKE_C_FLAGS_COMMON_STR ""
|
||||||
|
"-Werror -Wall -Wconversion -Wfloat-equal "
|
||||||
|
"-Wpedantic -Wpointer-arith -Wswitch-default "
|
||||||
|
"-Wpacked -Wextra -Winvalid-pch "
|
||||||
|
"-Wmissing-field-initializers -Wunreachable-code "
|
||||||
|
"-Wcast-align -Wcast-qual -Wdisabled-optimization "
|
||||||
|
"-Wformat=2 -Wformat-nonliteral -Wuninitialized "
|
||||||
|
"-Wformat-security -Wformat-y2k -Winit-self "
|
||||||
|
"-Wmissing-declarations -Wmissing-include-dirs "
|
||||||
|
"-Wredundant-decls -Wstrict-overflow=5 "
|
||||||
|
"-Wundef -Wno-unused")
|
||||||
|
|
||||||
|
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||||
|
string(CONCAT CMAKE_C_FLAGS_STR "${CMAKE_C_FLAGS_COMMON_STR} "
|
||||||
|
"-Wlogical-op")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_STR}")
|
||||||
|
elseif (CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||||
|
string(CONCAT CMAKE_C_FLAGS_STR "${CMAKE_C_FLAGS_COMMON_STR} ")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_STR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS_DEBUG "-Winline -g")
|
||||||
|
set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
|
||||||
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG")
|
||||||
|
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-Winline -g")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG")
|
||||||
|
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
|
||||||
|
|
||||||
|
# MESSAGE( STATUS "CMAKE_C_FLAGS: " ${CMAKE_C_FLAGS} )
|
||||||
|
# MESSAGE( STATUS "CMAKE_CXX_FLAGS: " ${CMAKE_CXX_FLAGS} )
|
||||||
|
# MESSAGE( STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE} )
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
1
template_cpp/bin/README
Normal file
1
template_cpp/bin/README
Normal file
@ -0,0 +1 @@
|
|||||||
|
This is a reserved directory name! Store the binary generated by `build.sh` in this directory
|
1
template_cpp/bin/deploy/README
Normal file
1
template_cpp/bin/deploy/README
Normal file
@ -0,0 +1 @@
|
|||||||
|
This is a reserved directory name, do not delete or use in your application!
|
1
template_cpp/bin/logs/README
Normal file
1
template_cpp/bin/logs/README
Normal file
@ -0,0 +1 @@
|
|||||||
|
This is a reserved directory name, do not delete or use in your application!
|
13
template_cpp/build.sh
Executable file
13
template_cpp/build.sh
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Change the current working directory to the location of the present file
|
||||||
|
cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
|
|
||||||
|
rm -rf target
|
||||||
|
mkdir target
|
||||||
|
cd target
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||||
|
cmake --build .
|
||||||
|
mv src/da_proc ../bin
|
7
template_cpp/cleanup.sh
Executable file
7
template_cpp/cleanup.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Change the current working directory to the location of the present file
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
|
|
||||||
|
rm -f "$DIR"/bin/da_proc
|
||||||
|
rm -rf "$DIR"/target
|
9
template_cpp/run.sh
Executable file
9
template_cpp/run.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Change the current working directory to the location of the present file
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
|
|
||||||
|
ret=0
|
||||||
|
exec 3>&1; $("$DIR"/bin/da_proc "$@" >&3); ret=$?; exec 3>&-
|
||||||
|
|
||||||
|
exit $ret
|
7
template_cpp/src/CMakeLists.txt
Normal file
7
template_cpp/src/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# DO NAME THE SYMBOLIC VARIABLE `SOURCES`
|
||||||
|
|
||||||
|
include_directories(include)
|
||||||
|
set(SOURCES src/main.cpp)
|
||||||
|
|
||||||
|
# DO NOT EDIT THE FOLLOWING LINE
|
||||||
|
add_executable(da_proc ${SOURCES})
|
32
template_cpp/src/include/barrier.hpp
Normal file
32
template_cpp/src/include/barrier.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "parser.hpp"
|
||||||
|
|
||||||
|
void waitOnBarrier(Parser::Host const &barrier);
|
||||||
|
|
||||||
|
void waitOnBarrier(Parser::Host const &barrier) {
|
||||||
|
struct sockaddr_in server;
|
||||||
|
std::memset(&server, 0, sizeof(server));
|
||||||
|
|
||||||
|
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
throw std::runtime_error("Could not create the barrier socket: " +
|
||||||
|
std::string(std::strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
server.sin_family = AF_INET;
|
||||||
|
server.sin_addr.s_addr = barrier.ip;
|
||||||
|
server.sin_port = barrier.port;
|
||||||
|
if (connect(fd, reinterpret_cast<struct sockaddr *>(&server),
|
||||||
|
sizeof(server)) < 0) {
|
||||||
|
throw std::runtime_error("Could not connect to the barrier: " +
|
||||||
|
std::string(std::strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
char dummy;
|
||||||
|
if (recv(fd, &dummy, sizeof(dummy), 0) < 0) {
|
||||||
|
throw std::runtime_error("Could not read from the barrier socket: " +
|
||||||
|
std::string(std::strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
357
template_cpp/src/include/parser.hpp
Normal file
357
template_cpp/src/include/parser.hpp
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
class Parser {
|
||||||
|
public:
|
||||||
|
struct Host {
|
||||||
|
Host() {}
|
||||||
|
Host(size_t id, std::string &ip_or_hostname, unsigned short port)
|
||||||
|
: id{id}, port{htons(port)} {
|
||||||
|
|
||||||
|
if (isValidIpAddress(ip_or_hostname.c_str())) {
|
||||||
|
ip = inet_addr(ip_or_hostname.c_str());
|
||||||
|
} else {
|
||||||
|
ip = ipLookup(ip_or_hostname.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ipReadable() const {
|
||||||
|
in_addr tmp_ip;
|
||||||
|
tmp_ip.s_addr = ip;
|
||||||
|
return std::string(inet_ntoa(tmp_ip));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short portReadable() const { return ntohs(port); }
|
||||||
|
|
||||||
|
unsigned long id;
|
||||||
|
in_addr_t ip;
|
||||||
|
unsigned short port;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool isValidIpAddress(const char *ipAddress) {
|
||||||
|
struct sockaddr_in sa;
|
||||||
|
int result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
|
||||||
|
return result != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_addr_t ipLookup(const char *host) {
|
||||||
|
struct addrinfo hints, *res;
|
||||||
|
char addrstr[128];
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = PF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_flags |= AI_CANONNAME;
|
||||||
|
|
||||||
|
if (getaddrinfo(host, NULL, &hints, &res) != 0) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Could not resolve host `" + std::string(host) +
|
||||||
|
"` to IP: " + std::string(std::strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (res) {
|
||||||
|
inet_ntop(res->ai_family, res->ai_addr->sa_data, addrstr, 128);
|
||||||
|
|
||||||
|
switch (res->ai_family) {
|
||||||
|
case AF_INET:
|
||||||
|
ptr =
|
||||||
|
&(reinterpret_cast<struct sockaddr_in *>(res->ai_addr))->sin_addr;
|
||||||
|
inet_ntop(res->ai_family, ptr, addrstr, 128);
|
||||||
|
return inet_addr(addrstr);
|
||||||
|
break;
|
||||||
|
// case AF_INET6:
|
||||||
|
// ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
|
||||||
|
// break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res = res->ai_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("No host resolves to IPv4");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Parser(const int argc, char const *const *argv, bool withConfig)
|
||||||
|
: argc{argc}, argv{argv}, withConfig{withConfig}, parsed{false} {}
|
||||||
|
|
||||||
|
void parse() {
|
||||||
|
if (!parseInternal()) {
|
||||||
|
help(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long id() const {
|
||||||
|
checkParsed();
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *hostsPath() const {
|
||||||
|
checkParsed();
|
||||||
|
return hostsPath_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
Host barrier() const {
|
||||||
|
checkParsed();
|
||||||
|
return barrier_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *outputPath() const {
|
||||||
|
checkParsed();
|
||||||
|
return outputPath_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *configPath() const {
|
||||||
|
checkParsed();
|
||||||
|
if (!withConfig) {
|
||||||
|
throw std::runtime_error("Parser is configure to ignore the config path");
|
||||||
|
}
|
||||||
|
|
||||||
|
return configPath_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Host> hosts() {
|
||||||
|
std::ifstream hostsFile(hostsPath());
|
||||||
|
std::vector<Host> hosts;
|
||||||
|
|
||||||
|
if (!hostsFile.is_open()) {
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "`" << hostsPath() << "` does not exist.";
|
||||||
|
throw std::invalid_argument(os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
int lineNum = 0;
|
||||||
|
while (std::getline(hostsFile, line)) {
|
||||||
|
lineNum += 1;
|
||||||
|
|
||||||
|
std::istringstream iss(line);
|
||||||
|
|
||||||
|
trim(line);
|
||||||
|
if (line.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long id;
|
||||||
|
std::string ip;
|
||||||
|
unsigned short port;
|
||||||
|
|
||||||
|
if (!(iss >> id >> ip >> port)) {
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "Parsing for `" << hostsPath() << "` failed at line " << lineNum;
|
||||||
|
throw std::invalid_argument(os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
hosts.push_back(Host(id, ip, port));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hosts.size() < 2UL) {
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "`" << hostsPath() << "` must contain at least two hosts";
|
||||||
|
throw std::invalid_argument(os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto comp = [](const Host &x, const Host &y) { return x.id < y.id; };
|
||||||
|
auto result = std::minmax_element(hosts.begin(), hosts.end(), comp);
|
||||||
|
size_t minID = (*result.first).id;
|
||||||
|
size_t maxID = (*result.second).id;
|
||||||
|
if (minID != 1UL || maxID != static_cast<unsigned long>(hosts.size())) {
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "In `" << hostsPath()
|
||||||
|
<< "` IDs of processes have to start from 1 and be compact";
|
||||||
|
throw std::invalid_argument(os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(hosts.begin(), hosts.end(),
|
||||||
|
[](const Host &a, const Host &b) -> bool { return a.id < b.id; });
|
||||||
|
|
||||||
|
return hosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool parseInternal() {
|
||||||
|
if (!parseID()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parseHostPath()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parseBarrier()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parseOutputPath()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parseConfigPath()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void help(const int, char const *const *argv) {
|
||||||
|
auto configStr = "CONFIG";
|
||||||
|
std::cerr << "Usage: " << argv[0]
|
||||||
|
<< " --id ID --hosts HOSTS --barrier NAME:PORT --output OUTPUT";
|
||||||
|
|
||||||
|
if (!withConfig) {
|
||||||
|
std::cerr << "\n";
|
||||||
|
} else {
|
||||||
|
std::cerr << " CONFIG\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseID() {
|
||||||
|
if (argc < 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::strcmp(argv[1], "--id") == 0) {
|
||||||
|
if (isPositiveNumber(argv[2])) {
|
||||||
|
try {
|
||||||
|
id_ = std::stoul(argv[2]);
|
||||||
|
} catch (std::invalid_argument const &e) {
|
||||||
|
return false;
|
||||||
|
} catch (std::out_of_range const &e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseHostPath() {
|
||||||
|
if (argc < 5) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::strcmp(argv[3], "--hosts") == 0) {
|
||||||
|
hostsPath_ = std::string(argv[4]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseBarrier() {
|
||||||
|
if (argc < 7) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::strcmp(argv[5], "--barrier") == 0) {
|
||||||
|
std::string barrier_addr = argv[6];
|
||||||
|
std::replace(barrier_addr.begin(), barrier_addr.end(), ':', ' ');
|
||||||
|
std::stringstream ss(barrier_addr);
|
||||||
|
|
||||||
|
std::string barrier_name;
|
||||||
|
unsigned short barrier_port;
|
||||||
|
|
||||||
|
ss >> barrier_name;
|
||||||
|
ss >> barrier_port;
|
||||||
|
|
||||||
|
barrier_ = Host(0, barrier_name, barrier_port);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseOutputPath() {
|
||||||
|
if (argc < 9) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::strcmp(argv[7], "--output") == 0) {
|
||||||
|
outputPath_ = std::string(argv[8]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseConfigPath() {
|
||||||
|
if (!withConfig) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 10) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
configPath_ = std::string(argv[9]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPositiveNumber(const std::string &s) const {
|
||||||
|
return !s.empty() && std::find_if(s.begin(), s.end(), [](unsigned char c) {
|
||||||
|
return !std::isdigit(c);
|
||||||
|
}) == s.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkParsed() const {
|
||||||
|
if (!parsed) {
|
||||||
|
throw std::runtime_error("Invoke parse() first");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ltrim(std::string &s) {
|
||||||
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
|
||||||
|
[](int ch) { return !std::isspace(ch); }));
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtrim(std::string &s) {
|
||||||
|
s.erase(std::find_if(s.rbegin(), s.rend(),
|
||||||
|
[](int ch) { return !std::isspace(ch); })
|
||||||
|
.base(),
|
||||||
|
s.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void trim(std::string &s) {
|
||||||
|
ltrim(s);
|
||||||
|
rtrim(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int argc;
|
||||||
|
char const *const *argv;
|
||||||
|
bool withConfig;
|
||||||
|
|
||||||
|
bool parsed;
|
||||||
|
|
||||||
|
unsigned long id_;
|
||||||
|
std::string hostsPath_;
|
||||||
|
Host barrier_;
|
||||||
|
std::string outputPath_;
|
||||||
|
std::string configPath_;
|
||||||
|
};
|
85
template_cpp/src/src/main.cpp
Normal file
85
template_cpp/src/src/main.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "barrier.hpp"
|
||||||
|
#include "parser.hpp"
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
static void stop(int) {
|
||||||
|
// reset signal handlers to default
|
||||||
|
signal(SIGTERM, SIG_DFL);
|
||||||
|
signal(SIGINT, SIG_DFL);
|
||||||
|
|
||||||
|
// immediately stop network packet processing
|
||||||
|
std::cout << "Immediately stopping network packet processing.\n";
|
||||||
|
|
||||||
|
// write/flush output file if necessary
|
||||||
|
std::cout << "Writing output.\n";
|
||||||
|
|
||||||
|
// exit directly from signal handler
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
signal(SIGTERM, stop);
|
||||||
|
signal(SIGINT, stop);
|
||||||
|
|
||||||
|
// `true` means that a config file is required.
|
||||||
|
// Call with `false` if no config file is necessary.
|
||||||
|
bool requireConfig = true;
|
||||||
|
|
||||||
|
Parser parser(argc, argv, requireConfig);
|
||||||
|
parser.parse();
|
||||||
|
|
||||||
|
std::cout << "My PID: " << getpid() << "\n";
|
||||||
|
std::cout << "Use `kill -SIGINT " << getpid() << "` or `kill -SIGTERM "
|
||||||
|
<< getpid() << "` to stop processing packets\n\n";
|
||||||
|
|
||||||
|
std::cout << "My ID: " << parser.id() << "\n\n";
|
||||||
|
|
||||||
|
std::cout << "Path to hosts:\n";
|
||||||
|
std::cout << "==============\n";
|
||||||
|
std::cout << parser.hostsPath() << "\n\n";
|
||||||
|
|
||||||
|
std::cout << "List of resolved hosts is:\n";
|
||||||
|
std::cout << "==========================\n";
|
||||||
|
auto hosts = parser.hosts();
|
||||||
|
for (auto &host : hosts) {
|
||||||
|
std::cout << host.id << "\n";
|
||||||
|
std::cout << "Human-readable IP: " << host.ipReadable() << "\n";
|
||||||
|
std::cout << "Machine-readable IP: " << host.ip << "\n";
|
||||||
|
std::cout << "Human-readbale Port: " << host.portReadable() << "\n";
|
||||||
|
std::cout << "Machine-readbale Port: " << host.port << "\n";
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "Barrier:\n";
|
||||||
|
std::cout << "========\n";
|
||||||
|
auto barrier = parser.barrier();
|
||||||
|
std::cout << "Human-readable IP: " << barrier.ipReadable() << "\n";
|
||||||
|
std::cout << "Machine-readable IP: " << barrier.ip << "\n";
|
||||||
|
std::cout << "Human-readbale Port: " << barrier.portReadable() << "\n";
|
||||||
|
std::cout << "Machine-readbale Port: " << barrier.port << "\n";
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "Path to output:\n";
|
||||||
|
std::cout << "===============\n";
|
||||||
|
std::cout << parser.outputPath() << "\n\n";
|
||||||
|
|
||||||
|
if (requireConfig) {
|
||||||
|
std::cout << "Path to config:\n";
|
||||||
|
std::cout << "===============\n";
|
||||||
|
std::cout << parser.configPath() << "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Doing some initialization...\n\n";
|
||||||
|
|
||||||
|
std::cout << "Waiting for all processes to finish initialization\n\n";
|
||||||
|
waitOnBarrier(barrier);
|
||||||
|
|
||||||
|
std::cout << "Broadcasting messages...\n\n";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user