Add C/C++ template
This commit is contained in:
		
							
								
								
									
										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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user