Add config parsing
This commit is contained in:
parent
229ea933cd
commit
d7b740b86e
88
Makefile.am
88
Makefile.am
@ -37,31 +37,11 @@ bin_PROGRAMS = paxos
|
||||
CONFIG = \
|
||||
src/config/config.hh \
|
||||
src/config/config.cc \
|
||||
src/config/proxy.hh \
|
||||
src/config/proxy.cc \
|
||||
src/config/parse.hh \
|
||||
src/config/parse.hxx \
|
||||
src/config/parse.cc \
|
||||
src/config/timeout.hh \
|
||||
src/config/timeout.cc \
|
||||
src/config/upstream.hh \
|
||||
src/config/upstream.cc
|
||||
|
||||
VHOST = \
|
||||
src/vhost/vhost-factory.cc \
|
||||
src/vhost/vhost-static-file.cc \
|
||||
src/vhost/vhost-reverse-proxy.cc \
|
||||
src/vhost/connection.hh \
|
||||
src/vhost/connection.cc \
|
||||
src/vhost/apm.hh \
|
||||
src/vhost/apm.cc \
|
||||
src/vhost/vhost.cc
|
||||
src/config/parse.cc
|
||||
|
||||
MISC = \
|
||||
src/misc/buffer.hh \
|
||||
src/misc/buffer.cc \
|
||||
src/misc/option.hh \
|
||||
src/misc/option.cc \
|
||||
src/misc/addrinfo/addrinfo-error.cc \
|
||||
src/misc/addrinfo/addrinfo-error.hh \
|
||||
src/misc/addrinfo/addrinfo-iterator.hh \
|
||||
@ -70,17 +50,9 @@ MISC = \
|
||||
src/misc/fd.cc \
|
||||
src/misc/fd.hh \
|
||||
src/misc/json.hh \
|
||||
src/misc/openssl/base64.cc \
|
||||
src/misc/openssl/base64.hh \
|
||||
src/misc/openssl/ssl-error.cc \
|
||||
src/misc/openssl/ssl-error.hh \
|
||||
src/misc/openssl/ssl-wrapper.hh \
|
||||
src/misc/openssl/ssl.hh \
|
||||
src/misc/socket.hh \
|
||||
src/misc/sys-wrapper.hh \
|
||||
src/misc/unistd.hh \
|
||||
src/misc/readiness/readiness.cc \
|
||||
src/misc/readiness/readiness.hh \
|
||||
src/misc/logger.cc \
|
||||
src/misc/logger.hh
|
||||
|
||||
@ -109,76 +81,22 @@ EVENTS = \
|
||||
src/events/reverse-proxy.cc \
|
||||
src/events/reverse-proxy.hh
|
||||
|
||||
ERROR = \
|
||||
src/error/init-error.hh \
|
||||
src/error/not-implemented.hh \
|
||||
src/error/parsing-error.hh \
|
||||
src/error/connection-closed.hh \
|
||||
src/error/connection-failed.hh \
|
||||
src/error/backend-unavailable.hh
|
||||
|
||||
SOCKET = \
|
||||
src/socket/default-socket.cc \
|
||||
src/socket/default-socket.hh \
|
||||
src/socket/socket.hh \
|
||||
src/socket/ssl-socket.cc \
|
||||
src/socket/ssl-socket.hh
|
||||
|
||||
TIMER = \
|
||||
src/timer/timer.cc \
|
||||
src/timer/timer.hh \
|
||||
src/timer/queue.cc \
|
||||
src/timer/queue.hh \
|
||||
src/timer/throughput-queue.cc \
|
||||
src/timer/throughput-queue.hh \
|
||||
src/timer/proxy-queue.cc \
|
||||
src/timer/procy-queue.hh \
|
||||
src/timer/queue-manager.cc \
|
||||
src/timer/queue-manager.hh
|
||||
|
||||
SCHEDULER = \
|
||||
src/scheduler/scheduler.cc \
|
||||
src/scheduler/scheduler.hh \
|
||||
src/scheduler/round-robin.cc \
|
||||
src/scheduler/round-robin.hh \
|
||||
src/scheduler/failover.cc \
|
||||
src/scheduler/failover.hh \
|
||||
src/scheduler/fail-robin.cc \
|
||||
src/scheduler/fail-robin.hh \
|
||||
src/scheduler/send-health.cc \
|
||||
src/scheduler/send-health.hh \
|
||||
src/scheduler/recv-health.cc \
|
||||
src/scheduler/recv-health.hh
|
||||
src/socket/socket.hh
|
||||
|
||||
SOURCES = \
|
||||
src/request/error.cc \
|
||||
src/request/error.hh \
|
||||
src/request/request.cc \
|
||||
src/request/request.hh \
|
||||
src/request/message.hh \
|
||||
src/request/message.cc \
|
||||
src/request/response.hh \
|
||||
src/request/response.cc \
|
||||
src/request/types.hh \
|
||||
src/vhost/dispatcher.cc \
|
||||
src/vhost/dispatcher.hh \
|
||||
src/vhost/vhost-factory.hh \
|
||||
src/vhost/vhost-reverse-proxy.hh \
|
||||
src/vhost/vhost-static-file.hh \
|
||||
src/vhost/vhost.hh \
|
||||
$(CONFIG) \
|
||||
$(VHOST) \
|
||||
$(MISC) \
|
||||
$(EVENTS) \
|
||||
$(ERROR) \
|
||||
$(SOCKET) \
|
||||
$(TIMER) \
|
||||
$(SCHEDULER) \
|
||||
$(NULL)
|
||||
|
||||
|
||||
# Compile source files again to avoid silenting undefined references.
|
||||
paxos_SOURCES = \
|
||||
$(SOURCES) \
|
||||
src/main.cc \
|
||||
$(NULL)
|
||||
|
||||
|
10
config-files/one-legislator.json
Normal file
10
config-files/one-legislator.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"legislators" : [
|
||||
{
|
||||
"ip" : "127.0.0.1",
|
||||
"port" : 8000,
|
||||
"name" : "test",
|
||||
"self" : true
|
||||
}
|
||||
]
|
||||
}
|
112
src/config/config.cc
Normal file
112
src/config/config.cc
Normal file
@ -0,0 +1,112 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "config.hh"
|
||||
#include "parse.hh"
|
||||
|
||||
namespace paxos
|
||||
{
|
||||
|
||||
ServerConfig::ServerConfig(const std::vector<LegislatorConfig>& legislators)
|
||||
: legislators_(legislators)
|
||||
{
|
||||
}
|
||||
|
||||
static std::string format_ip(std::string ip)
|
||||
{
|
||||
int family = 0;
|
||||
|
||||
/* Check if it is an IPv4 or Ipv6 address */
|
||||
if (ip.find(":") != std::string::npos)
|
||||
family = AF_INET6;
|
||||
else
|
||||
family = AF_INET;
|
||||
|
||||
/* Allocated static buffer to make conversion */
|
||||
unsigned char buf[sizeof(struct in6_addr)];
|
||||
char formatted_ip[INET6_ADDRSTRLEN];
|
||||
|
||||
/* Convert ip string to network address structure */
|
||||
int success = inet_pton(family, ip.c_str(), buf);
|
||||
|
||||
if (success <= 0)
|
||||
error_and_exit(1, "parse_configuration: " + ip + " is an invalid ip");
|
||||
|
||||
/* Convert back the network address to an string */
|
||||
inet_ntop(family, buf, formatted_ip, INET6_ADDRSTRLEN);
|
||||
return formatted_ip;
|
||||
}
|
||||
|
||||
|
||||
static void parse_mandatory_keys(const json& j, LegislatorConfig& config)
|
||||
{
|
||||
int port_int;
|
||||
|
||||
safe_get_key(j, "ip", config.ip, true);
|
||||
config.ip = format_ip(config.ip);
|
||||
|
||||
safe_get_key(j, "port", port_int, true);
|
||||
config.port = std::to_string(port_int);
|
||||
|
||||
safe_get_key(j, "name", config.name, true);
|
||||
|
||||
safe_get_key(j, "self", config.is_self, true);
|
||||
}
|
||||
|
||||
|
||||
static void from_json(const json& j, LegislatorConfig& config)
|
||||
{
|
||||
parse_mandatory_keys(j, config);
|
||||
}
|
||||
|
||||
|
||||
static std::vector<LegislatorConfig> parse_legislators(const json& j)
|
||||
{
|
||||
/* Get 'vhosts' value */
|
||||
std::vector<json> legislators;
|
||||
safe_get_key(j, "legislators", legislators, true);
|
||||
|
||||
/* Create VHostConfig vector and fill with VHostConfig */
|
||||
std::vector<LegislatorConfig> legislator_configs;
|
||||
|
||||
for (auto it : legislators)
|
||||
{
|
||||
/* Differenciable vhost checking */
|
||||
auto legislator = it.get<paxos::LegislatorConfig>();
|
||||
|
||||
legislator_configs.push_back(legislator);
|
||||
}
|
||||
|
||||
return legislator_configs;
|
||||
}
|
||||
|
||||
|
||||
ServerConfig ServerConfig::parse(const std::string& path)
|
||||
{
|
||||
json json_dict;
|
||||
std::ifstream json_file(path);
|
||||
|
||||
/* Check if file is corretly opened */
|
||||
if (!json_file.is_open())
|
||||
{
|
||||
error_and_exit(1, "parse_configuration: file " + path
|
||||
+ " doesn't exist.");
|
||||
}
|
||||
|
||||
|
||||
/* Check if file respect the json syntax */
|
||||
try
|
||||
{
|
||||
json_file >> json_dict;
|
||||
}
|
||||
catch (const nlohmann::detail::parse_error& e)
|
||||
{
|
||||
error_and_exit(1, e.what());
|
||||
}
|
||||
|
||||
std::vector<LegislatorConfig> legislators = parse_legislators(json_dict);
|
||||
|
||||
return ServerConfig(legislators);
|
||||
}
|
||||
}
|
25
src/config/config.hh
Normal file
25
src/config/config.hh
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include<iostream>
|
||||
#include <string>
|
||||
#include "misc/json.hh"
|
||||
|
||||
namespace paxos
|
||||
{
|
||||
struct LegislatorConfig
|
||||
{
|
||||
std::string ip;
|
||||
std::string port;
|
||||
std::string name;
|
||||
bool is_self;
|
||||
};
|
||||
|
||||
struct ServerConfig
|
||||
{
|
||||
ServerConfig(const std::vector<LegislatorConfig>& legislators);
|
||||
|
||||
std::vector<LegislatorConfig> legislators_;
|
||||
|
||||
static ServerConfig parse(const std::string& path);
|
||||
};
|
||||
}
|
12
src/config/parse.cc
Normal file
12
src/config/parse.cc
Normal file
@ -0,0 +1,12 @@
|
||||
#include "parse.hh"
|
||||
|
||||
namespace paxos
|
||||
{
|
||||
void error_and_exit(int code, const std::string& error)
|
||||
{
|
||||
/* Display 'error' on stderr and exit with 'code' */
|
||||
std::cerr << error << "\n";
|
||||
exit(code);
|
||||
}
|
||||
|
||||
} // namespace http
|
12
src/config/parse.hh
Normal file
12
src/config/parse.hh
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "misc/json.hh"
|
||||
|
||||
namespace paxos
|
||||
{
|
||||
[[noreturn]] void error_and_exit(int code, const std::string& error);
|
||||
|
||||
} // namespace http
|
||||
|
||||
#include "parse.hxx"
|
32
src/config/parse.hxx
Normal file
32
src/config/parse.hxx
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include "parse.hh"
|
||||
|
||||
namespace paxos
|
||||
{
|
||||
template <typename ValueType>
|
||||
bool safe_get_key(const json& json_obj, const std::string& key,
|
||||
ValueType& value, bool mandatory = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
json_obj.at(key).get_to(value);
|
||||
}
|
||||
catch (json::out_of_range& e)
|
||||
{
|
||||
if (mandatory)
|
||||
error_and_exit(1, "parse_configuration: mandatory key '"
|
||||
+ key + "' not found.");
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cout << e.what() << " in " << key << "\n";
|
||||
error_and_exit(1, "parse_configuration: key '" + key +
|
||||
"' is associated with a value of bad type");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // namespace http
|
15
src/error/connection-closed.hh
Normal file
15
src/error/connection-closed.hh
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
namespace http
|
||||
{
|
||||
struct ConnectionRecvClosedError: public std::system_error
|
||||
{
|
||||
explicit ConnectionRecvClosedError()
|
||||
: std::system_error{errno, std::system_category()}
|
||||
{}
|
||||
};
|
||||
} //namespace http
|
15
src/error/connection-failed.hh
Normal file
15
src/error/connection-failed.hh
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
namespace http
|
||||
{
|
||||
struct ConnectionFailed : public std::system_error
|
||||
{
|
||||
explicit ConnectionFailed()
|
||||
: std::system_error{errno, std::system_category()}
|
||||
{}
|
||||
};
|
||||
} //namespace http
|
15
src/error/init-error.hh
Normal file
15
src/error/init-error.hh
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace http
|
||||
{
|
||||
struct InitializationError : public std::logic_error
|
||||
{
|
||||
explicit InitializationError(const std::string& what_arg)
|
||||
: std::logic_error{"Initialization error: " + what_arg}
|
||||
{}
|
||||
virtual ~InitializationError() = default;
|
||||
};
|
||||
} // namespace http
|
15
src/error/not-implemented.hh
Normal file
15
src/error/not-implemented.hh
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace http
|
||||
{
|
||||
class NotImplemented : public std::logic_error
|
||||
{
|
||||
public:
|
||||
NotImplemented()
|
||||
: std::logic_error{"not implemented exception"}
|
||||
{}
|
||||
virtual ~NotImplemented() = default;
|
||||
};
|
||||
} // namespace http
|
15
src/error/parsing-error.hh
Normal file
15
src/error/parsing-error.hh
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace http
|
||||
{
|
||||
struct ParsingError : public std::logic_error
|
||||
{
|
||||
explicit ParsingError(const std::string& what_arg)
|
||||
: std::logic_error{"Parsing error: " + what_arg}
|
||||
{}
|
||||
virtual ~ParsingError() = default;
|
||||
};
|
||||
} // namespace http
|
0
src/legislator/legislator.cc
Normal file
0
src/legislator/legislator.cc
Normal file
12
src/legislator/legislator.hh
Normal file
12
src/legislator/legislator.hh
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "legislator-config.hh"
|
||||
|
||||
namespace paxos
|
||||
{
|
||||
class Legislator
|
||||
{
|
||||
public:
|
||||
LegislatorConfig config;
|
||||
|
||||
}
|
||||
}
|
11
src/main.cc
11
src/main.cc
@ -1,5 +1,10 @@
|
||||
int main(int argc, char **argv)
|
||||
#include <iostream>
|
||||
|
||||
#include "config/config.hh"
|
||||
|
||||
|
||||
int main(int, char **argv)
|
||||
{
|
||||
argv = argv;
|
||||
return argc;
|
||||
paxos::ServerConfig config = paxos::ServerConfig::parse(argv[1]);
|
||||
std::cout << config.legislators_[0].name << "\n";
|
||||
}
|
||||
|
15
src/misc/addrinfo/addrinfo-error.cc
Normal file
15
src/misc/addrinfo/addrinfo-error.cc
Normal file
@ -0,0 +1,15 @@
|
||||
#include "addrinfo-error.hh"
|
||||
|
||||
namespace misc
|
||||
{
|
||||
const std::error_category& addrinfo_category()
|
||||
{
|
||||
static addrinfo_error_category instance;
|
||||
return instance;
|
||||
}
|
||||
} // namespace misc
|
||||
|
||||
inline std::error_code std::make_error_code(misc::addrinfo_error e)
|
||||
{
|
||||
return std::error_code(static_cast<int>(e), misc::addrinfo_category());
|
||||
}
|
82
src/misc/addrinfo/addrinfo-error.hh
Normal file
82
src/misc/addrinfo/addrinfo-error.hh
Normal file
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* \file misc/addrinfo/addrinfo-error.hh
|
||||
* \brief Implementation of an extention to system_errors for addrinfo.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <netdb.h>
|
||||
#include <system_error>
|
||||
|
||||
namespace misc
|
||||
{
|
||||
/**
|
||||
* \enum addrinfo_error
|
||||
* \brief Possible errors returned by getaddrinfo.
|
||||
*/
|
||||
enum addrinfo_error
|
||||
{
|
||||
BADFLAGS = EAI_BADFLAGS,
|
||||
NONAME = EAI_NONAME,
|
||||
AGAIN = EAI_AGAIN,
|
||||
FAIL = EAI_FAIL,
|
||||
FAMILY = EAI_FAMILY,
|
||||
SOCKTYPE = EAI_SOCKTYPE,
|
||||
SERVICE = EAI_SERVICE,
|
||||
MEMORY = EAI_MEMORY,
|
||||
SYSTEM = EAI_SYSTEM,
|
||||
OVERFLOW = EAI_OVERFLOW,
|
||||
NODATA = EAI_NODATA,
|
||||
ADDRFAMILY = EAI_ADDRFAMILY,
|
||||
INPROGRESS = EAI_INPROGRESS,
|
||||
CANCELED = EAI_CANCELED,
|
||||
NOTCANCELED = EAI_NOTCANCELED,
|
||||
ALLDONE = EAI_ALLDONE,
|
||||
INTR = EAI_INTR,
|
||||
IDN_ENCODE = EAI_IDN_ENCODE,
|
||||
};
|
||||
|
||||
/**
|
||||
* \class addrinfo_error_category
|
||||
* \brief Error category signifying the system error coming from
|
||||
* getaddrinfo.
|
||||
*/
|
||||
class addrinfo_error_category : public std::error_category
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Name of the category.
|
||||
*/
|
||||
virtual const char* name() const noexcept override
|
||||
{
|
||||
return "addrinfo_error_category";
|
||||
}
|
||||
/**
|
||||
* \brief Error message.
|
||||
*/
|
||||
virtual std::string message(int value) const override
|
||||
{
|
||||
return gai_strerror(value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Singleton instance of the new error_category.
|
||||
*/
|
||||
const std::error_category& addrinfo_category();
|
||||
} // namespace misc
|
||||
|
||||
namespace std
|
||||
{
|
||||
/**
|
||||
* \brief Setup addrinfo_error to be used as error_codes.
|
||||
*/
|
||||
template <>
|
||||
struct is_error_code_enum<misc::addrinfo_error> : public std::true_type
|
||||
{};
|
||||
|
||||
/**
|
||||
* \brief Translation between addrinfo_errors and error_codes.
|
||||
*/
|
||||
inline std::error_code make_error_code(misc::addrinfo_error e);
|
||||
} // namespace std
|
102
src/misc/addrinfo/addrinfo-iterator.hh
Normal file
102
src/misc/addrinfo/addrinfo-iterator.hh
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* /file misc/addrinfo/addrinfo-iterator.hh
|
||||
* /brief Iterator over AddrInfo declaration.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <netdb.h>
|
||||
|
||||
namespace misc
|
||||
{
|
||||
/**
|
||||
* \class addrinfo_iterator
|
||||
* \brief Iterator over AddrInfo objects.
|
||||
*/
|
||||
template <class Value>
|
||||
class addrinfo_iter
|
||||
: public boost::iterator_facade<addrinfo_iter<Value>, Value,
|
||||
boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Default constructor (end iterator).
|
||||
*/
|
||||
addrinfo_iter()
|
||||
: m_node(nullptr)
|
||||
{}
|
||||
|
||||
/**
|
||||
* \brief Constructor from a given AddrInfo.
|
||||
* \param p Value* the AddrInfo
|
||||
*/
|
||||
explicit addrinfo_iter(Value* p)
|
||||
: m_node(p)
|
||||
{}
|
||||
|
||||
/**
|
||||
* \brief Begin of the iterator range.
|
||||
*/
|
||||
addrinfo_iter<Value> begin()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief End of the iterator range.
|
||||
*/
|
||||
addrinfo_iter<Value> end()
|
||||
{
|
||||
return addrinfo_iter<Value>{};
|
||||
}
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
/**
|
||||
* \brief Advance the iterator by one step.
|
||||
*/
|
||||
void increment()
|
||||
{
|
||||
m_node = m_node->ai_next;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check equality between iterators.
|
||||
*/
|
||||
bool equal(const addrinfo_iter<Value>& other) const
|
||||
{
|
||||
return this->m_node == other.m_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Access to the value through dereferenciation
|
||||
*/
|
||||
Value& dereference() const
|
||||
{
|
||||
return *m_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Begin of a given iterator.
|
||||
*/
|
||||
Value& begin(const addrinfo_iter<Value>& n)
|
||||
{
|
||||
return n->m_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Current value of the iterator.
|
||||
*/
|
||||
Value* m_node;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Alias to AddrInfo iterators type.
|
||||
*/
|
||||
using addrinfo_iterator = addrinfo_iter<addrinfo>;
|
||||
/**
|
||||
* \brief Alias to const AddrInfo iterators type.
|
||||
*/
|
||||
using addrinfo_const_iterator = addrinfo_iter<const addrinfo>;
|
||||
} // namespace misc
|
24
src/misc/addrinfo/addrinfo.cc
Normal file
24
src/misc/addrinfo/addrinfo.cc
Normal file
@ -0,0 +1,24 @@
|
||||
#include "addrinfo.hh"
|
||||
|
||||
namespace misc
|
||||
{
|
||||
AddrInfo getaddrinfo(const char* node, const char* service,
|
||||
const AddrInfoHint& hints)
|
||||
{
|
||||
struct addrinfo* res;
|
||||
|
||||
auto rc = ::getaddrinfo(node, service, &hints, &res);
|
||||
if (rc)
|
||||
throw std::system_error(rc, addrinfo_error_category(),
|
||||
"getaddrinfo");
|
||||
|
||||
return AddrInfo(res);
|
||||
}
|
||||
} // namespace misc
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const addrinfo&)
|
||||
{
|
||||
os << "addrinfo{"
|
||||
<< "}";
|
||||
return os;
|
||||
}
|
185
src/misc/addrinfo/addrinfo.hh
Normal file
185
src/misc/addrinfo/addrinfo.hh
Normal file
@ -0,0 +1,185 @@
|
||||
/**
|
||||
* \file misc/addrinfo/addrinfo.hh
|
||||
* \brief Structures used to wrap getaddrinfo(3).
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <utility>
|
||||
|
||||
#include "addrinfo-error.hh"
|
||||
#include "addrinfo-iterator.hh"
|
||||
|
||||
namespace misc
|
||||
{
|
||||
/**
|
||||
* \class AddrInfo
|
||||
* \brief Object representing list of network addresses (IP, Port, Host).
|
||||
*/
|
||||
class AddrInfo
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Constructor from an addrinfo struct.
|
||||
*/
|
||||
AddrInfo(::addrinfo* info)
|
||||
: info_{info}
|
||||
{}
|
||||
|
||||
~AddrInfo()
|
||||
{
|
||||
freeaddrinfo(info_);
|
||||
}
|
||||
|
||||
AddrInfo(const AddrInfo&) = delete;
|
||||
AddrInfo& operator=(const AddrInfo&) = delete;
|
||||
AddrInfo(AddrInfo&& addr)
|
||||
: info_{std::exchange(addr.info_, nullptr)}
|
||||
{}
|
||||
AddrInfo& operator=(AddrInfo&& addr)
|
||||
{
|
||||
freeaddrinfo(info_);
|
||||
info_ = std::exchange(addr.info_, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Begin of the list of addresses.
|
||||
*/
|
||||
addrinfo_iterator begin()
|
||||
{
|
||||
return addrinfo_iterator(info_);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Begin of the const list of addresses.
|
||||
*/
|
||||
addrinfo_const_iterator begin() const
|
||||
{
|
||||
return addrinfo_const_iterator(info_);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief End of the list of addresses.
|
||||
*/
|
||||
addrinfo_iterator end()
|
||||
{
|
||||
return addrinfo_iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief End of the const list of addresses.
|
||||
*/
|
||||
addrinfo_const_iterator end() const
|
||||
{
|
||||
return addrinfo_const_iterator();
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Addrinfo structure held by the object.
|
||||
*/
|
||||
::addrinfo* info_;
|
||||
};
|
||||
|
||||
/**
|
||||
* \class AddrInfoHint
|
||||
* \brief Builder class used to specify requirements about addresses
|
||||
* returned by getaddrinfo(3).
|
||||
*/
|
||||
struct AddrInfoHint : public ::addrinfo
|
||||
{
|
||||
AddrInfoHint()
|
||||
{
|
||||
memset(this, 0, sizeof(::addrinfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Specify the flag member of the structure.
|
||||
*/
|
||||
AddrInfoHint& flags(int val)
|
||||
{
|
||||
this->ai_flags = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Specify the family member of the structure.
|
||||
*/
|
||||
AddrInfoHint& family(int val)
|
||||
{
|
||||
this->ai_family = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Specify the socktype member of the structure.
|
||||
*/
|
||||
AddrInfoHint& socktype(int val)
|
||||
{
|
||||
this->ai_socktype = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Specify the protocol member of the structure.
|
||||
*/
|
||||
AddrInfoHint& protocol(int val)
|
||||
{
|
||||
this->ai_protocol = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Specify the member of the structure.
|
||||
*/
|
||||
AddrInfoHint& addrlen(socklen_t val)
|
||||
{
|
||||
this->ai_addrlen = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Specify the addr member of the structure.
|
||||
*/
|
||||
AddrInfoHint& addr(::sockaddr* val)
|
||||
{
|
||||
this->ai_addr = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Specify the canonname member of the structure.
|
||||
*/
|
||||
AddrInfoHint& canonname(char* val)
|
||||
{
|
||||
this->ai_canonname = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Specify the member next of the structure.
|
||||
*/
|
||||
AddrInfoHint& next(::addrinfo* val)
|
||||
{
|
||||
this->ai_next = val;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Wrapper around getaddrinfo(3).
|
||||
*/
|
||||
AddrInfo getaddrinfo(const char* node, const char* service,
|
||||
const AddrInfoHint& hints);
|
||||
} // namespace misc
|
||||
|
||||
/**
|
||||
* \brief Outputs the addrinfo to a stream.
|
||||
*
|
||||
* Only used for debug purposes.
|
||||
*/
|
||||
std::ostream& operator<<(std::ostream&, const ::addrinfo&);
|
113
src/misc/buffer.cc
Normal file
113
src/misc/buffer.cc
Normal file
@ -0,0 +1,113 @@
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
|
||||
#include "error/connection-closed.hh"
|
||||
#include "misc/buffer.hh"
|
||||
|
||||
namespace misc
|
||||
{
|
||||
constexpr size_t CRLF_LENGTH = 2;
|
||||
|
||||
constexpr size_t BUFF_SIZE = 8192;
|
||||
|
||||
Buffer::Buffer()
|
||||
{
|
||||
data_ = std::deque<std::string>(1);
|
||||
}
|
||||
|
||||
void Buffer::append(const std::string& tab)
|
||||
{
|
||||
size_t crlf_pos = tab.find("\r\n");
|
||||
data_.back() += tab.substr(0, crlf_pos);
|
||||
size_t line_begin = crlf_pos + CRLF_LENGTH;
|
||||
|
||||
while (crlf_pos != tab.npos && line_begin < tab.size())
|
||||
{
|
||||
data_.back() += "\r\n";
|
||||
|
||||
crlf_pos = tab.find("\r\n", line_begin);
|
||||
|
||||
data_.emplace_back(tab, line_begin, crlf_pos - line_begin);
|
||||
|
||||
line_begin = crlf_pos + CRLF_LENGTH;
|
||||
}
|
||||
|
||||
if (crlf_pos != tab.npos && line_begin == tab.size())
|
||||
{
|
||||
data_.back() += "\r\n";
|
||||
data_.emplace_back();
|
||||
}
|
||||
}
|
||||
|
||||
size_t Buffer::receive(http::Socket& socket)
|
||||
{
|
||||
char buf[BUFF_SIZE];
|
||||
ssize_t n = socket.recv(buf, BUFF_SIZE);
|
||||
if (n == 0)
|
||||
throw http::ConnectionRecvClosedError();
|
||||
if (n == -1)
|
||||
return 0;
|
||||
|
||||
auto str = std::string(buf, n);
|
||||
|
||||
this->append(str);
|
||||
return n;
|
||||
}
|
||||
|
||||
std::string Buffer::popline()
|
||||
{
|
||||
if (this->empty())
|
||||
throw std::logic_error("Buffer::popline : pop in a empty Buffer");
|
||||
|
||||
std::string toReturn = data_.front();
|
||||
data_.pop_front();
|
||||
if (data_.size() == 0)
|
||||
data_.emplace_back();
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
void Buffer::pop_front(size_t content_length)
|
||||
{
|
||||
while (data_.front().size() < content_length)
|
||||
{
|
||||
content_length -= data_.front().size();
|
||||
data_.pop_front();
|
||||
}
|
||||
data_.front() = data_.front().substr(content_length);
|
||||
if (data_.front().empty() && data_.size() > 1)
|
||||
data_.pop_front();
|
||||
}
|
||||
|
||||
bool Buffer::empty() const
|
||||
{
|
||||
return this->get_nb_lines() == 0 && data_.back().empty();
|
||||
}
|
||||
|
||||
const std::string& Buffer::getline(size_t line) const
|
||||
{
|
||||
try
|
||||
{
|
||||
return data_[line];
|
||||
}
|
||||
catch (const std::out_of_range& e)
|
||||
{
|
||||
std::cerr << "[Buffer::getline(size_t line)] "
|
||||
<< line << "out of " << data_.size();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Buffer::get_nb_lines() const
|
||||
{
|
||||
return data_.size() - 1;
|
||||
}
|
||||
|
||||
std::string Buffer::to_string() const
|
||||
{
|
||||
std::string str;
|
||||
for (auto line : data_)
|
||||
str += line;
|
||||
return str;
|
||||
}
|
||||
}
|
49
src/misc/buffer.hh
Normal file
49
src/misc/buffer.hh
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
#include "socket/default-socket.hh"
|
||||
|
||||
namespace misc
|
||||
{
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
Buffer();
|
||||
|
||||
~Buffer() = default;
|
||||
Buffer(const Buffer&) = default;
|
||||
Buffer& operator=(const Buffer&) = default;
|
||||
|
||||
/**
|
||||
** \brief Append parsed tab on CRLF characters in data_.
|
||||
** \param tab The buffer received from Socket::recv() to parse.
|
||||
*/
|
||||
void append(const std::string& tab);
|
||||
|
||||
/**
|
||||
** \brief Call the socket recv method and append to the buffer
|
||||
** \param socket The default socket
|
||||
*/
|
||||
size_t receive(http::Socket& socket);
|
||||
|
||||
/**
|
||||
** \brief Pop the string in front of data_ and returns it.
|
||||
*/
|
||||
std::string popline();
|
||||
|
||||
void pop_front(size_t content_length);
|
||||
|
||||
bool empty() const;
|
||||
|
||||
const std::string& getline(size_t line) const;
|
||||
|
||||
size_t get_nb_lines() const;
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
private:
|
||||
std::deque<std::string> data_;
|
||||
};
|
||||
}
|
42
src/misc/fd.cc
Normal file
42
src/misc/fd.cc
Normal file
@ -0,0 +1,42 @@
|
||||
#include "misc/fd.hh"
|
||||
|
||||
#include "misc/socket.hh"
|
||||
#include "misc/unistd.hh"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace misc
|
||||
{
|
||||
FileDescriptor& FileDescriptor::operator=(FileDescriptor&& fileDescriptor)
|
||||
{
|
||||
if (fd_ != -1)
|
||||
sys::close(fd_);
|
||||
fd_ = std::exchange(fileDescriptor.fd_, -1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FileDescriptor::~FileDescriptor()
|
||||
{
|
||||
if (*this)
|
||||
{
|
||||
sys::close(fd_);
|
||||
std::cerr << "Closed " << fd_ << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
FileDescriptor::operator int() const&
|
||||
{
|
||||
return fd_;
|
||||
}
|
||||
|
||||
FileDescriptor::operator bool() const&
|
||||
{
|
||||
return fd_ >= 0;
|
||||
}
|
||||
|
||||
void FileDescriptor::fcntl_set(int flags)
|
||||
{
|
||||
sys::fcntl_set(fd_, flags);
|
||||
}
|
||||
|
||||
} // namespace misc
|
70
src/misc/fd.hh
Normal file
70
src/misc/fd.hh
Normal file
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* \file misc/fd.hh
|
||||
* \brief FileDescriptor declaration.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
#include <unistd.h>
|
||||
#include <utility>
|
||||
|
||||
#include "misc/sys-wrapper.hh"
|
||||
|
||||
namespace misc
|
||||
{
|
||||
/**
|
||||
* \class FileDescriptor
|
||||
* \brief A resource object representing a fd.
|
||||
*/
|
||||
struct FileDescriptor
|
||||
{
|
||||
/**
|
||||
* \brief Construct a FileDescriptor from a given fd.
|
||||
* \param fd int
|
||||
*/
|
||||
|
||||
explicit FileDescriptor(int fd)
|
||||
: fd_{fd}
|
||||
{}
|
||||
|
||||
FileDescriptor() = default;
|
||||
FileDescriptor(const FileDescriptor&) = delete;
|
||||
FileDescriptor& operator=(const FileDescriptor&) = delete;
|
||||
|
||||
FileDescriptor(FileDescriptor&& fileDescriptor)
|
||||
: fd_{std::exchange(fileDescriptor.fd_, -1)}
|
||||
{}
|
||||
FileDescriptor& operator=(FileDescriptor&& fileDescriptor);
|
||||
|
||||
~FileDescriptor();
|
||||
|
||||
/**
|
||||
* \brief Implicit conversion to int.
|
||||
*/
|
||||
operator int() const&;
|
||||
|
||||
/**
|
||||
* \brief Implicit conversion to bool.
|
||||
*
|
||||
* \return Whether or not the FileDescriptor holds a valid fd.
|
||||
*/
|
||||
operator bool() const&;
|
||||
|
||||
/**
|
||||
* \brief man 2 fcntl
|
||||
*/
|
||||
void fcntl_set(int flags);
|
||||
|
||||
/**
|
||||
* \brief The fd held by the FileDescriptor object.
|
||||
*/
|
||||
int fd_ = -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Alias to the smart pointer used to manage FileDescriptors
|
||||
* memory allocation.
|
||||
*/
|
||||
using shared_fd = std::shared_ptr<FileDescriptor>;
|
||||
} // namespace misc
|
13
src/misc/json.hh
Normal file
13
src/misc/json.hh
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||
#pragma GCC diagnostic ignored "-Wswitch-default"
|
||||
#pragma GCC diagnostic ignored "-Winline"
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op-parentheses"
|
||||
#endif
|
||||
#include <json.hpp>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
using json = nlohmann::json;
|
11
src/misc/logger.cc
Normal file
11
src/misc/logger.cc
Normal file
@ -0,0 +1,11 @@
|
||||
#include "logger.hh"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace http
|
||||
{
|
||||
void log(std::string str, Color color)
|
||||
{
|
||||
std::cout << "\033[1;" + std::to_string(color) + "m" + str + "\033[0m\n";
|
||||
}
|
||||
} // namespace http
|
20
src/misc/logger.hh
Normal file
20
src/misc/logger.hh
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace http
|
||||
{
|
||||
enum Color
|
||||
{
|
||||
black = 30,
|
||||
red = 31,
|
||||
green = 32,
|
||||
yellow = 33,
|
||||
blue = 34,
|
||||
magenta = 35,
|
||||
cyan = 36,
|
||||
white = 37
|
||||
};
|
||||
|
||||
void log(std::string str, Color color);
|
||||
} // namespace http
|
100
src/misc/socket.hh
Normal file
100
src/misc/socket.hh
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* \file misc/socket.hh
|
||||
* \brief Socket related syscalls.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "misc/fd.hh"
|
||||
#include "misc/sys-wrapper.hh"
|
||||
|
||||
namespace sys
|
||||
{
|
||||
/**
|
||||
* \brief accept(2).
|
||||
*/
|
||||
inline auto accept = make_wrapper<misc::FileDescriptor>(::accept);
|
||||
|
||||
/**
|
||||
* \brief bind(2).
|
||||
*/
|
||||
inline auto bind = make_wrapper<void>(::bind);
|
||||
|
||||
/**
|
||||
* \brief connect(2).
|
||||
*/
|
||||
inline auto connect = make_wrapper<void>(::connect);
|
||||
|
||||
static int fcntl_wrapper(int fildes, int opts)
|
||||
{
|
||||
auto flags = ::fcntl(fildes, F_GETFL);
|
||||
return ::fcntl(fildes, F_SETFL, flags | opts);
|
||||
}
|
||||
/**
|
||||
* \brief fcntl(2).
|
||||
*
|
||||
* Since fcntl is a variadic syscall we need to call a helper function
|
||||
* with a fixed number of parameter to create a wrapper out of it.
|
||||
*/
|
||||
inline auto fcntl_set = make_wrapper<int>(fcntl_wrapper);
|
||||
|
||||
/**
|
||||
* \brief getsockname(2).
|
||||
*/
|
||||
inline auto getsockname = make_wrapper<void>(::getsockname);
|
||||
|
||||
/**
|
||||
* \brief listen(2).
|
||||
*/
|
||||
inline auto listen = make_wrapper<void>(::listen);
|
||||
|
||||
/**
|
||||
* \brief lseek(2).
|
||||
*/
|
||||
inline auto lseek = make_wrapper<off_t>(::lseek);
|
||||
|
||||
/**
|
||||
* \brief read(2).
|
||||
*/
|
||||
inline auto read = make_wrapper<ssize_t>(::read);
|
||||
|
||||
/**
|
||||
* \brief recv(2).
|
||||
*/
|
||||
inline auto recv = make_wrapper<ssize_t>(::recv);
|
||||
|
||||
/**
|
||||
* \brief send(2).
|
||||
*/
|
||||
inline auto send = make_wrapper<ssize_t>(::send);
|
||||
|
||||
/**
|
||||
* \brief sendfile(2).
|
||||
*/
|
||||
inline auto sendfile = make_wrapper<ssize_t>(::sendfile);
|
||||
|
||||
/**
|
||||
* \brief setsockopt(2).
|
||||
*/
|
||||
inline auto setsockopt = make_wrapper<void>(::setsockopt);
|
||||
|
||||
/**
|
||||
* \brief getsockopt(2).
|
||||
*/
|
||||
inline auto getsockopt = make_wrapper<void>(::getsockopt);
|
||||
|
||||
/**
|
||||
* \brief socket(2).
|
||||
*/
|
||||
inline auto socket = make_wrapper<misc::FileDescriptor>(::socket);
|
||||
|
||||
/**
|
||||
* \brief getpeername(2).
|
||||
*/
|
||||
inline auto getpeername = make_wrapper<void>(::getpeername);
|
||||
} // namespace sys
|
63
src/misc/sys-wrapper.hh
Normal file
63
src/misc/sys-wrapper.hh
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* \file misc/sys-wrapper.hh
|
||||
* \brief SysWrapper declaration.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
|
||||
namespace sys
|
||||
{
|
||||
/**
|
||||
* \class SysWrapper
|
||||
* \brief Wrapping around syscalls to convert failure into exceptions.
|
||||
*
|
||||
* Wrapping syscalls this way helps to insure the RAII idiom.
|
||||
*/
|
||||
template <typename RetType, typename SysRetType, typename... Args>
|
||||
class SysWrapper
|
||||
{
|
||||
public:
|
||||
SysWrapper(SysRetType syscall(Args...))
|
||||
: syscall_{syscall}
|
||||
{}
|
||||
|
||||
/* Needs template to enable universal referencing.
|
||||
Template deduction should be done automatically. */
|
||||
template <typename... UniversalArgs>
|
||||
RetType operator()(UniversalArgs&&... args)
|
||||
{
|
||||
SysRetType ret;
|
||||
|
||||
do
|
||||
{
|
||||
errno = 0;
|
||||
ret = syscall_(std::forward<UniversalArgs>(args)...);
|
||||
} while (errno == EINTR);
|
||||
|
||||
if (ret == SysRetType(-1) && errno != EWOULDBLOCK
|
||||
&& errno != EAGAIN)
|
||||
{
|
||||
throw std::system_error(errno, std::system_category());
|
||||
}
|
||||
|
||||
return RetType(ret);
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<SysRetType(Args...)> syscall_;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Helper function to build SysWrapper.
|
||||
*/
|
||||
template <typename RetType, typename SysRetType, typename... Args>
|
||||
SysWrapper<RetType, SysRetType, Args...>
|
||||
make_wrapper(SysRetType syscall(Args...))
|
||||
{
|
||||
return SysWrapper<RetType, SysRetType, Args...>(syscall);
|
||||
}
|
||||
} // namespace sys
|
55
src/misc/unistd.hh
Normal file
55
src/misc/unistd.hh
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* \file misc/unistd.hh
|
||||
* \brief unistd.h syscall wrappers.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "misc/fd.hh"
|
||||
#include "misc/sys-wrapper.hh"
|
||||
|
||||
namespace sys
|
||||
{
|
||||
/**
|
||||
* \brief close(2).
|
||||
*/
|
||||
inline auto close = make_wrapper<void>(::close);
|
||||
|
||||
/**
|
||||
* \brief fork(2).
|
||||
*/
|
||||
inline auto fork = make_wrapper<pid_t>(::fork);
|
||||
|
||||
/**
|
||||
* \brief fstat(2).
|
||||
*/
|
||||
inline auto fstat = make_wrapper<int>(::fstat);
|
||||
|
||||
/**
|
||||
* \brief kill(2).
|
||||
*/
|
||||
inline auto kill = make_wrapper<void>(::kill);
|
||||
|
||||
static int open_wrapper(const char* path, int flags)
|
||||
{
|
||||
return ::open(path, flags);
|
||||
}
|
||||
/**
|
||||
* \brief open(2).
|
||||
*
|
||||
* Since open is a variadic syscall we need to call a helper with a
|
||||
* fixed number of parameters to create a wrapper out of it.
|
||||
*/
|
||||
inline auto open = make_wrapper<misc::FileDescriptor>(open_wrapper);
|
||||
|
||||
/**
|
||||
* \brief wait(2).
|
||||
*/
|
||||
inline auto waitpid = make_wrapper<void>(::waitpid);
|
||||
} // namespace sys
|
81
src/socket/default-socket.cc
Normal file
81
src/socket/default-socket.cc
Normal file
@ -0,0 +1,81 @@
|
||||
#include <cerrno>
|
||||
|
||||
#include "socket/default-socket.hh"
|
||||
#include "misc/socket.hh"
|
||||
#include "misc/unistd.hh"
|
||||
#include "error/connection-closed.hh"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace paxos
|
||||
{
|
||||
DefaultSocket::DefaultSocket(const misc::shared_fd& fd)
|
||||
: Socket(fd)
|
||||
{}
|
||||
|
||||
DefaultSocket::DefaultSocket(int domain, int type, int protocol)
|
||||
: Socket{std::make_shared<misc::FileDescriptor>(
|
||||
sys::socket(domain, type, protocol))}
|
||||
{
|
||||
}
|
||||
|
||||
void DefaultSocket::listen(int backlog)
|
||||
{
|
||||
sys::listen(*fd_, backlog);
|
||||
}
|
||||
|
||||
ssize_t DefaultSocket::recv(void* dst, size_t len)
|
||||
{
|
||||
return sys::recv(*fd_, dst, len, MSG_NOSIGNAL);
|
||||
}
|
||||
|
||||
ssize_t DefaultSocket::send(const void* src, size_t len)
|
||||
{
|
||||
return sys::send(*fd_, src, len, MSG_NOSIGNAL);
|
||||
}
|
||||
|
||||
ssize_t DefaultSocket::sendfile(misc::shared_fd& fd, off_t& offset, size_t len)
|
||||
{
|
||||
return sys::sendfile(*fd_, *fd, &offset, len);
|
||||
}
|
||||
|
||||
void DefaultSocket::bind(const sockaddr* addr, socklen_t addrlen)
|
||||
{
|
||||
sys::bind(*fd_, addr, addrlen);
|
||||
}
|
||||
|
||||
void DefaultSocket::fcntl_set_O_NONBLOCK()
|
||||
{
|
||||
fd_->fcntl_set(O_NONBLOCK);
|
||||
}
|
||||
|
||||
void DefaultSocket::setsockopt(int level, int optname, int optval)
|
||||
{
|
||||
sys::setsockopt(*fd_, level, optname, &optval, sizeof(int));
|
||||
}
|
||||
|
||||
void DefaultSocket::getsockopt(int level, int optname, int& optval)
|
||||
{
|
||||
unsigned int optlen;
|
||||
sys::getsockopt(*fd_, level, optname, &optval, &optlen);
|
||||
}
|
||||
|
||||
shared_socket DefaultSocket::accept(sockaddr* addr, socklen_t* addrlen)
|
||||
{
|
||||
misc::shared_fd client_fd = std::make_shared<misc::FileDescriptor>(sys::accept(*fd_, addr, addrlen));
|
||||
|
||||
auto ret = std::make_shared<DefaultSocket>(client_fd);
|
||||
|
||||
//Set the ip and listener_port of the accepted socket
|
||||
ret->set_listener_port(port_);
|
||||
ret->set_ip(ip_);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DefaultSocket::connect(const sockaddr* addr, socklen_t len)
|
||||
{
|
||||
sys::connect(*fd_, addr, len);
|
||||
}
|
||||
|
||||
// Implement all other methods (see header).
|
||||
} // namespace http
|
49
src/socket/default-socket.hh
Normal file
49
src/socket/default-socket.hh
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* \file socket/default_socket.hh
|
||||
* \brief DefaultSocket declaration.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "misc/socket.hh"
|
||||
#include "socket/socket.hh"
|
||||
|
||||
namespace paxos
|
||||
{
|
||||
/**
|
||||
* \struct DefaultSocket
|
||||
* \brief Implementation of the Socket interface.
|
||||
*/
|
||||
struct DefaultSocket : public Socket
|
||||
{
|
||||
explicit DefaultSocket(const misc::shared_fd&);
|
||||
DefaultSocket(int domain, int type, int protocol);
|
||||
|
||||
DefaultSocket() = default;
|
||||
DefaultSocket(const DefaultSocket&) = delete;
|
||||
DefaultSocket& operator=(const DefaultSocket&) = delete;
|
||||
DefaultSocket(DefaultSocket&&) = default;
|
||||
DefaultSocket& operator=(DefaultSocket&&) = default;
|
||||
~DefaultSocket() = default;
|
||||
|
||||
ssize_t recv(void* dst, size_t len) final;
|
||||
|
||||
ssize_t send(const void* src, size_t len) final;
|
||||
|
||||
ssize_t sendfile(misc::shared_fd& fd, off_t& offset, size_t len) final;
|
||||
|
||||
void bind(const sockaddr* addr, socklen_t addrlen) final;
|
||||
|
||||
void listen(int backlog) final;
|
||||
|
||||
void fcntl_set_O_NONBLOCK() final;
|
||||
|
||||
void setsockopt(int level, int optname, int optval) final;
|
||||
|
||||
void getsockopt(int level, int optname, int& optval) final;
|
||||
|
||||
shared_socket accept(sockaddr* addr, socklen_t* addrlen) final;
|
||||
|
||||
void connect(const sockaddr*, socklen_t) final;
|
||||
};
|
||||
} // namespace http
|
189
src/socket/socket.hh
Normal file
189
src/socket/socket.hh
Normal file
@ -0,0 +1,189 @@
|
||||
/**
|
||||
* \file socket/socket.hh
|
||||
* \brief Socket declaration.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "misc/fd.hh"
|
||||
#include "misc/socket.hh"
|
||||
|
||||
namespace paxos
|
||||
{
|
||||
/**
|
||||
* \struct Socket
|
||||
* \brief Value object representing a socket.
|
||||
*
|
||||
* socket(7)
|
||||
*/
|
||||
struct Socket
|
||||
{
|
||||
/**
|
||||
* \brief Create a Socket from a fd.
|
||||
*/
|
||||
explicit Socket(const misc::shared_fd& fd)
|
||||
: fd_{fd}
|
||||
{}
|
||||
|
||||
Socket() = default;
|
||||
Socket(const Socket&) = delete;
|
||||
Socket& operator=(const Socket&) = delete;
|
||||
Socket(Socket&&) = default;
|
||||
Socket& operator=(Socket&&) = default;
|
||||
virtual ~Socket() = default;
|
||||
|
||||
/**
|
||||
* \brief recv(2).
|
||||
*/
|
||||
virtual ssize_t recv(void* dst, size_t len) = 0;
|
||||
|
||||
/**
|
||||
* \brief send(2).
|
||||
*/
|
||||
virtual ssize_t send(const void* src, size_t len) = 0;
|
||||
|
||||
/**
|
||||
* \brief sendfile(2).
|
||||
*/
|
||||
virtual ssize_t sendfile(misc::shared_fd&, off_t&, size_t) = 0;
|
||||
|
||||
/**
|
||||
* \brief bind(2).
|
||||
*/
|
||||
virtual void bind(const sockaddr* addr, socklen_t addrlen) = 0;
|
||||
|
||||
/**
|
||||
* \brief listen(2).
|
||||
*/
|
||||
virtual void listen(int backlog) = 0;
|
||||
|
||||
/**
|
||||
* \brief fcntl(2). Demander aux yaka
|
||||
*/
|
||||
virtual void fcntl_set_O_NONBLOCK() = 0;
|
||||
|
||||
/**
|
||||
* \brief setsockopt(2).
|
||||
*/
|
||||
virtual void setsockopt(int level, int optname, int optval) = 0;
|
||||
|
||||
/**
|
||||
* \brief getsockopt(2).
|
||||
*/
|
||||
virtual void getsockopt(int level, int optname, int& optval) = 0;
|
||||
|
||||
/**
|
||||
* \brief accept(2).
|
||||
*/
|
||||
virtual std::shared_ptr<Socket> accept(sockaddr* addr,
|
||||
socklen_t* addrlen) = 0;
|
||||
|
||||
|
||||
std::string getsockname() const
|
||||
{
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
struct sockaddr_in6 addr;
|
||||
bzero(&addr, sizeof(struct sockaddr_in6));
|
||||
unsigned int len = sizeof(struct sockaddr_in6);
|
||||
sys::getsockname(fd_->fd_, (struct sockaddr *) &addr, &len);
|
||||
if (addr.sin6_family == AF_INET6)
|
||||
inet_ntop(addr.sin6_family, &addr.sin6_addr, ip,
|
||||
INET6_ADDRSTRLEN);
|
||||
else
|
||||
inet_ntop(addr.sin6_family,
|
||||
&((struct sockaddr_in *)&addr)->sin_addr, ip,
|
||||
INET6_ADDRSTRLEN);
|
||||
return ip;
|
||||
}
|
||||
|
||||
std::string getpeername()
|
||||
{
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
struct sockaddr_in6 addr;
|
||||
bzero(&addr, sizeof(struct sockaddr_in6));
|
||||
unsigned int len = sizeof(struct sockaddr_in6);
|
||||
sys::getpeername(fd_->fd_, (struct sockaddr *) &addr, &len);
|
||||
if (addr.sin6_family == AF_INET6)
|
||||
inet_ntop(addr.sin6_family, &addr.sin6_addr, ip,
|
||||
INET6_ADDRSTRLEN);
|
||||
else
|
||||
inet_ntop(addr.sin6_family,
|
||||
&((struct sockaddr_in *)&addr)->sin_addr, ip,
|
||||
INET6_ADDRSTRLEN);
|
||||
return ip;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \brief connect(2).
|
||||
*/
|
||||
virtual void connect(const sockaddr*, socklen_t) = 0;
|
||||
|
||||
const misc::shared_fd fd_get() const noexcept
|
||||
{
|
||||
return fd_;
|
||||
}
|
||||
|
||||
|
||||
const std::string& get_port() const
|
||||
{
|
||||
return port_;
|
||||
}
|
||||
|
||||
void set_port(const std::string& port)
|
||||
{
|
||||
port_ = port;
|
||||
}
|
||||
|
||||
const std::string& get_listener_port() const
|
||||
{
|
||||
return listener_port_;
|
||||
}
|
||||
|
||||
void set_listener_port(const std::string& listener_port)
|
||||
{
|
||||
listener_port_ = listener_port;
|
||||
}
|
||||
|
||||
const std::string& get_ip() const
|
||||
{
|
||||
return ip_;
|
||||
}
|
||||
|
||||
void set_ip(const std::string& ip)
|
||||
{
|
||||
ip_ = ip;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief File descriptor of the socket.
|
||||
*/
|
||||
misc::shared_fd fd_;
|
||||
|
||||
/**
|
||||
* \brief The port of the socket
|
||||
*/
|
||||
std::string port_;
|
||||
|
||||
/**
|
||||
* \brief The port of the listening socket which accepted this socket
|
||||
*/
|
||||
std::string listener_port_;
|
||||
|
||||
/**
|
||||
* \brief The ip of the socket
|
||||
*/
|
||||
std::string ip_;
|
||||
};
|
||||
|
||||
using shared_socket = std::shared_ptr<Socket>;
|
||||
} // namespace http
|
Loading…
Reference in New Issue
Block a user