Unverified Commit f95f215e authored by Joseph Noir's avatar Joseph Noir Committed by GitHub

Merge pull request #726

Add URI class, close #708
parents f97a71eb ed94c0e0
...@@ -65,6 +65,10 @@ set(LIBCAF_CORE_SRCS ...@@ -65,6 +65,10 @@ set(LIBCAF_CORE_SRCS
src/inbound_path.cpp src/inbound_path.cpp
src/ini_consumer.cpp src/ini_consumer.cpp
src/invoke_result_visitor.cpp src/invoke_result_visitor.cpp
src/ipv4_address.cpp
src/ipv4_subnet.cpp
src/ipv6_address.cpp
src/ipv6_subnet.cpp
src/local_actor.cpp src/local_actor.cpp
src/logger.cpp src/logger.cpp
src/mailbox_element.cpp src/mailbox_element.cpp
...@@ -118,6 +122,9 @@ set(LIBCAF_CORE_SRCS ...@@ -118,6 +122,9 @@ set(LIBCAF_CORE_SRCS
src/type_erased_value.cpp src/type_erased_value.cpp
src/uniform_type_info_map.cpp src/uniform_type_info_map.cpp
src/unprofiled.cpp src/unprofiled.cpp
src/uri.cpp
src/uri_builder.cpp
src/uri_impl.cpp
src/work_sharing.cpp src/work_sharing.cpp
src/work_stealing.cpp src/work_stealing.cpp
) )
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <cstring>
#include "caf/config.hpp"
#include "caf/detail/comparable.hpp"
namespace caf {
/// Base type for addresses based on a byte representation such as IP or
/// Ethernet addresses.
template <class Derived>
class byte_address : detail::comparable<Derived> {
public:
// -- element access ---------------------------------------------------------
/// Returns the byte at given index.
uint8_t& operator[](size_t index) noexcept {
return dref().bytes()[index];
}
/// Returns the byte at given index.
const uint8_t& operator[](size_t index) const noexcept {
return dref().bytes()[index];
}
// -- properties -------------------------------------------------------------
/// Returns the number of bytes of the address.
size_t size() const noexcept {
return dref().bytes().size();
}
// -- comparison -------------------------------------------------------------
/// Returns a negative number if `*this < other`, zero if `*this == other`
/// and a positive number if `*this > other`.
int compare(const Derived& other) const noexcept {
auto& buf = dref().bytes();
return memcmp(buf.data(), other.bytes().data(), Derived::num_bytes);
}
// -- transformations --------------------------------------------------------
Derived network_address(size_t prefix_length) const noexcept {
static constexpr uint8_t netmask_tbl[] = {0x00, 0x80, 0xC0, 0xE0,
0xF0, 0xF8, 0xFC, 0xFE};
prefix_length = std::min(prefix_length, Derived::num_bytes * 8);
Derived netmask;
auto bytes_to_keep = prefix_length / 8;
auto remainder = prefix_length % 8;
size_t i = 0;
for (; i < bytes_to_keep; ++i)
netmask[i] = 0xFF;
if (remainder != 0)
netmask[i] = netmask_tbl[remainder];
Derived result{dref()};
result &= netmask;
return result;
}
// -- bitwise member operators -----------------------------------------------
/// Bitwise ANDs `*this` and `other`.
Derived& operator&=(const Derived& other) {
auto& buf = dref().bytes();
for (size_t index = 0; index < Derived::num_bytes; ++index)
buf[index] &= other[index];
return dref();
}
/// Bitwise ORs `*this` and `other`.
Derived& operator|=(const Derived& other) {
auto& buf = dref().bytes();
for (size_t index = 0; index < Derived::num_bytes; ++index)
buf[index] |= other[index];
return dref();
}
/// Bitwise XORs `*this` and `other`.
Derived& operator^=(const Derived& other) {
auto& buf = dref().bytes();
for (size_t index = 0; index < Derived::num_bytes; ++index)
buf[index] ^= other[index];
return dref();
}
// -- bitwise free operators -------------------------------------------------
friend Derived operator&(const Derived& x, const Derived& y) {
Derived result{x};
result &= y;
return result;
}
friend Derived operator|(const Derived& x, const Derived& y) {
Derived result{x};
result |= y;
return result;
}
friend Derived operator^(const Derived& x, const Derived& y) {
Derived result{x};
result ^= y;
return result;
}
private:
Derived& dref() noexcept {
return *static_cast<Derived*>(this);
}
const Derived& dref() const noexcept {
return *static_cast<const Derived*>(this);
}
};
} // namespace caf
...@@ -136,7 +136,11 @@ ...@@ -136,7 +136,11 @@
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
# define CAF_POP_WARNINGS \ # define CAF_POP_WARNINGS \
_Pragma("GCC diagnostic pop") _Pragma("GCC diagnostic pop")
# define CAF_ANNOTATE_FALLTHROUGH static_cast<void>(0) # if __GNUC__ >= 7
# define CAF_ANNOTATE_FALLTHROUGH __attribute__((fallthrough))
# else
# define CAF_ANNOTATE_FALLTHROUGH static_cast<void>(0)
# endif
# define CAF_COMPILER_VERSION \ # define CAF_COMPILER_VERSION \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
// disable thread_local on GCC/macOS due to heap-use-after-free bug: // disable thread_local on GCC/macOS due to heap-use-after-free bug:
......
...@@ -37,39 +37,65 @@ ...@@ -37,39 +37,65 @@
ps.code = caf::pec::unexpected_eof; \ ps.code = caf::pec::unexpected_eof; \
return; \ return; \
{ \ { \
static constexpr auto mismatch_ec = caf::pec::unexpected_character static_cast<void>(0); // dummy; init state closes parentheses
/// Defines a non-terminal state in the FSM. /// Defines a non-terminal state in the FSM.
#define state(name) \ #define state(name) \
CAF_FSM_EVAL_MISMATCH_EC \
} \ } \
{ \ for (;;) { \
static constexpr auto mismatch_ec = caf::pec::unexpected_character; \ /* jumps back up here if no transition matches */ \
ps.code = ch != '\n' ? caf::pec::unexpected_character \
: caf::pec::unexpected_newline; \
return; \
s_##name : \ s_##name : \
if (ch == '\0') \ if (ch == '\0') \
goto s_unexpected_eof; \ goto s_unexpected_eof; \
e_##name : e_##name :
/// Defines a terminal state in the FSM. /// Defines a state in the FSM that doesn't check for end-of-input. Unstable
#define term_state(name) \ /// states must make a transition and cause undefined behavior otherwise.
CAF_FSM_EVAL_MISMATCH_EC \ #define unstable_state(name) \
} \ } \
{ \ { \
static constexpr auto mismatch_ec = caf::pec::trailing_character; \
s_##name : \ s_##name : \
if (ch == '\0') \
goto s_fin; \
e_##name : e_##name :
/// Ends the definition of an FSM. /// Ends the definition of an FSM.
#define fin() \ #define fin() \
CAF_FSM_EVAL_MISMATCH_EC \
} \ } \
s_fin: \ s_fin: \
ps.code = caf::pec::success; \ ps.code = caf::pec::success; \
return; return;
/// Defines a terminal state in the FSM.
#define CAF_TERM_STATE_IMPL1(name) \
} \
for (;;) { \
/* jumps back up here if no transition matches */ \
ps.code = caf::pec::trailing_character; \
return; \
s_##name : \
if (ch == '\0') \
goto s_fin; \
e_##name :
/// Defines a terminal state in the FSM that runs `exit_statement` when leaving
/// the state with code `pec::success` or `pec::trailing_character`.
#define CAF_TERM_STATE_IMPL2(name, exit_statement) \
} \
for (;;) { \
/* jumps back up here if no transition matches */ \
ps.code = caf::pec::trailing_character; \
exit_statement; \
return; \
s_##name : \
if (ch == '\0') { \
exit_statement; \
goto s_fin; \
} \
e_##name :
#define CAF_TRANSITION_IMPL1(target) \ #define CAF_TRANSITION_IMPL1(target) \
ch = ps.next(); \ ch = ps.next(); \
goto s_##target; goto s_##target;
...@@ -184,6 +210,11 @@ ...@@ -184,6 +210,11 @@
#ifdef CAF_MSVC #ifdef CAF_MSVC
/// Defines a terminal state in the FSM.
#define term_state(...) \
CAF_PP_CAT(CAF_PP_OVERLOAD(CAF_TERM_STATE_IMPL, __VA_ARGS__)(__VA_ARGS__), \
CAF_PP_EMPTY())
/// Transitions to target state if a predicate (optional argument 1) holds for /// Transitions to target state if a predicate (optional argument 1) holds for
/// the current token and executes an action (optional argument 2) before /// the current token and executes an action (optional argument 2) before
/// entering the new state. /// entering the new state.
...@@ -214,6 +245,10 @@ ...@@ -214,6 +245,10 @@
#else // CAF_MSVC #else // CAF_MSVC
/// Defines a terminal state in the FSM.
#define term_state(...) \
CAF_PP_OVERLOAD(CAF_TERM_STATE_IMPL, __VA_ARGS__)(__VA_ARGS__)
/// Transitions to target state if a predicate (optional argument 1) holds for /// Transitions to target state if a predicate (optional argument 1) holds for
/// the current token and executes an action (optional argument 2) before /// the current token and executes an action (optional argument 2) before
/// entering the new state. /// entering the new state.
...@@ -238,7 +273,13 @@ ...@@ -238,7 +273,13 @@
#endif // CAF_MSVC #endif // CAF_MSVC
// Makes an epsiolon transition into another state if the `statement` is true. /// Makes a transition into another state if the `statement` is true.
#define transition_if(statement, ...) \
if (statement) { \
transition(__VA_ARGS__) \
}
/// Makes an epsiolon transition into another state if the `statement` is true.
#define epsilon_if(statement, ...) \ #define epsilon_if(statement, ...) \
if (statement) { \ if (statement) { \
epsilon(__VA_ARGS__) \ epsilon(__VA_ARGS__) \
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#undef term_state #undef term_state
#undef unstable_state
#undef fin #undef fin
#undef CAF_TRANSITION_IMPL1 #undef CAF_TRANSITION_IMPL1
...@@ -74,6 +76,8 @@ ...@@ -74,6 +76,8 @@
#undef fsm_epsilon #undef fsm_epsilon
#undef transition_if
#undef epsilon_if #undef epsilon_if
#undef fsm_transition_if #undef fsm_transition_if
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include "caf/config.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
CAF_PUSH_UNUSED_LABEL_WARNING
#include "caf/detail/parser/fsm.hpp"
namespace caf {
namespace detail {
namespace parser {
template <class Iterator, class Sentinel, class Consumer>
void read_ipv4_octet(state<Iterator, Sentinel>& ps, Consumer& consumer) {
uint8_t res = 0;
// Reads the a decimal place.
auto rd_decimal = [&](char c) {
return add_ascii<10>(res, c);
};
// Computes the result on success.
auto g = caf::detail::make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
consumer.value(res);
});
start();
state(init) {
transition(read, decimal_chars, rd_decimal(ch), pec::integer_overflow)
}
term_state(read) {
transition(read, decimal_chars, rd_decimal(ch), pec::integer_overflow)
}
fin();
}
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_ipv4_address(state<Iterator, Sentinel>& ps, Consumer& consumer) {
int octets = 0;
start();
state(init) {
fsm_epsilon(read_ipv4_octet(ps, consumer), rd_dot, decimal_chars, ++octets)
}
state(rd_dot) {
transition(rd_oct, '.')
}
state(rd_oct) {
fsm_epsilon_if(octets < 3, read_ipv4_octet(ps, consumer), rd_dot,
decimal_chars, ++octets)
fsm_epsilon_if(octets == 3, read_ipv4_octet(ps, consumer), done)
}
term_state(done) {
// nop
}
fin();
}
} // namespace parser
} // namespace detail
} // namespace caf
#include "caf/detail/parser/fsm_undef.hpp"
CAF_POP_WARNINGS
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include "caf/config.hpp"
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/read_ipv6_address.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
#include "caf/uri.hpp"
CAF_PUSH_UNUSED_LABEL_WARNING
#include "caf/detail/parser/fsm.hpp"
namespace caf {
namespace detail {
namespace parser {
// foo://example.com:8042/over/there?name=ferret#nose
// \_/ \______________/\_________/ \_________/ \__/
// | | | | |
// scheme authority path query fragment
// | _____________________|__
// / \ / \.
// urn:example:animal:ferret:nose
// Unlike our other parsers, the URI parsers only check for validity and
// generate ranges for the subcomponents. URIs can't have linebreaks, so we can
// safely keep track of the position by looking at the column.
template <class Iterator, class Sentinel>
void read_uri_percent_encoded(state<Iterator, Sentinel>& ps, std::string& str) {
uint8_t char_code = 0;
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
str += static_cast<char>(char_code);
});
start();
state(init) {
transition(read_nibble, hexadecimal_chars, add_ascii<16>(char_code, ch))
}
state(read_nibble) {
transition(done, hexadecimal_chars, add_ascii<16>(char_code, ch))
}
term_state(done) {
// nop
}
fin();
}
inline bool uri_unprotected_char(char c) {
return in_whitelist(alphanumeric_chars, c) || in_whitelist("-._~", c);
}
#define read_next_char(next_state, dest) \
transition(next_state, uri_unprotected_char, dest += ch) \
fsm_transition(read_uri_percent_encoded(ps, dest), next_state, '%')
template <class Iterator, class Sentinel, class Consumer>
void read_uri_query(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
// Local variables.
uri::query_map result;
std::string key;
std::string value;
// Utility functions.
auto take_str = [&](std::string& str) {
using std::swap;
std::string res;
swap(str, res);
return std::move(res);
};
auto push = [&] {
result.emplace(take_str(key), take_str(value));
};
// Call consumer on exit.
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
consumer.query(std::move(result));
});
// FSM declaration.
start();
// Query may be empty.
term_state(init) {
read_next_char(read_key, key)
}
state(read_key) {
read_next_char(read_key, key)
transition(read_value, '=')
}
term_state(read_value, push()) {
read_next_char(read_value, value)
transition(init, '&', push())
}
fin();
}
template <class Iterator, class Sentinel, class Consumer>
void read_uri(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
// Local variables.
std::string str;
uint16_t port = 0;
// Replaces `str` with a default constructed string to make sure we're never
// operating on a moved-from string object.
auto take_str = [&] {
using std::swap;
std::string res;
swap(str, res);
return std::move(res);
};
// Allowed character sets.
auto path_char = [](char c) {
return in_whitelist(alphanumeric_chars, c) || c == '/';
};
// Utility setters for avoiding code duplication.
auto set_path = [&] {
consumer.path(take_str());
};
auto set_host = [&] {
consumer.host(take_str());
};
auto set_userinfo = [&] {
consumer.userinfo(take_str());
};
// Consumer for reading IPv6 addresses.
struct {
Consumer& f;
void value(ipv6_address addr) {
f.host(addr);
}
} ip_consumer{consumer};
// FSM declaration.
start();
state(init) {
epsilon(read_scheme)
}
state(read_scheme) {
read_next_char(read_scheme, str)
transition(have_scheme, ':', consumer.scheme(take_str()))
}
state(have_scheme) {
transition(disambiguate_path, '/')
read_next_char(read_path, str)
fsm_transition(read_uri_percent_encoded(ps, str), read_path, '%')
}
// This state is terminal, because "file:/" is a valid URI.
term_state(disambiguate_path, consumer.path("/")) {
transition(start_authority, '/')
epsilon(read_path, any_char, str += '/')
}
state(start_authority) {
read_next_char(read_authority, str)
fsm_transition(read_ipv6_address(ps, ip_consumer), await_end_of_ipv6, '[')
}
state(await_end_of_ipv6) {
transition(end_of_ipv6_host, ']')
}
term_state(end_of_ipv6_host) {
transition(start_port, ':')
epsilon(end_of_authority)
}
term_state(end_of_host) {
transition(start_port, ':', set_host())
epsilon(end_of_authority, "/?#", set_host())
}
term_state(read_authority, set_host()) {
read_next_char(read_authority, str)
transition(start_host, '@', set_userinfo())
transition(start_port, ':', set_host())
epsilon(end_of_authority, "/?#", set_host())
}
state(start_host) {
read_next_char(read_host, str)
fsm_transition(read_ipv6_address(ps, ip_consumer), await_end_of_ipv6, '[')
}
term_state(read_host, set_host()) {
read_next_char(read_host, str)
transition(start_port, ':', set_host())
epsilon(end_of_authority, "/?#", set_host())
}
state(start_port) {
transition(read_port, decimal_chars, add_ascii<10>(port, ch))
}
term_state(read_port, consumer.port(port)) {
transition(read_port, decimal_chars, add_ascii<10>(port, ch),
pec::integer_overflow)
epsilon(end_of_authority, "/?#", consumer.port(port))
}
term_state(end_of_authority) {
transition(read_path, '/')
transition(start_query, '?')
transition(read_fragment, '#')
}
term_state(read_path, set_path()) {
transition(read_path, path_char, str += ch)
fsm_transition(read_uri_percent_encoded(ps, str), read_path, '%')
transition(start_query, '?', set_path())
transition(read_fragment, '#', set_path())
}
term_state(start_query) {
fsm_epsilon(read_uri_query(ps, consumer), end_of_query)
}
unstable_state(end_of_query) {
transition(read_fragment, '#')
epsilon(done)
}
term_state(read_fragment, consumer.fragment(take_str())) {
read_next_char(read_fragment, str)
}
term_state(done) {
// nop
}
fin();
}
} // namespace parser
} // namespace detail
} // namespace caf
#include "caf/detail/parser/fsm_undef.hpp"
CAF_POP_WARNINGS
...@@ -51,13 +51,12 @@ struct state { ...@@ -51,13 +51,12 @@ struct state {
/// otherwise the next character. /// otherwise the next character.
char next() noexcept { char next() noexcept {
++i; ++i;
++column;
if (i != e) { if (i != e) {
auto c = *i; auto c = *i;
if (c == '\n') { if (c == '\n') {
++line; ++line;
column = 1; column = 1;
} else {
++column;
} }
return c; return c;
} }
......
...@@ -25,8 +25,9 @@ ...@@ -25,8 +25,9 @@
#include <vector> #include <vector>
#include "caf/atom.hpp" #include "caf/atom.hpp"
#include "caf/none.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/none.hpp"
#include "caf/string_view.hpp"
#include "caf/meta/type_name.hpp" #include "caf/meta/type_name.hpp"
#include "caf/meta/omittable.hpp" #include "caf/meta/omittable.hpp"
...@@ -73,18 +74,23 @@ public: ...@@ -73,18 +74,23 @@ public:
void consume(atom_value& x); void consume(atom_value& x);
void consume(const char* cstr); void consume(string_view str);
inline void consume(bool& x) { inline void consume(bool& x) {
result_ += x ? "true" : "false"; result_ += x ? "true" : "false";
} }
inline void consume(char* cstr) { inline void consume(const char* cstr) {
consume(const_cast<const char*>(cstr)); if (cstr == nullptr) {
result_ += "null";
} else {
string_view tmp{cstr, strlen(cstr)};
consume(tmp);
}
} }
inline void consume(std::string& str) { inline void consume(char* cstr) {
consume(str.c_str()); consume(const_cast<const char*>(cstr));
} }
template <class T> template <class T>
...@@ -132,6 +138,7 @@ public: ...@@ -132,6 +138,7 @@ public:
template <class T> template <class T>
enable_if_t<is_iterable<T>::value enable_if_t<is_iterable<T>::value
&& !is_inspectable<stringification_inspector, T>::value && !is_inspectable<stringification_inspector, T>::value
&& !std::is_convertible<T, string_view>::value
&& !has_to_string<T>::value> && !has_to_string<T>::value>
consume(T& xs) { consume(T& xs) {
result_ += '['; result_ += '[';
...@@ -243,6 +250,7 @@ public: ...@@ -243,6 +250,7 @@ public:
&& !std::is_pointer<T>::value && !std::is_pointer<T>::value
&& !is_inspectable<stringification_inspector, T>::value && !is_inspectable<stringification_inspector, T>::value
&& !std::is_arithmetic<T>::value && !std::is_arithmetic<T>::value
&& !std::is_convertible<T, string_view>::value
&& !has_to_string<T>::value> && !has_to_string<T>::value>
consume(T&) { consume(T&) {
result_ += "<unprintable>"; result_ += "<unprintable>";
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <atomic>
#include <cstdint>
#include <string>
#include <utility>
#include "caf/error.hpp"
#include "caf/fwd.hpp"
#include "caf/meta/load_callback.hpp"
#include "caf/ref_counted.hpp"
#include "caf/string_view.hpp"
#include "caf/uri.hpp"
namespace caf {
namespace detail {
class uri_impl {
public:
// -- constructors, destructors, and assignment operators --------------------
uri_impl();
uri_impl(const uri_impl&) = delete;
uri_impl& operator=(const uri_impl&) = delete;
// -- member variables -------------------------------------------------------
static uri_impl default_instance;
/// Null-terminated buffer for holding the string-representation of the URI.
std::string str;
/// Scheme component.
std::string scheme;
/// Assembled authority component.
uri::authority_type authority;
/// Path component.
std::string path;
/// Query component as key-value pairs.
uri::query_map query;
/// The fragment component.
std::string fragment;
// -- properties -------------------------------------------------------------
bool valid() const noexcept {
return !scheme.empty() && (!authority.empty() || !path.empty());
}
// -- modifiers --------------------------------------------------------------
/// Assembles the human-readable string representation for this URI.
void assemble_str();
// Escapes all reserved characters according to RFC 3986 in `x` and
// adds the encoded string to `str`.
void add_encoded(string_view x, bool is_path = false);
// -- friend functions -------------------------------------------------------
friend void intrusive_ptr_add_ref(const uri_impl* p);
friend void intrusive_ptr_release(const uri_impl* p);
private:
// -- member variables -------------------------------------------------------
mutable std::atomic<size_t> rc_;
};
// -- related free functions -------------------------------------------------
/// @relates uri_impl
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, uri_impl& x) {
auto load = [&]() -> error {
x.str.clear();
if (x.valid())
x.assemble_str();
return none;
};
return f(x.scheme, x.authority, x.path, x.query, x.fragment,
meta::load_callback(load));
}
} // namespace detail
} // namespace caf
...@@ -104,7 +104,9 @@ class group; ...@@ -104,7 +104,9 @@ class group;
class group_module; class group_module;
class inbound_path; class inbound_path;
class ipv4_address; class ipv4_address;
class ipv4_subnet;
class ipv6_address; class ipv6_address;
class ipv6_subnet;
class local_actor; class local_actor;
class mailbox_element; class mailbox_element;
class message; class message;
...@@ -126,6 +128,8 @@ class string_view; ...@@ -126,6 +128,8 @@ class string_view;
class type_erased_tuple; class type_erased_tuple;
class type_erased_value; class type_erased_value;
class uniform_type_info_map; class uniform_type_info_map;
class uri;
class uri_builder;
// -- structs ------------------------------------------------------------------ // -- structs ------------------------------------------------------------------
...@@ -161,6 +165,8 @@ enum class atom_value : uint64_t; ...@@ -161,6 +165,8 @@ enum class atom_value : uint64_t;
// -- aliases ------------------------------------------------------------------ // -- aliases ------------------------------------------------------------------
using actor_id = uint64_t; using actor_id = uint64_t;
using ip_address = ipv6_address;
using ip_subnet = ipv6_subnet;
using stream_slot = uint16_t; using stream_slot = uint16_t;
// -- functions ---------------------------------------------------------------- // -- functions ----------------------------------------------------------------
...@@ -235,10 +241,15 @@ template <class> class type_erased_value_impl; ...@@ -235,10 +241,15 @@ template <class> class type_erased_value_impl;
template <class> class stream_distribution_tree; template <class> class stream_distribution_tree;
class disposer; class disposer;
class message_data; class dynamic_message_data;
class group_manager; class group_manager;
class message_data;
class private_thread; class private_thread;
class dynamic_message_data; class uri_impl;
void intrusive_ptr_add_ref(const uri_impl* p);
void intrusive_ptr_release(const uri_impl* p);
} // namespace detail } // namespace detail
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include "caf/ipv6_address.hpp"
namespace caf {
/// An IP address. The address family is IPv6 unless `embeds_v4` returns true.
using ip_address = ipv6_address;
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include "caf/ipv6_subnet.hpp"
namespace caf {
/// An IP subnetwork. The address family is IPv6 unless `embeds_v4` returns
/// true.
using ip_subnet = ipv6_subnet;
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <array>
#include <cstdint>
#include <string>
#include "caf/byte_address.hpp"
#include "caf/detail/comparable.hpp"
#include "caf/fwd.hpp"
namespace caf {
class ipv4_address : public byte_address<ipv4_address> {
public:
// -- constants --------------------------------------------------------------
static constexpr size_t num_bytes = 4;
// -- member types -----------------------------------------------------------
using super = byte_address<ipv4_address>;
using array_type = std::array<uint8_t, num_bytes>;
// -- constructors, destructors, and assignment operators --------------------
ipv4_address();
explicit ipv4_address(array_type bytes);
// -- properties -------------------------------------------------------------
/// Returns whether this is a loopback address.
bool is_loopback() const noexcept;
/// Returns whether this is a multicast address.
bool is_multicast() const noexcept;
/// Returns the bits of the IP address in a single integer.
inline uint32_t bits() const noexcept {
return bits_;
}
/// Sets all bits of the IP address in a single 32-bit write.
/// @private
inline void bits(uint32_t value) noexcept {
bits_ = value;
}
/// Returns the bytes of the IP address as array.
inline array_type& bytes() noexcept {
return bytes_;
}
/// Returns the bytes of the IP address as array.
inline const array_type& bytes() const noexcept {
return bytes_;
}
/// Alias for `bytes()`.
inline array_type& data() noexcept {
return bytes_;
}
/// Alias for `bytes()`.
inline const array_type& data() const noexcept {
return bytes_;
}
// -- inspection -------------------------------------------------------------
template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, ipv4_address& x) {
return f(x.bits_);
}
private:
// -- member variables -------------------------------------------------------
union {
uint32_t bits_;
array_type bytes_;
};
// -- sanity checks ----------------------------------------------------------
static_assert(sizeof(array_type) == sizeof(uint32_t),
"array<char, 4> has a different size than uint32");
};
// -- related free functions ---------------------------------------------------
/// Returns a human-readable string representation of the address.
/// @relates ipv4_address
std::string to_string(const ipv4_address& x);
/// Tries to parse the content of `str` into `dest`.
/// @relates ipv4_address
error parse(string_view str, ipv4_address& dest);
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include "caf/detail/comparable.hpp"
#include "caf/ipv4_address.hpp"
namespace caf {
class ipv4_subnet : detail::comparable<ipv4_subnet> {
public:
// -- constructors, destructors, and assignment operators --------------------
ipv4_subnet();
ipv4_subnet(ipv4_address network_address, uint8_t prefix_length);
// -- properties -------------------------------------------------------------
/// Returns the network address for this subnet.
inline ipv4_address network_address() const noexcept {
return address_;
}
/// Returns the prefix length of the netmask in bits.
inline uint8_t prefix_length() const noexcept {
return prefix_length_;
}
/// Returns whether `addr` belongs to this subnet.
bool contains(ipv4_address addr) const noexcept;
/// Returns whether this subnet includes `other`.
bool contains(ipv4_subnet other) const noexcept;
// -- comparison -------------------------------------------------------------
int compare(const ipv4_subnet& other) const noexcept;
private:
// -- member variables -------------------------------------------------------
ipv4_address address_;
uint8_t prefix_length_;
};
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <array>
#include <cstdint>
#include <initializer_list>
#include <string>
#include "caf/byte_address.hpp"
#include "caf/detail/comparable.hpp"
#include "caf/fwd.hpp"
namespace caf {
class ipv6_address : public byte_address<ipv6_address>,
detail::comparable<ipv6_address, ipv4_address> {
public:
// -- constants --------------------------------------------------------------
static constexpr size_t num_bytes = 16;
// -- member types -----------------------------------------------------------
using super = byte_address<ipv6_address>;
using array_type = std::array<uint8_t, num_bytes>;
using u16_array_type = std::array<uint16_t, 8>;
using uint16_ilist = std::initializer_list<uint16_t>;
// -- constructors, destructors, and assignment operators --------------------
/// Constructs an all-zero address.
ipv6_address();
/// Constructs an address from given prefix and suffix.
/// @pre `prefix.size() + suffix.size() <= 8`
/// @warning assumes network byte order for prefix and suffix
ipv6_address(uint16_ilist prefix, uint16_ilist suffix);
/// Embeds an IPv4 address into an IPv6 address.
explicit ipv6_address(ipv4_address addr);
/// Constructs an IPv6 address from given bytes.
explicit ipv6_address(array_type bytes);
// -- comparison -------------------------------------------------------------
using super::compare;
/// Returns a negative number if `*this < other`, zero if `*this == other`
/// and a positive number if `*this > other`.
int compare(ipv4_address other) const noexcept;
// -- properties -------------------------------------------------------------
/// Returns whether this address embeds an IPv4 address.
bool embeds_v4() const noexcept;
/// Returns an embedded IPv4 address.
/// @pre `embeds_v4()`
ipv4_address embedded_v4() const noexcept;
/// Returns whether this is a loopback address.
bool is_loopback() const noexcept;
/// Returns the bytes of the IP address as array.
inline array_type& bytes() noexcept {
return bytes_;
}
/// Returns the bytes of the IP address as array.
inline const array_type& bytes() const noexcept {
return bytes_;
}
/// Alias for `bytes()`.
inline array_type& data() noexcept {
return bytes_;
}
/// Alias for `bytes()`.
inline const array_type& data() const noexcept {
return bytes_;
}
/// Returns whether this address contains only zeros, i.e., equals `::`.
inline bool zero() const noexcept {
return half_segments_[0] == 0 && half_segments_[1] == 0;
}
// -- inspection -------------------------------------------------------------
template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f,
ipv6_address& x) {
return f(x.bytes_);
}
friend std::string to_string(ipv6_address x);
private:
// -- member variables -------------------------------------------------------
union {
std::array<uint64_t, 2> half_segments_;
std::array<uint32_t, 4> quad_segments_;
u16_array_type oct_segments_;
array_type bytes_;
};
};
error parse(string_view str, ipv6_address& dest);
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include "caf/detail/comparable.hpp"
#include "caf/fwd.hpp"
#include "caf/ipv4_address.hpp"
#include "caf/ipv4_subnet.hpp"
#include "caf/ipv6_address.hpp"
namespace caf {
class ipv6_subnet : detail::comparable<ipv6_subnet> {
public:
// -- constants --------------------------------------------------------------
/// Stores the offset of an embedded IPv4 subnet in bits.
static constexpr uint8_t v4_offset =
static_cast<uint8_t>(ipv6_address::num_bytes - ipv4_address::num_bytes) * 8;
// -- constructors, destructors, and assignment operators --------------------
ipv6_subnet();
explicit ipv6_subnet(ipv4_subnet subnet);
ipv6_subnet(ipv4_address network_address, uint8_t prefix_length);
ipv6_subnet(ipv6_address network_address, uint8_t prefix_length);
// -- properties -------------------------------------------------------------
/// Returns whether this subnet embeds an IPv4 subnet.
bool embeds_v4() const noexcept;
/// Returns an embedded IPv4 subnet.
/// @pre `embeds_v4()`
ipv4_subnet embedded_v4() const noexcept;
/// Returns the network address for this subnet.
inline ipv6_address network_address() const noexcept {
return address_;
}
/// Returns the prefix length of the netmask.
inline uint8_t prefix_length() const noexcept {
return prefix_length_;
}
/// Returns whether `addr` belongs to this subnet.
bool contains(ipv6_address addr) const noexcept;
/// Returns whether this subnet includes `other`.
bool contains(ipv6_subnet other) const noexcept;
/// Returns whether `addr` belongs to this subnet.
bool contains(ipv4_address addr) const noexcept;
/// Returns whether this subnet includes `other`.
bool contains(ipv4_subnet other) const noexcept;
// -- comparison -------------------------------------------------------------
int compare(const ipv6_subnet& other) const noexcept;
private:
// -- member variables -------------------------------------------------------
ipv6_address address_;
uint8_t prefix_length_;
};
} // namespace caf
...@@ -52,11 +52,11 @@ struct is_string_like { ...@@ -52,11 +52,11 @@ struct is_string_like {
decltype(x->size()) decltype(x->size())
>::value >::value
>::type* = nullptr, >::type* = nullptr,
// check if `x->compare(*x)` is well-formed and returns an integer // check if `x->find('?', 0)` is well-formed and returns an integer
// (distinguishes vectors from strings) // (distinguishes vectors from strings)
typename std::enable_if< typename std::enable_if<
std::is_integral< std::is_integral<
decltype(x->compare(*x)) decltype(x->find('?', 0))
>::value >::value
>::type* = nullptr); >::type* = nullptr);
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <vector>
#include "caf/detail/comparable.hpp"
#include "caf/detail/unordered_flat_map.hpp"
#include "caf/fwd.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/ip_address.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
namespace caf {
/// A URI according to RFC 3986.
class uri : detail::comparable<uri>, detail::comparable<uri, string_view> {
public:
// -- member types -----------------------------------------------------------
/// Pointer to implementation.
using impl_ptr = intrusive_ptr<const detail::uri_impl>;
/// Host subcomponent of the authority component. Either an IP address or
/// an hostname as string.
using host_type = variant<std::string, ip_address>;
/// Bundles the authority component of the URI, i.e., userinfo, host, and
/// port.
struct authority_type {
std::string userinfo;
host_type host;
uint16_t port;
inline authority_type() : port(0) {
// nop
}
/// Returns whether `host` is empty, i.e., the host is not an IP address
/// and the string is empty.
bool empty() const noexcept {
auto str = get_if<std::string>(&host);
return str != nullptr && str->empty();
}
};
/// Separates the query component into key-value pairs.
using path_list = std::vector<string_view>;
/// Separates the query component into key-value pairs.
using query_map = detail::unordered_flat_map<std::string, std::string>;
// -- constructors, destructors, and assignment operators --------------------
uri();
uri(uri&&) = default;
uri(const uri&) = default;
uri& operator=(uri&&) = default;
uri& operator=(const uri&) = default;
explicit uri(impl_ptr ptr);
// -- properties -------------------------------------------------------------
/// Returns whether all components of this URI are empty.
bool empty() const noexcept;
/// Returns the full URI as provided by the user.
string_view str() const noexcept;
/// Returns the scheme component.
string_view scheme() const noexcept;
/// Returns the authority component.
const authority_type& authority() const noexcept;
/// Returns the path component as provided by the user.
string_view path() const noexcept;
/// Returns the query component as key-value map.
const query_map& query() const noexcept;
/// Returns the fragment component.
string_view fragment() const noexcept;
// -- comparison -------------------------------------------------------------
int compare(const uri& other) const noexcept;
int compare(string_view x) const noexcept;
// -- friend functions -------------------------------------------------------
friend error inspect(caf::serializer& dst, uri& x);
friend error inspect(caf::deserializer& src, uri& x);
private:
impl_ptr impl_;
};
// -- related free functions ---------------------------------------------------
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, uri::authority_type& x) {
return f(x.userinfo, x.host, x.port);
}
/// @relates uri
std::string to_string(const uri& x);
/// @relates uri
error parse(string_view str, uri& dest);
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <string>
#include "caf/fwd.hpp"
#include "caf/uri.hpp"
namespace caf {
class uri_builder {
public:
// -- member types -----------------------------------------------------------
/// Pointer to implementation.
using impl_ptr = intrusive_ptr<detail::uri_impl>;
// -- constructors, destructors, and assignment operators --------------------
uri_builder();
uri_builder(uri_builder&&) = default;
uri_builder& operator=(uri_builder&&) = default;
// -- setter -----------------------------------------------------------------
uri_builder& scheme(std::string str);
uri_builder& userinfo(std::string str);
uri_builder& host(std::string str);
uri_builder& host(ip_address addr);
uri_builder& port(uint16_t value);
uri_builder& path(std::string str);
uri_builder& query(uri::query_map map);
uri_builder& fragment(std::string str);
// -- factory functions ------------------------------------------------------
uri make();
private:
// -- member variables -------------------------------------------------------
impl_ptr impl_;
};
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/ipv4_address.hpp"
#include "caf/detail/network_order.hpp"
#include "caf/detail/parser/read_ipv4_address.hpp"
#include "caf/error.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
namespace caf {
namespace {
inline uint32_t net_order(uint32_t value) {
return detail::to_network_order(value);
}
struct ipv4_address_consumer {
size_t pos;
ipv4_address& dest;
ipv4_address_consumer(ipv4_address& ref) : pos(0), dest(ref) {
// nop
}
void value(uint8_t octet) {
dest[pos++] = octet;
}
};
} // namespace <anonymous>
// -- constructors, destructors, and assignment operators ----------------------
ipv4_address::ipv4_address() {
bits_ = 0u;
}
ipv4_address::ipv4_address(array_type bytes) {
memcpy(bytes_.data(), bytes.data(), bytes.size());
}
// -- properties ---------------------------------------------------------------
bool ipv4_address::is_loopback() const noexcept {
// All addresses in 127.0.0.0/8 are considered loopback addresses.
return (bits_ & net_order(0xFF000000)) == net_order(0x7F000000);
}
bool ipv4_address::is_multicast() const noexcept {
// All addresses in 224.0.0.0/8 are considered loopback addresses.
return (bits_ & net_order(0xFF000000)) == net_order(0xE0000000);
}
// -- related free functions ---------------------------------------------------
std::string to_string(const ipv4_address& x) {
using std::to_string;
std::string result;
result += to_string(x[0]);
for (size_t i = 1; i < x.data().size(); ++i) {
result += '.';
result += to_string(x[i]);
}
return result;
}
error parse(string_view str, ipv4_address& dest) {
using namespace detail;
parser::state<string_view::iterator> res{str.begin(), str.end()};
ipv4_address_consumer f{dest};
parser::read_ipv4_address(res, f);
if (res.code == pec::success)
return none;
return make_error(res.code, res.line, res.column);
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/ipv4_subnet.hpp"
namespace caf {
// -- constructors, destructors, and assignment operators --------------------
ipv4_subnet::ipv4_subnet() {
// nop
}
ipv4_subnet::ipv4_subnet(ipv4_address network_address, uint8_t prefix_length)
: address_(network_address),
prefix_length_(prefix_length) {
// nop
}
// -- properties ---------------------------------------------------------------
bool ipv4_subnet::contains(ipv4_address addr) const noexcept {
return address_ == addr.network_address(prefix_length_);
}
bool ipv4_subnet::contains(ipv4_subnet other) const noexcept {
// We can only contain a subnet if it's prefix is greater or equal.
if (prefix_length_ > other.prefix_length_)
return false;
return prefix_length_ == other.prefix_length_
? address_ == other.address_
: address_ == other.address_.network_address(prefix_length_);
}
// -- comparison ---------------------------------------------------------------
int ipv4_subnet::compare(const ipv4_subnet& other) const noexcept {
auto sub_res = address_.compare(other.address_);
return sub_res != 0 ? sub_res
: static_cast<int>(prefix_length_) - other.prefix_length_;
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/ipv6_address.hpp"
#include "caf/detail/append_hex.hpp"
#include "caf/detail/network_order.hpp"
#include "caf/detail/parser/read_ipv6_address.hpp"
#include "caf/error.hpp"
#include "caf/ipv4_address.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
namespace caf {
namespace {
struct ipv6_address_consumer {
ipv6_address& dest;
ipv6_address_consumer(ipv6_address& ref) : dest(ref) {
// nop
}
void value(ipv6_address val) {
dest = val;
}
};
// It's good practice when printing IPv6 addresses to:
// - remove leading zeros in all segments
// - use lowercase hexadecimal characters
// @param pointer to an uint16_t segment converted to uint8_t*
void append_v6_hex(std::string& result, const uint8_t* xs) {
auto tbl = "0123456789abcdef";
size_t j = 0;
std::array<char, (sizeof(uint16_t) * 2) + 1> buf;
buf.fill(0);
for (size_t i = 0; i < sizeof(uint16_t); ++i) {
auto c = xs[i];
buf[j++] = tbl[c >> 4];
buf[j++] = tbl[c & 0x0F];
}
auto pred = [](char c) {
return c != '0';
};
auto first_non_zero = std::find_if(buf.begin(), buf.end(), pred);
CAF_ASSERT(first_non_zero != buf.end());
if (*first_non_zero != '\0')
result += &(*first_non_zero);
else
result += '0';
}
inline uint32_t net_order_32(uint32_t value) {
return detail::to_network_order(value);
}
inline uint64_t net_order_64(uint64_t value) {
return detail::to_network_order(value);
}
std::array<uint32_t, 3> v4_prefix{{0, 0, net_order_32(0x0000FFFFu)}};
} // namespace <anonymous>
// -- constructors, destructors, and assignment operators ----------------------
ipv6_address::ipv6_address() {
half_segments_[0] = 0;
half_segments_[1] = 0;
}
ipv6_address::ipv6_address(uint16_ilist prefix, uint16_ilist suffix) {
CAF_ASSERT((prefix.size() + suffix.size()) <= 8);
auto addr_fill = [&](uint16_ilist chunks) {
union {
uint16_t i;
std::array<uint8_t, 2> a;
} tmp;
size_t p = 0;
for (auto chunk : chunks) {
tmp.i = detail::to_network_order(chunk);
bytes_[p++] = tmp.a[0];
bytes_[p++] = tmp.a[1];
}
};
bytes_.fill(0);
addr_fill(suffix);
std::rotate(bytes_.begin(), bytes_.begin() + suffix.size() * 2, bytes_.end());
addr_fill(prefix);
}
ipv6_address::ipv6_address(ipv4_address addr) {
std::copy(v4_prefix.begin(), v4_prefix.end(), quad_segments_.begin());
quad_segments_.back() = addr.bits();
}
ipv6_address::ipv6_address(array_type bytes) {
memcpy(bytes_.data(), bytes.data(), bytes.size());
}
int ipv6_address::compare(ipv4_address other) const noexcept {
ipv6_address tmp{other};
return compare(tmp);
}
// -- properties ---------------------------------------------------------------
bool ipv6_address::embeds_v4() const noexcept {
using std::begin;
using std::end;
return std::equal(begin(v4_prefix), end(v4_prefix), quad_segments_.begin());
}
ipv4_address ipv6_address::embedded_v4() const noexcept {
ipv4_address result;
result.bits(quad_segments_.back());
return result;
}
bool ipv6_address::is_loopback() const noexcept {
// IPv6 defines "::1" as the loopback address, when embedding a v4 we
// dispatch accordingly.
return embeds_v4()
? embedded_v4().is_loopback()
: half_segments_[0] == 0 && half_segments_[1] == net_order_64(1u);
}
// -- related free functions ---------------------------------------------------
namespace {
using u16_iterator = ipv6_address::u16_array_type::const_iterator;
using u16_range = std::pair<u16_iterator, u16_iterator>;
u16_range longest_streak(u16_iterator first, u16_iterator last) {
auto two_zeros = [](uint16_t x, uint16_t y) {
return x == 0 && y == 0;
};
auto not_zero = [](uint16_t x) {
return x != 0;
};
u16_range result;
result.first = std::adjacent_find(first, last, two_zeros);
if (result.first == last)
return {last, last};
result.second = std::find_if(result.first + 2, last, not_zero);
if (result.second == last)
return result;
auto next_streak = longest_streak(result.second, last);
auto range_size = [](u16_range x) {
return std::distance(x.first, x.second);
};
return range_size(result) >= range_size(next_streak) ? result : next_streak;
}
} // namespace <anonymous>
std::string to_string(ipv6_address x) {
// Shortcut for embedded v4 addresses.
if (x.embeds_v4())
return to_string(x.embedded_v4());
// Shortcut for all-zero addresses.
if (x.zero())
return "::";
// Output buffer.
std::string result;
// Utility for appending chunks to the result.
auto add_chunk = [&](uint16_t x) {
append_v6_hex(result, reinterpret_cast<uint8_t*>(&x));
};
auto add_chunks = [&](u16_iterator i, u16_iterator e) {
if (i != e) {
add_chunk(*i);
for (++i; i != e; ++i) {
result += ':';
add_chunk(*i);
}
}
};
// Scan for the longest streak of 0 16-bit chunks for :: shorthand.
auto first = x.oct_segments_.cbegin();
auto last = x.oct_segments_.cend();
auto streak = longest_streak(first, last);
// Put it all together.
if (streak.first == last) {
add_chunks(first, last);
} else {
add_chunks(first, streak.first);
result += "::";
add_chunks(streak.second, last);
}
return result;
}
error parse(string_view str, ipv6_address& dest) {
using namespace detail;
parser::state<string_view::iterator> res{str.begin(), str.end()};
ipv6_address_consumer f{dest};
parser::read_ipv6_address(res, f);
if (res.code == pec::success)
return none;
return make_error(res.code, res.line, res.column);
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/ipv6_subnet.hpp"
namespace caf {
// -- constructors, destructors, and assignment operators --------------------
ipv6_subnet::ipv6_subnet() {
// nop
}
ipv6_subnet::ipv6_subnet(ipv4_subnet subnet)
: address_(ipv6_address{subnet.network_address()}),
prefix_length_(v4_offset + subnet.prefix_length()){
// nop
}
ipv6_subnet::ipv6_subnet(ipv4_address network_address, uint8_t prefix_length)
: address_(network_address),
prefix_length_(prefix_length + v4_offset) {
// nop
}
ipv6_subnet::ipv6_subnet(ipv6_address network_address, uint8_t prefix_length)
: address_(network_address),
prefix_length_(prefix_length) {
// nop
}
// -- properties ---------------------------------------------------------------
bool ipv6_subnet::embeds_v4() const noexcept {
return prefix_length_ >= v4_offset && address_.embeds_v4();
}
ipv4_subnet ipv6_subnet::embedded_v4() const noexcept {
return {address_.embedded_v4(),
static_cast<uint8_t>(prefix_length_ - v4_offset)};
}
bool ipv6_subnet::contains(ipv6_address addr) const noexcept {
return address_ == addr.network_address(prefix_length_);
}
bool ipv6_subnet::contains(ipv6_subnet other) const noexcept {
// We can only contain a subnet if it's prefix is greater or equal.
if (prefix_length_ > other.prefix_length_)
return false;
return prefix_length_ == other.prefix_length_
? address_ == other.address_
: address_ == other.address_.network_address(prefix_length_);
}
bool ipv6_subnet::contains(ipv4_address addr) const noexcept {
return embeds_v4() ? embedded_v4().contains(addr) : false;
}
bool ipv6_subnet::contains(ipv4_subnet other) const noexcept {
return embeds_v4() ? embedded_v4().contains(other) : false;
}
// -- comparison ---------------------------------------------------------------
int ipv6_subnet::compare(const ipv6_subnet& other) const noexcept {
auto sub_res = address_.compare(other.address_);
return sub_res != 0 ? sub_res
: static_cast<int>(prefix_length_) - other.prefix_length_;
}
} // namespace caf
...@@ -101,7 +101,16 @@ string_view string_view::substr(size_type pos, size_type n) const noexcept { ...@@ -101,7 +101,16 @@ string_view string_view::substr(size_type pos, size_type n) const noexcept {
} }
int string_view::compare(string_view str) const noexcept { int string_view::compare(string_view str) const noexcept {
return strncmp(data(), str.data(), std::min(size(), str.size())); auto s0 = size();
auto s1 = str.size();
auto fallback = [](int x, int y) {
return x == 0 ? y : x;
};
if (s0 == s1)
return strncmp(data(), str.data(), s0);
else if (s0 < s1)
return fallback(strncmp(data(), str.data(), s0), -1);
return fallback(strncmp(data(), str.data(), s1), 1);
} }
int string_view::compare(size_type pos1, size_type n1, int string_view::compare(size_type pos1, size_type n1,
......
...@@ -39,20 +39,20 @@ void stringification_inspector::consume(atom_value& x) { ...@@ -39,20 +39,20 @@ void stringification_inspector::consume(atom_value& x) {
result_ += '\''; result_ += '\'';
} }
void stringification_inspector::consume(const char* cstr) { void stringification_inspector::consume(string_view str) {
if (cstr == nullptr || *cstr == '\0') { if (str.empty()) {
result_ += R"("")"; result_ += R"("")";
return; return;
} }
if (*cstr == '"') { if (str[0] == '"') {
// assume an already escaped string // Assume an already escaped string.
result_ += cstr; result_.insert(result_.end(), str.begin(), str.end());
return; return;
} }
// Escape string.
result_ += '"'; result_ += '"';
char c; for (char c : str) {
for(;;) { switch (c) {
switch (c = *cstr++) {
default: default:
result_ += c; result_ += c;
break; break;
...@@ -62,11 +62,8 @@ void stringification_inspector::consume(const char* cstr) { ...@@ -62,11 +62,8 @@ void stringification_inspector::consume(const char* cstr) {
case '"': case '"':
result_ += R"(\")"; result_ += R"(\")";
break; break;
case '\0':
goto end_of_string;
} }
} }
end_of_string:
result_ += '"'; result_ += '"';
} }
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/uri.hpp"
#include "caf/deserializer.hpp"
#include "caf/detail/parser/read_uri.hpp"
#include "caf/detail/uri_impl.hpp"
#include "caf/error.hpp"
#include "caf/make_counted.hpp"
#include "caf/serializer.hpp"
#include "caf/uri_builder.hpp"
namespace caf {
uri::uri() : impl_(&detail::uri_impl::default_instance) {
// nop
}
uri::uri(impl_ptr ptr) : impl_(std::move(ptr)) {
CAF_ASSERT(impl_ != nullptr);
}
bool uri::empty() const noexcept {
return str().empty();
}
string_view uri::str() const noexcept {
return impl_->str;
}
string_view uri::scheme() const noexcept {
return impl_->scheme;
}
const uri::authority_type& uri::authority() const noexcept {
return impl_->authority;
}
string_view uri::path() const noexcept {
return impl_->path;
}
const uri::query_map& uri::query() const noexcept {
return impl_->query;
}
string_view uri::fragment() const noexcept {
return impl_->fragment;
}
// -- comparison ---------------------------------------------------------------
int uri::compare(const uri& other) const noexcept {
return str().compare(other.str());
}
int uri::compare(string_view x) const noexcept {
return string_view{str()}.compare(x);
}
// -- friend functions ---------------------------------------------------------
error inspect(caf::serializer& dst, uri& x) {
return inspect(dst, const_cast<detail::uri_impl&>(*x.impl_));
}
error inspect(caf::deserializer& src, uri& x) {
auto impl = make_counted<detail::uri_impl>();
auto err = inspect(src, *impl);
if (err == none)
x = uri{std::move(impl)};
return err;
}
// -- related free functions ---------------------------------------------------
std::string to_string(const uri& x) {
auto x_str = x.str();
std::string result{x_str.begin(), x_str.end()};
return result;
}
error parse(string_view str, uri& dest) {
using namespace detail::parser;
uri_builder builder;
state<string_view::iterator> res{str.begin(), str.end()};
read_uri(res, builder);
if (res.code == pec::success) {
dest = builder.make();
return none;
}
return make_error(res.code, res.line, res.column);
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/uri_builder.hpp"
#include "caf/detail/uri_impl.hpp"
#include "caf/make_counted.hpp"
namespace caf {
uri_builder::uri_builder() : impl_(make_counted<detail::uri_impl>()) {
// nop
}
uri_builder& uri_builder::scheme(std::string str) {
impl_->scheme = std::move(str);
return *this;
}
uri_builder& uri_builder::userinfo(std::string str) {
impl_->authority.userinfo = std::move(str);
return *this;
}
uri_builder& uri_builder::host(std::string str) {
impl_->authority.host = std::move(str);
return *this;
}
uri_builder& uri_builder::host(ip_address addr) {
impl_->authority.host = addr;
return *this;
}
uri_builder& uri_builder::port(uint16_t value) {
impl_->authority.port = value;
return *this;
}
uri_builder& uri_builder::path(std::string str) {
impl_->path = std::move(str);
return *this;
}
uri_builder& uri_builder::query(uri::query_map map) {
impl_->query = std::move(map);
return *this;
}
uri_builder& uri_builder::fragment(std::string str) {
impl_->fragment = std::move(str);
return *this;
}
uri uri_builder::make() {
impl_->assemble_str();
return uri{std::move(impl_)};
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/detail/uri_impl.hpp"
#include "caf/detail/parser/read_uri.hpp"
#include "caf/error.hpp"
#include "caf/ip_address.hpp"
#include "caf/string_algorithms.hpp"
namespace caf {
namespace detail {
// -- constructors, destructors, and assignment operators ----------------------
uri_impl::uri_impl() : rc_(1) {
// nop
}
// -- member variables ---------------------------------------------------------
uri_impl uri_impl::default_instance;
// -- modifiers ----------------------------------------------------------------
void uri_impl::assemble_str() {
add_encoded(scheme);
str += ':';
if (authority.empty()) {
CAF_ASSERT(!path.empty());
add_encoded(path, true);
} else {
str += "//";
if (!authority.userinfo.empty()) {
add_encoded(authority.userinfo);
str += '@';
}
auto addr = get_if<ip_address>(&authority.host);
if (addr == nullptr) {
add_encoded(get<std::string>(authority.host));
} else {
str += '[';
str += to_string(*addr);
str += ']';
}
if (authority.port != 0) {
str += ':';
str += std::to_string(authority.port);
}
if (!path.empty()) {
str += '/';
add_encoded(path, true);
}
}
if (!query.empty()) {
str += '?';
auto i = query.begin();
auto add_kvp = [&](decltype(*i) kvp) {
add_encoded(kvp.first);
str += '=';
add_encoded(kvp.second);
};
add_kvp(*i);
for (++i; i != query.end(); ++i) {
str += '&';
add_kvp(*i);
}
}
if (!fragment.empty()) {
str += '#';
add_encoded(fragment);
}
}
void uri_impl::add_encoded(string_view x, bool is_path) {
for (auto ch : x)
switch (ch) {
case '/':
if (is_path) {
str += ch;
break;
}
// fall through
case ' ':
case ':':
case '?':
case '#':
case '[':
case ']':
case '@':
case '!':
case '$':
case '&':
case '\'':
case '"':
case '(':
case ')':
case '*':
case '+':
case ',':
case ';':
case '=':
str += '%';
detail::append_hex(str, reinterpret_cast<uint8_t*>(&ch), 1);
break;
default:
str += ch;
}
}
// -- friend functions ---------------------------------------------------------
void intrusive_ptr_add_ref(const uri_impl* p) {
p->rc_.fetch_add(1, std::memory_order_relaxed);
}
void intrusive_ptr_release(const uri_impl* p) {
if (p->rc_ == 1 || p->rc_.fetch_sub(1, std::memory_order_acq_rel) == 1)
delete p;
}
} // namespace detail
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE ipv4_address
#include "caf/test/dsl.hpp"
#include "caf/ipv4_address.hpp"
#include "caf/detail/network_order.hpp"
using caf::detail::to_network_order;
using namespace caf;
namespace {
using array_type = ipv4_address::array_type;
ipv4_address addr(uint8_t oct1, uint8_t oct2, uint8_t oct3, uint8_t oct4) {
return ipv4_address({oct1, oct2, oct3, oct4});
}
} // namespace <anonymous>
CAF_TEST(constructing) {
ipv4_address localhost({127, 0, 0, 1});
CAF_CHECK_EQUAL(localhost.bits(), to_network_order(0x7F000001u));
CAF_CHECK_EQUAL(localhost.data(), array_type({127, 0, 0, 1}));
ipv4_address zero;
CAF_CHECK_EQUAL(zero.data(), array_type({0, 0, 0, 0}));
}
CAF_TEST(to and from string) {
ipv4_address x;
auto err = parse("255.255.255.255", x);
CAF_CHECK_EQUAL(err, pec::success);
CAF_CHECK_EQUAL(x.bits(), 0xFFFFFFFF);
CAF_CHECK_EQUAL(to_string(x), "255.255.255.255");
CAF_CHECK_EQUAL(x, addr(255, 255, 255, 255));
}
CAF_TEST(properties) {
CAF_CHECK_EQUAL(addr(127, 0, 0, 1).is_loopback(), true);
CAF_CHECK_EQUAL(addr(127, 0, 0, 254).is_loopback(), true);
CAF_CHECK_EQUAL(addr(127, 0, 1, 1).is_loopback(), true);
CAF_CHECK_EQUAL(addr(128, 0, 0, 1).is_loopback(), false);
CAF_CHECK_EQUAL(addr(224, 0, 0, 1).is_multicast(), true);
CAF_CHECK_EQUAL(addr(224, 0, 0, 254).is_multicast(), true);
CAF_CHECK_EQUAL(addr(224, 0, 1, 1).is_multicast(), true);
CAF_CHECK_EQUAL(addr(225, 0, 0, 1).is_multicast(), false);
}
CAF_TEST(network addresses) {
auto all1 = addr(255, 255, 255, 255);
CAF_CHECK_EQUAL(all1.network_address(0), addr(0x00, 0x00, 0x00, 0x00));
CAF_CHECK_EQUAL(all1.network_address(7), addr(0xFE, 0x00, 0x00, 0x00));
CAF_CHECK_EQUAL(all1.network_address(8), addr(0xFF, 0x00, 0x00, 0x00));
CAF_CHECK_EQUAL(all1.network_address(9), addr(0xFF, 0x80, 0x00, 0x00));
CAF_CHECK_EQUAL(all1.network_address(31), addr(0xFF, 0xFF, 0xFF, 0xFE));
CAF_CHECK_EQUAL(all1.network_address(32), addr(0xFF, 0xFF, 0xFF, 0xFF));
CAF_CHECK_EQUAL(all1.network_address(33), addr(0xFF, 0xFF, 0xFF, 0xFF));
}
CAF_TEST(operators) {
CAF_CHECK_EQUAL(addr(16, 0, 0, 8) & addr(255, 2, 4, 6), addr(16, 0, 0, 0));
CAF_CHECK_EQUAL(addr(16, 0, 0, 8) | addr(255, 2, 4, 6), addr(255, 2, 4, 14));
CAF_CHECK_EQUAL(addr(16, 0, 0, 8) ^ addr(255, 2, 4, 6), addr(239, 2, 4, 14));
}
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE ipv4_subnet
#include "caf/test/dsl.hpp"
#include "caf/ipv4_subnet.hpp"
using namespace caf;
namespace {
ipv4_address addr(uint8_t oct1, uint8_t oct2, uint8_t oct3, uint8_t oct4) {
return ipv4_address({oct1, oct2, oct3, oct4});
}
ipv4_subnet operator/(ipv4_address addr, uint8_t prefix) {
return {addr, prefix};
}
} // namespace <anonymous>
CAF_TEST(constructing) {
ipv4_subnet zero{addr(0, 0, 0, 0), 32};
CAF_CHECK_EQUAL(zero.network_address(), addr(0, 0, 0, 0));
CAF_CHECK_EQUAL(zero.prefix_length(), 32u);
ipv4_subnet local{addr(127, 0, 0, 0), 8};
CAF_CHECK_EQUAL(local.network_address(), addr(127, 0, 0, 0));
CAF_CHECK_EQUAL(local.prefix_length(), 8u);
}
CAF_TEST(constains) {
ipv4_subnet local{addr(127, 0, 0, 0), 8};
CAF_CHECK(local.contains(addr(127, 0, 0, 1)));
CAF_CHECK(local.contains(addr(127, 1, 2, 3)));
CAF_CHECK(local.contains(addr(127, 128, 0, 0) / 9));
CAF_CHECK(local.contains(addr(127, 0, 0, 0) / 8));
CAF_CHECK(!local.contains(addr(127, 0, 0, 0) / 7));
}
CAF_TEST(ordering) {
CAF_CHECK_EQUAL(addr(192, 168, 168, 0) / 24, addr(192, 168, 168, 0) / 24);
CAF_CHECK_NOT_EQUAL(addr(192, 168, 168, 0) / 25, addr(192, 168, 168, 0) / 24);
CAF_CHECK_LESS(addr(192, 168, 167, 0) / 24, addr(192, 168, 168, 0) / 24);
CAF_CHECK_LESS(addr(192, 168, 168, 0) / 24, addr(192, 168, 168, 0) / 25);
}
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <initializer_list>
#include "caf/config.hpp"
#define CAF_SUITE ipv6_address
#include "caf/test/dsl.hpp"
#include "caf/ipv4_address.hpp"
#include "caf/ipv6_address.hpp"
using namespace caf;
namespace {
using array_type = ipv6_address::array_type;
ipv6_address addr(std::initializer_list<uint16_t> prefix,
std::initializer_list<uint16_t> suffix = {}) {
return ipv6_address{prefix, suffix};
}
} // namespace <anonymous>
CAF_TEST(constructing) {
ipv6_address localhost({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1});
CAF_CHECK_EQUAL(localhost.data(),
array_type({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}));
CAF_CHECK_EQUAL(localhost, addr({}, {0x01}));
}
CAF_TEST(comparison) {
CAF_CHECK_EQUAL(addr({1, 2, 3}), addr({1, 2, 3}));
CAF_CHECK_NOT_EQUAL(addr({3, 2, 1}), addr({1, 2, 3}));
CAF_CHECK_EQUAL(addr({}, {0xFFFF, 0x7F00, 0x0001}),
ipv4_address({127, 0, 0, 1}));
}
CAF_TEST(from string) {
auto from_string = [](string_view str) {
ipv6_address result;
auto err = parse(str, result);
if (err)
CAF_FAIL("error while parsing " << str << ": " << to_string(err));
return result;
};
CAF_CHECK_EQUAL(from_string("::1"), addr({}, {0x01}));
CAF_CHECK_EQUAL(from_string("::11"), addr({}, {0x11}));
CAF_CHECK_EQUAL(from_string("::112"), addr({}, {0x0112}));
CAF_CHECK_EQUAL(from_string("::1122"), addr({}, {0x1122}));
CAF_CHECK_EQUAL(from_string("::1:2"), addr({}, {0x01, 0x02}));
CAF_CHECK_EQUAL(from_string("::1:2"), addr({}, {0x01, 0x02}));
CAF_CHECK_EQUAL(from_string("1::1"), addr({0x01}, {0x01}));
CAF_CHECK_EQUAL(from_string("1::"), addr({0x01}, {}));
CAF_CHECK_EQUAL(from_string("0.1.0.1"), addr({}, {0xFFFF, 0x01, 0x01}));
CAF_CHECK_EQUAL(from_string("::ffff:127.0.0.1"),
addr({}, {0xFFFF, 0x7F00, 0x0001}));
CAF_CHECK_EQUAL(from_string("1:2:3:4:5:6:7:8"), addr({1,2,3,4,5,6,7,8}));
CAF_CHECK_EQUAL(from_string("1:2:3:4::5:6:7:8"), addr({1,2,3,4,5,6,7,8}));
CAF_CHECK_EQUAL(from_string("1:2:3:4:5:6:0.7.0.8"), addr({1,2,3,4,5,6,7,8}));
auto invalid = [](string_view str) {
ipv6_address result;
auto err = parse(str, result);
return err != none;
};
CAF_CHECK(invalid("1:2:3:4:5:6:7:8:9"));
CAF_CHECK(invalid("1:2:3:4::5:6:7:8:9"));
CAF_CHECK(invalid("1:2:3::4:5:6::7:8:9"));
}
CAF_TEST(to string) {
CAF_CHECK_EQUAL(to_string(addr({}, {0x01})), "::1");
CAF_CHECK_EQUAL(to_string(addr({0x01}, {0x01})), "1::1");
CAF_CHECK_EQUAL(to_string(addr({0x01})), "1::");
CAF_CHECK_EQUAL(to_string(addr({}, {0xFFFF, 0x01, 0x01})), "0.1.0.1");
}
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE ipv6_subnet
#include "caf/test/dsl.hpp"
#include "caf/ipv6_subnet.hpp"
using namespace caf;
namespace {
ipv6_subnet operator/(ipv6_address addr, uint8_t prefix) {
return {addr, prefix};
}
} // namespace <anonymous>
CAF_TEST(constructing) {
auto zero = ipv6_address() / 128;
CAF_CHECK_EQUAL(zero.network_address(), ipv6_address());
CAF_CHECK_EQUAL(zero.prefix_length(), 128u);
}
CAF_TEST(constains) {
auto local = ipv6_address{{0xbebe, 0xbebe}, {}} / 32;
CAF_CHECK(local.contains(ipv6_address({0xbebe, 0xbebe, 0xbebe}, {})));
CAF_CHECK(!local.contains(ipv6_address({0xbebe, 0xbebf}, {})));
}
CAF_TEST(embedding) {
ipv4_subnet v4_local{ipv4_address({127, 0, 0, 1}), 8};
ipv6_subnet local{v4_local};
CAF_CHECK(local.embeds_v4());
CAF_CHECK_EQUAL(local.prefix_length(), 104u);
}
...@@ -99,7 +99,9 @@ CAF_TEST(compare) { ...@@ -99,7 +99,9 @@ CAF_TEST(compare) {
CAF_CHECK(x.compare(0, 3, "abc") == 0); CAF_CHECK(x.compare(0, 3, "abc") == 0);
CAF_CHECK(x.compare(1, 2, y, 0, 2) == 0); CAF_CHECK(x.compare(1, 2, y, 0, 2) == 0);
CAF_CHECK(x.compare(2, 1, z, 0, 1) == 0); CAF_CHECK(x.compare(2, 1, z, 0, 1) == 0);
CAF_CHECK(x.compare(2, 1, z, 0, 2) == 0); CAF_CHECK(x.compare(2, 1, z, 0, 1) == 0);
// make sure substrings aren't equal
CAF_CHECK(string_view("a/") != string_view("a/b"));
} }
CAF_TEST(copy) { CAF_TEST(copy) {
......
This diff is collapsed.
...@@ -328,7 +328,7 @@ public: ...@@ -328,7 +328,7 @@ public:
} }
inline void log(level lvl, const std::nullptr_t&) { inline void log(level lvl, const std::nullptr_t&) {
log(lvl, "<null>"); log(lvl, "null");
} }
/// Output stream for logging purposes. /// Output stream for logging purposes.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment