From 7869ef2ace9a487abb0b489ca432b0a8878c5083 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 2 Nov 2013 03:19:24 +0100 Subject: First step of the connection skeleton Basic connect, socket creating, polling, recving, etc. --- src/utils/scopeguard.hpp | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/utils/scopeguard.hpp (limited to 'src/utils') diff --git a/src/utils/scopeguard.hpp b/src/utils/scopeguard.hpp new file mode 100644 index 0000000..df78831 --- /dev/null +++ b/src/utils/scopeguard.hpp @@ -0,0 +1,89 @@ +#ifndef SCOPEGUARD_HPP +#define SCOPEGUARD_HPP + +#include +#include + +/** + * A class to be used to make sure some functions are called when the scope + * is left, because they will be called in the ScopeGuard's destructor. It + * can for example be used to delete some pointer whenever any exception is + * called. Example: + + * { + * ScopeGuard scope; + * int* number = new int(2); + * scope.add_callback([number]() { delete number; }); + * // Do some other stuff with the number. But these stuff might throw an exception: + * throw std::runtime_error("Some error not caught here, but in our caller"); + * return true; + * } + + * In this example, our pointer will always be deleted, even when the + * exception is thrown. If we want the functions to be called only when the + * scope is left because of an unexpected exception, we can use + * ScopeGuard::disable(); + */ + +namespace utils +{ + +class ScopeGuard +{ +public: + /** + * The constructor can take a callback. But additional callbacks can be + * added later with add_callback() + */ + explicit ScopeGuard(std::function&& func): + enabled(true) + { + this->add_callback(std::move(func)); + } + /** + * default constructor, the scope guard is enabled but empty, use + * add_callback() + */ + explicit ScopeGuard(): + enabled(true) + { + } + /** + * Call all callbacks in the desctructor, unless it has been disabled. + */ + ~ScopeGuard() + { + if (this->enabled) + for (auto& func: this->callbacks) + func(); + } + /** + * Add a callback to be called in our destructor, one scope guard can be + * used for more than one task, if needed. + */ + void add_callback(std::function&& func) + { + this->callbacks.emplace_back(std::move(func)); + } + /** + * Disable that scope guard, nothing will be done when the scope is + * exited. + */ + void disable() + { + this->enabled = false; + } + +private: + bool enabled; + std::vector> callbacks; + + ScopeGuard(const ScopeGuard&) = delete; + ScopeGuard& operator=(ScopeGuard&&) = delete; + ScopeGuard(ScopeGuard&&) = delete; + ScopeGuard& operator=(const ScopeGuard&) = delete; +}; + +} + +#endif -- cgit v1.2.3 From 4b76a30d0479f366374c7dcf99ac211038722503 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 6 Nov 2013 20:56:59 +0100 Subject: Add make_unique.hpp and split.hpp --- src/utils/make_unique.hpp | 78 +++++++++++++++++++++++++++++++++++++++++++++++ src/utils/split.hpp | 21 +++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 src/utils/make_unique.hpp create mode 100644 src/utils/split.hpp (limited to 'src/utils') diff --git a/src/utils/make_unique.hpp b/src/utils/make_unique.hpp new file mode 100644 index 0000000..67964c8 --- /dev/null +++ b/src/utils/make_unique.hpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2012 Nathan L. Binkert + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MAKE_UNIQUE_HH__ +#define __MAKE_UNIQUE_HH__ + +#include + +namespace std { +namespace detail { + +// helper to construct a non-array unique_ptr +template +struct make_unique_helper { + typedef std::unique_ptr unique_ptr; + + template + static inline unique_ptr make(Args&&... args) { + return unique_ptr(new T(std::forward(args)...)); + } +}; + +// helper to construct an array unique_ptr +template +struct make_unique_helper { + typedef std::unique_ptr unique_ptr; + + template + static inline unique_ptr make(Args&&... args) { + return unique_ptr(new T[sizeof...(Args)]{std::forward(args)...}); +} +}; + +// helper to construct an array unique_ptr with specified extent +template +struct make_unique_helper { + typedef std::unique_ptr unique_ptr; + + template + static inline unique_ptr make(Args&&... args) { + static_assert(N >= sizeof...(Args), + "For make_unique N must be as largs as the number of arguments"); + return unique_ptr(new T[N]{std::forward(args)...}); + } + +#if __GNUC__ == 4 && __GNUC_MINOR__ <= 6 + // G++ 4.6 has an ICE when you have no arguments + static inline unique_ptr make() { + return unique_ptr(new T[N]); + } +#endif +}; + + +} // namespace detail + +template +inline typename detail::make_unique_helper::unique_ptr +make_unique(Args&&... args) { + return detail::make_unique_helper::make(std::forward(args)...); +} + +} // namespace std + +#endif // __MAKE_UNIQUE_HH__ diff --git a/src/utils/split.hpp b/src/utils/split.hpp new file mode 100644 index 0000000..0067131 --- /dev/null +++ b/src/utils/split.hpp @@ -0,0 +1,21 @@ +#ifndef SPLIT_INCLUDED +# define SPLIT_INCLUDED + +#include +#include +#include + +namespace utils +{ + std::vector split(const std::string &s, const char delim) + { + std::vector ret; + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) + ret.emplace_back(std::move(item)); + return ret; + } +} + +#endif // SPLIT_INCLUDED -- cgit v1.2.3 From ccebe901d7d76dfddc082d994efa54ef2aefee57 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 9 Nov 2013 06:01:47 +0100 Subject: Check UTF-8 encoding, and convert strings to UTF-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle conversion errors properly by inserting � instead. Add a binary header to provide portable way to write binary literals (I like them) Also add a test file. ref #2404 --- src/utils/binary.hpp | 16 ++++++ src/utils/encoding.cpp | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ src/utils/encoding.hpp | 21 ++++++++ 3 files changed, 176 insertions(+) create mode 100644 src/utils/binary.hpp create mode 100644 src/utils/encoding.cpp create mode 100644 src/utils/encoding.hpp (limited to 'src/utils') diff --git a/src/utils/binary.hpp b/src/utils/binary.hpp new file mode 100644 index 0000000..10807bc --- /dev/null +++ b/src/utils/binary.hpp @@ -0,0 +1,16 @@ +#ifndef BINARY_INCLUDED +# define BINARY_INCLUDED + +template struct binary +{ + static_assert(FIRST == '0' || FIRST == '1', "invalid binary digit" ); + enum { value = ((FIRST - '0') << sizeof...(REST)) + binary::value }; +}; + +template<> struct binary<'0'> { enum { value = 0 }; }; +template<> struct binary<'1'> { enum { value = 1 }; }; + +template inline +constexpr unsigned int operator "" _b() { return binary::value; } + +#endif // BINARY_INCLUDED diff --git a/src/utils/encoding.cpp b/src/utils/encoding.cpp new file mode 100644 index 0000000..a1bc01b --- /dev/null +++ b/src/utils/encoding.cpp @@ -0,0 +1,139 @@ +#include +#include + +#include + +#include +#include +#include + +/** + * The UTF-8-encoded character used as a place holder when a character conversion fails. + * This is U+FFFD � "replacement character" + */ +static const char* invalid_char = "\xef\xbf\xbd"; +static const size_t invalid_char_len = 3; + +namespace utils +{ + /** + * Based on http://en.wikipedia.org/wiki/UTF-8#Description + */ + bool is_valid_utf8(const char* s) + { + if (!s) + return false; + + const unsigned char* str = reinterpret_cast(s); + + while (*str) + { + // 4 bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + if ((str[0] & 11111000_b) == 11110000_b) + { + if (!str[1] || !str[2] || !str[3] + || ((str[1] & 11000000_b) != 10000000_b) + || ((str[2] & 11000000_b) != 10000000_b) + || ((str[3] & 11000000_b) != 10000000_b)) + return false; + str += 4; + } + // 3 bytes: 1110xxx 10xxxxxx 10xxxxxx + else if ((str[0] & 11110000_b) == 11100000_b) + { + if (!str[1] || !str[2] + || ((str[1] & 11000000_b) != 10000000_b) + || ((str[2] & 11000000_b) != 10000000_b)) + return false; + str += 3; + } + // 2 bytes: 110xxxxx 10xxxxxx + else if (((str[0]) & 11100000_b) == 11000000_b) + { + if (!str[1] || + ((str[1] & 11000000_b) != 10000000_b)) + return false; + str += 2; + } + // 1 byte: 0xxxxxxx + else if ((str[0] & 10000000_b) != 0) + return false; + else + str++; + } + return true; + } + + std::string convert_to_utf8(const std::string& str, const char* charset) + { + std::string res; + + const iconv_t cd = iconv_open("UTF-8", charset); + if (cd == (iconv_t)-1) + throw std::runtime_error("Cannot convert into UTF-8"); + + // Make sure cd is always closed when we leave this function + ScopeGuard sg([&]{ iconv_close(cd); }); + + // iconv will not attempt to modify this buffer, but it still requires + // a char**. + size_t inbytesleft = str.size(); + char* inbuf_ptr = const_cast(str.c_str()); + + size_t outbytesleft = str.size() * 4; + char* outbuf = new char[outbytesleft]; + char* outbuf_ptr = outbuf; + + // Make sure outbuf is always deleted when we leave this function + sg.add_callback([&]{ delete[] outbuf; }); + + bool done = false; + while (done == false) + { + size_t error = iconv(cd, &inbuf_ptr, &inbytesleft, &outbuf_ptr, &outbytesleft); + if ((size_t)-1 == error) + { + switch (errno) + { + case EILSEQ: + // Invalid byte found. Insert a placeholder instead of the + // converted character, jump one byte and continue + memcpy(outbuf_ptr, invalid_char, invalid_char_len); + outbuf_ptr += invalid_char_len; + inbytesleft--; + inbuf_ptr++; + break; + case EINVAL: + // A multibyte sequence is not terminated, but we can't + // provide any more data, so we just add a placeholder to + // indicate that the character is not properly converted, + // and we stop the conversion + memcpy(outbuf_ptr, invalid_char, invalid_char_len); + outbuf_ptr += invalid_char_len; + outbuf_ptr++; + done = true; + break; + case E2BIG: + // This should never happen + done = true; + default: + // This should happen even neverer + done = true; + break; + } + } + else + { + // The conversion finished without any error, stop converting + done = true; + } + } + // Terminate the converted buffer, and copy that buffer it into the + // string we return + *outbuf_ptr = '\0'; + res = outbuf; + return res; + } + +} + diff --git a/src/utils/encoding.hpp b/src/utils/encoding.hpp new file mode 100644 index 0000000..362f1df --- /dev/null +++ b/src/utils/encoding.hpp @@ -0,0 +1,21 @@ +#ifndef ENCODING_INCLUDED +# define ENCODING_INCLUDED + +#include + +namespace utils +{ + /** + * Returns true if the given null-terminated string is valid utf-8. + * + * Based on http://en.wikipedia.org/wiki/UTF-8#Description + */ + bool is_valid_utf8(const char* s); + /** + * Convert the given string (encoded is "encoding") into valid utf-8. + * If some decoding fails, insert an utf-8 placeholder character instead. + */ + std::string convert_to_utf8(const std::string& str, const char* encoding); +} + +#endif // ENCODING_INCLUDED -- cgit v1.2.3 From ef014f7ddf8fd603a4238f5ed4878d7038ce162d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 10 Nov 2013 03:18:08 +0100 Subject: Properly detect iconv features to compile --- src/utils/encoding.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/utils') diff --git a/src/utils/encoding.cpp b/src/utils/encoding.cpp index a1bc01b..2a6aecb 100644 --- a/src/utils/encoding.cpp +++ b/src/utils/encoding.cpp @@ -75,10 +75,15 @@ namespace utils // Make sure cd is always closed when we leave this function ScopeGuard sg([&]{ iconv_close(cd); }); - // iconv will not attempt to modify this buffer, but it still requires - // a char**. size_t inbytesleft = str.size(); + + // iconv will not attempt to modify this buffer, but some plateform + // require a char** anyway +#ifdef ICONV_SECOND_ARGUMENT_IS_CONST + const char* inbuf_ptr = str.c_str(); +#else char* inbuf_ptr = const_cast(str.c_str()); +#endif size_t outbytesleft = str.size() * 4; char* outbuf = new char[outbytesleft]; -- cgit v1.2.3 From 5cb81cace08b016f50708bb8ef718e07865b435a Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 10 Nov 2013 03:29:12 +0100 Subject: And actually use the values found by cmake --- src/utils/encoding.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/utils') diff --git a/src/utils/encoding.cpp b/src/utils/encoding.cpp index 2a6aecb..2d95132 100644 --- a/src/utils/encoding.cpp +++ b/src/utils/encoding.cpp @@ -7,6 +7,8 @@ #include #include +#include "config.h" + /** * The UTF-8-encoded character used as a place holder when a character conversion fails. * This is U+FFFD � "replacement character" -- cgit v1.2.3 From af4fc92c215e48cf13be36a1f8e8e1a821dabb5a Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 10 Nov 2013 03:35:31 +0100 Subject: Fix the include of the config.h --- src/utils/encoding.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils') diff --git a/src/utils/encoding.cpp b/src/utils/encoding.cpp index 2d95132..634964b 100644 --- a/src/utils/encoding.cpp +++ b/src/utils/encoding.cpp @@ -7,7 +7,7 @@ #include #include -#include "config.h" +#include /** * The UTF-8-encoded character used as a place holder when a character conversion fails. -- cgit v1.2.3 From 5817a95b5ee89480788832be35679dfcd2ed833b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 12 Nov 2013 23:43:43 +0100 Subject: Basic handling of modes, both ways --- src/utils/split.cpp | 18 ++++++++++++++++++ src/utils/split.hpp | 10 +--------- 2 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 src/utils/split.cpp (limited to 'src/utils') diff --git a/src/utils/split.cpp b/src/utils/split.cpp new file mode 100644 index 0000000..82852ee --- /dev/null +++ b/src/utils/split.cpp @@ -0,0 +1,18 @@ +#include + +namespace utils +{ + std::vector split(const std::string &s, const char delim, const bool allow_empty) + { + std::vector ret; + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) + { + if (item.empty() && !allow_empty) + continue ; + ret.emplace_back(std::move(item)); + } + return ret; + } +} diff --git a/src/utils/split.hpp b/src/utils/split.hpp index 0067131..9fee90a 100644 --- a/src/utils/split.hpp +++ b/src/utils/split.hpp @@ -7,15 +7,7 @@ namespace utils { - std::vector split(const std::string &s, const char delim) - { - std::vector ret; - std::stringstream ss(s); - std::string item; - while (std::getline(ss, item, delim)) - ret.emplace_back(std::move(item)); - return ret; - } + std::vector split(const std::string &s, const char delim, const bool allow_empty=true); } #endif // SPLIT_INCLUDED -- cgit v1.2.3 From bfcc9cdc7462c515c308592735bc661103fb92b5 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 21 Nov 2013 00:58:14 +0100 Subject: Send XMPP multi-line messages as multiple IRC messages --- src/utils/split.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils') diff --git a/src/utils/split.cpp b/src/utils/split.cpp index 82852ee..afe4300 100644 --- a/src/utils/split.cpp +++ b/src/utils/split.cpp @@ -2,7 +2,7 @@ namespace utils { - std::vector split(const std::string &s, const char delim, const bool allow_empty) + std::vector split(const std::string& s, const char delim, const bool allow_empty) { std::vector ret; std::stringstream ss(s); -- cgit v1.2.3 From 1151c26c363e736a98c5fcb723c753658fe35b9b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 28 Nov 2013 02:14:42 +0100 Subject: Channel names are case insensitive But some servers (epiknet for example) send channel names with an uppercase --- src/utils/tolower.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/utils/tolower.hpp (limited to 'src/utils') diff --git a/src/utils/tolower.hpp b/src/utils/tolower.hpp new file mode 100644 index 0000000..22d2b8f --- /dev/null +++ b/src/utils/tolower.hpp @@ -0,0 +1,18 @@ +#ifndef TOLOWER_INCLUDED +# define TOLOWER_INCLUDED + +#include + +namespace utils +{ + std::string tolower(const std::string& original) + { + std::string res; + res.reserve(original.size()); + for (const char c: original) + res += static_cast(std::tolower(c)); + return res; + } +} + +#endif // SPLIT_INCLUDED -- cgit v1.2.3 From cb718def0cb51aac4c2125e3864522740fcb2573 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 8 Dec 2013 18:02:24 +0100 Subject: Put utils::tolower definition in its own cpp file --- src/utils/tolower.cpp | 13 +++++++++++++ src/utils/tolower.hpp | 9 +-------- 2 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 src/utils/tolower.cpp (limited to 'src/utils') diff --git a/src/utils/tolower.cpp b/src/utils/tolower.cpp new file mode 100644 index 0000000..3e518bd --- /dev/null +++ b/src/utils/tolower.cpp @@ -0,0 +1,13 @@ +#include + +namespace utils +{ + std::string tolower(const std::string& original) + { + std::string res; + res.reserve(original.size()); + for (const char c: original) + res += static_cast(std::tolower(c)); + return res; + } +} diff --git a/src/utils/tolower.hpp b/src/utils/tolower.hpp index 22d2b8f..0019182 100644 --- a/src/utils/tolower.hpp +++ b/src/utils/tolower.hpp @@ -5,14 +5,7 @@ namespace utils { - std::string tolower(const std::string& original) - { - std::string res; - res.reserve(original.size()); - for (const char c: original) - res += static_cast(std::tolower(c)); - return res; - } + std::string tolower(const std::string& original); } #endif // SPLIT_INCLUDED -- cgit v1.2.3 From 3960e4d5afa09c299f595b411ee8522db30580fd Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 11 Dec 2013 21:07:39 +0100 Subject: Functions to provide xml-valid strings By removing invalid chars, see http://www.w3.org/TR/xml/#charsets --- src/utils/encoding.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils/encoding.hpp | 8 ++++++ 2 files changed, 81 insertions(+) (limited to 'src/utils') diff --git a/src/utils/encoding.cpp b/src/utils/encoding.cpp index 634964b..76d1922 100644 --- a/src/utils/encoding.cpp +++ b/src/utils/encoding.cpp @@ -9,6 +9,8 @@ #include +#include + /** * The UTF-8-encoded character used as a place holder when a character conversion fails. * This is U+FFFD � "replacement character" @@ -66,6 +68,77 @@ namespace utils return true; } + std::string remove_invalid_xml_chars(const std::string& original) + { + // The given string MUST be a valid utf-8 string + unsigned char* res = new unsigned char[original.size()]; + ScopeGuard sg([&res]() { delete[] res;}); + + // pointer where we write valid chars + unsigned char* r = res; + + const unsigned char* str = reinterpret_cast(original.c_str()); + std::bitset<20> codepoint; + + while (*str) + { + // 4 bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + if ((str[0] & 11111000_b) == 11110000_b) + { + codepoint = ((str[0] & 00000111_b) << 18); + codepoint |= ((str[1] & 00111111_b) << 12); + codepoint |= ((str[2] & 00111111_b) << 6 ); + codepoint |= ((str[3] & 00111111_b) << 0 ); + if (codepoint.to_ulong() <= 0x10FFFF) + { + ::memcpy(r, str, 4); + r += 4; + } + str += 4; + } + // 3 bytes: 1110xxx 10xxxxxx 10xxxxxx + else if ((str[0] & 11110000_b) == 11100000_b) + { + codepoint = ((str[0] & 00001111_b) << 12); + codepoint |= ((str[1] & 00111111_b) << 6); + codepoint |= ((str[2] & 00111111_b) << 0 ); + if (codepoint.to_ulong() <= 0xD7FF || + (codepoint.to_ulong() >= 0xE000 && codepoint.to_ulong() <= 0xFFFD)) + { + ::memcpy(r, str, 3); + r += 3; + } + str += 3; + } + // 2 bytes: 110xxxxx 10xxxxxx + else if (((str[0]) & 11100000_b) == 11000000_b) + { + // All 2 bytes char are valid, don't even bother calculating + // the codepoint + ::memcpy(r, str, 2); + r += 2; + str += 2; + } + // 1 byte: 0xxxxxxx + else if ((str[0] & 10000000_b) == 0) + { + codepoint = ((str[0] & 01111111_b)); + if (codepoint.to_ulong() == 0x09 || + codepoint.to_ulong() == 0x0A || + codepoint.to_ulong() == 0x0D || + codepoint.to_ulong() >= 0x20) + { + ::memcpy(r, str, 1); + r += 1; + } + str += 1; + } + else + throw std::runtime_error("Invalid UTF-8 passed to remove_invalid_xml_chars"); + } + return std::string(reinterpret_cast(res), r-res); + } + std::string convert_to_utf8(const std::string& str, const char* charset) { std::string res; diff --git a/src/utils/encoding.hpp b/src/utils/encoding.hpp index 362f1df..a3bccfc 100644 --- a/src/utils/encoding.hpp +++ b/src/utils/encoding.hpp @@ -11,6 +11,14 @@ namespace utils * Based on http://en.wikipedia.org/wiki/UTF-8#Description */ bool is_valid_utf8(const char* s); + /** + * Remove all invalid codepoints from the given utf-8-encoded string. + * The value returned is a copy of the string, without the removed chars. + * + * See http://www.w3.org/TR/xml/#charsets for the list of valid characters + * in XML. + */ + std::string remove_invalid_xml_chars(const std::string& original); /** * Convert the given string (encoded is "encoding") into valid utf-8. * If some decoding fails, insert an utf-8 placeholder character instead. -- cgit v1.2.3 From 48b4f7b83f9f8e6d89d56f5e24f0ed1d7c4676a1 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 12 Jan 2014 04:12:27 +0100 Subject: Remove cryptopp dependency, directly include a simple sha1 implementation --- src/utils/sha1.cpp | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils/sha1.hpp | 35 ++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 src/utils/sha1.cpp create mode 100644 src/utils/sha1.hpp (limited to 'src/utils') diff --git a/src/utils/sha1.cpp b/src/utils/sha1.cpp new file mode 100644 index 0000000..76476df --- /dev/null +++ b/src/utils/sha1.cpp @@ -0,0 +1,154 @@ +/* This code is public-domain - it is based on libcrypt + * placed in the public domain by Wei Dai and other contributors. + */ + +#include "sha1.hpp" + +#define SHA1_K0 0x5a827999 +#define SHA1_K20 0x6ed9eba1 +#define SHA1_K40 0x8f1bbcdc +#define SHA1_K60 0xca62c1d6 + +const uint8_t sha1InitState[] = { + 0x01,0x23,0x45,0x67, // H0 + 0x89,0xab,0xcd,0xef, // H1 + 0xfe,0xdc,0xba,0x98, // H2 + 0x76,0x54,0x32,0x10, // H3 + 0xf0,0xe1,0xd2,0xc3 // H4 +}; + +void sha1_init(sha1nfo *s) { + memcpy(s->state.b,sha1InitState,HASH_LENGTH); + s->byteCount = 0; + s->bufferOffset = 0; +} + +uint32_t sha1_rol32(uint32_t number, uint8_t bits) { + return ((number << bits) | (number >> (32-bits))); +} + +void sha1_hashBlock(sha1nfo *s) { + uint8_t i; + uint32_t a,b,c,d,e,t; + + a=s->state.w[0]; + b=s->state.w[1]; + c=s->state.w[2]; + d=s->state.w[3]; + e=s->state.w[4]; + for (i=0; i<80; i++) { + if (i>=16) { + t = s->buffer.w[(i+13)&15] ^ s->buffer.w[(i+8)&15] ^ s->buffer.w[(i+2)&15] ^ s->buffer.w[i&15]; + s->buffer.w[i&15] = sha1_rol32(t,1); + } + if (i<20) { + t = (d ^ (b & (c ^ d))) + SHA1_K0; + } else if (i<40) { + t = (b ^ c ^ d) + SHA1_K20; + } else if (i<60) { + t = ((b & c) | (d & (b | c))) + SHA1_K40; + } else { + t = (b ^ c ^ d) + SHA1_K60; + } + t+=sha1_rol32(a,5) + e + s->buffer.w[i&15]; + e=d; + d=c; + c=sha1_rol32(b,30); + b=a; + a=t; + } + s->state.w[0] += a; + s->state.w[1] += b; + s->state.w[2] += c; + s->state.w[3] += d; + s->state.w[4] += e; +} + +void sha1_addUncounted(sha1nfo *s, uint8_t data) { + s->buffer.b[s->bufferOffset ^ 3] = data; + s->bufferOffset++; + if (s->bufferOffset == BLOCK_LENGTH) { + sha1_hashBlock(s); + s->bufferOffset = 0; + } +} + +void sha1_writebyte(sha1nfo *s, uint8_t data) { + ++s->byteCount; + sha1_addUncounted(s, data); +} + +void sha1_write(sha1nfo *s, const char *data, size_t len) { + for (;len--;) sha1_writebyte(s, (uint8_t) *data++); +} + +void sha1_pad(sha1nfo *s) { + // Implement SHA-1 padding (fips180-2 §5.1.1) + + // Pad with 0x80 followed by 0x00 until the end of the block + sha1_addUncounted(s, 0x80); + while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00); + + // Append length in the last 8 bytes + sha1_addUncounted(s, 0); // We're only using 32 bit lengths + sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths + sha1_addUncounted(s, 0); // So zero pad the top bits + sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8 + sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as + sha1_addUncounted(s, s->byteCount >> 13); // byte. + sha1_addUncounted(s, s->byteCount >> 5); + sha1_addUncounted(s, s->byteCount << 3); +} + +uint8_t* sha1_result(sha1nfo *s) { + int i; + // Pad to complete the last block + sha1_pad(s); + + // Swap byte order back + for (i=0; i<5; i++) { + uint32_t a,b; + a=s->state.w[i]; + b=a<<24; + b|=(a<<8) & 0x00ff0000; + b|=(a>>8) & 0x0000ff00; + b|=a>>24; + s->state.w[i]=b; + } + + // Return pointer to hash (20 characters) + return s->state.b; +} + +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5c + +void sha1_initHmac(sha1nfo *s, const uint8_t* key, int keyLength) { + uint8_t i; + memset(s->keyBuffer, 0, BLOCK_LENGTH); + if (keyLength > BLOCK_LENGTH) { + // Hash long keys + sha1_init(s); + for (;keyLength--;) sha1_writebyte(s, *key++); + memcpy(s->keyBuffer, sha1_result(s), HASH_LENGTH); + } else { + // Block length keys are used as is + memcpy(s->keyBuffer, key, keyLength); + } + // Start inner hash + sha1_init(s); + for (i=0; ikeyBuffer[i] ^ HMAC_IPAD); + } +} + +uint8_t* sha1_resultHmac(sha1nfo *s) { + uint8_t i; + // Complete inner hash + memcpy(s->innerHash,sha1_result(s),HASH_LENGTH); + // Calculate outer hash + sha1_init(s); + for (i=0; ikeyBuffer[i] ^ HMAC_OPAD); + for (i=0; iinnerHash[i]); + return sha1_result(s); +} diff --git a/src/utils/sha1.hpp b/src/utils/sha1.hpp new file mode 100644 index 0000000..d02de75 --- /dev/null +++ b/src/utils/sha1.hpp @@ -0,0 +1,35 @@ +/* This code is public-domain - it is based on libcrypt + * placed in the public domain by Wei Dai and other contributors. + */ + +#include +#include + +#define HASH_LENGTH 20 +#define BLOCK_LENGTH 64 + +union _buffer { + uint8_t b[BLOCK_LENGTH]; + uint32_t w[BLOCK_LENGTH/4]; +}; + +union _state { + uint8_t b[HASH_LENGTH]; + uint32_t w[HASH_LENGTH/4]; +}; + +typedef struct sha1nfo { + union _buffer buffer; + uint8_t bufferOffset; + union _state state; + uint32_t byteCount; + uint8_t keyBuffer[BLOCK_LENGTH]; + uint8_t innerHash[HASH_LENGTH]; +} sha1nfo; + +void sha1_init(sha1nfo *s); +void sha1_writebyte(sha1nfo *s, uint8_t data); +void sha1_write(sha1nfo *s, const char *data, size_t len); +uint8_t* sha1_result(sha1nfo *s); +void sha1_initHmac(sha1nfo *s, const uint8_t* key, int keyLength); +uint8_t* sha1_resultHmac(sha1nfo *s); -- cgit v1.2.3 From d1c6d64546f5b139ec7946696602be5fe9fca66e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 13 Jan 2014 20:19:10 +0100 Subject: Add missing stdexcept includes --- src/utils/encoding.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/utils') diff --git a/src/utils/encoding.cpp b/src/utils/encoding.cpp index 76d1922..fa4958b 100644 --- a/src/utils/encoding.cpp +++ b/src/utils/encoding.cpp @@ -3,6 +3,8 @@ #include +#include + #include #include #include -- cgit v1.2.3 From c6059e5a215624e205cae401183f3a8bb1bf87d0 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 28 Apr 2014 18:46:25 +0200 Subject: Upgrade to C++14 --- src/utils/make_unique.hpp | 78 ----------------------------------------------- 1 file changed, 78 deletions(-) delete mode 100644 src/utils/make_unique.hpp (limited to 'src/utils') diff --git a/src/utils/make_unique.hpp b/src/utils/make_unique.hpp deleted file mode 100644 index 67964c8..0000000 --- a/src/utils/make_unique.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2012 Nathan L. Binkert - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef __MAKE_UNIQUE_HH__ -#define __MAKE_UNIQUE_HH__ - -#include - -namespace std { -namespace detail { - -// helper to construct a non-array unique_ptr -template -struct make_unique_helper { - typedef std::unique_ptr unique_ptr; - - template - static inline unique_ptr make(Args&&... args) { - return unique_ptr(new T(std::forward(args)...)); - } -}; - -// helper to construct an array unique_ptr -template -struct make_unique_helper { - typedef std::unique_ptr unique_ptr; - - template - static inline unique_ptr make(Args&&... args) { - return unique_ptr(new T[sizeof...(Args)]{std::forward(args)...}); -} -}; - -// helper to construct an array unique_ptr with specified extent -template -struct make_unique_helper { - typedef std::unique_ptr unique_ptr; - - template - static inline unique_ptr make(Args&&... args) { - static_assert(N >= sizeof...(Args), - "For make_unique N must be as largs as the number of arguments"); - return unique_ptr(new T[N]{std::forward(args)...}); - } - -#if __GNUC__ == 4 && __GNUC_MINOR__ <= 6 - // G++ 4.6 has an ICE when you have no arguments - static inline unique_ptr make() { - return unique_ptr(new T[N]); - } -#endif -}; - - -} // namespace detail - -template -inline typename detail::make_unique_helper::unique_ptr -make_unique(Args&&... args) { - return detail::make_unique_helper::make(std::forward(args)...); -} - -} // namespace std - -#endif // __MAKE_UNIQUE_HH__ -- cgit v1.2.3 From 594bac1e841588aef66efc208a295e08273aec32 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 28 Apr 2014 19:44:09 +0200 Subject: Remove binary.hpp and use the c++14 feature 0b --- src/utils/binary.hpp | 16 ---------------- src/utils/encoding.cpp | 45 ++++++++++++++++++++++----------------------- 2 files changed, 22 insertions(+), 39 deletions(-) delete mode 100644 src/utils/binary.hpp (limited to 'src/utils') diff --git a/src/utils/binary.hpp b/src/utils/binary.hpp deleted file mode 100644 index 10807bc..0000000 --- a/src/utils/binary.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef BINARY_INCLUDED -# define BINARY_INCLUDED - -template struct binary -{ - static_assert(FIRST == '0' || FIRST == '1', "invalid binary digit" ); - enum { value = ((FIRST - '0') << sizeof...(REST)) + binary::value }; -}; - -template<> struct binary<'0'> { enum { value = 0 }; }; -template<> struct binary<'1'> { enum { value = 1 }; }; - -template inline -constexpr unsigned int operator "" _b() { return binary::value; } - -#endif // BINARY_INCLUDED diff --git a/src/utils/encoding.cpp b/src/utils/encoding.cpp index fa4958b..dc0101c 100644 --- a/src/utils/encoding.cpp +++ b/src/utils/encoding.cpp @@ -1,5 +1,4 @@ #include -#include #include @@ -35,34 +34,34 @@ namespace utils while (*str) { // 4 bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - if ((str[0] & 11111000_b) == 11110000_b) + if ((str[0] & 0b11111000) == 0b11110000) { if (!str[1] || !str[2] || !str[3] - || ((str[1] & 11000000_b) != 10000000_b) - || ((str[2] & 11000000_b) != 10000000_b) - || ((str[3] & 11000000_b) != 10000000_b)) + || ((str[1] & 0b11000000) != 0b10000000) + || ((str[2] & 0b11000000) != 0b10000000) + || ((str[3] & 0b11000000) != 0b10000000)) return false; str += 4; } // 3 bytes: 1110xxx 10xxxxxx 10xxxxxx - else if ((str[0] & 11110000_b) == 11100000_b) + else if ((str[0] & 0b11110000) == 0b11100000) { if (!str[1] || !str[2] - || ((str[1] & 11000000_b) != 10000000_b) - || ((str[2] & 11000000_b) != 10000000_b)) + || ((str[1] & 0b11000000) != 0b10000000) + || ((str[2] & 0b11000000) != 0b10000000)) return false; str += 3; } // 2 bytes: 110xxxxx 10xxxxxx - else if (((str[0]) & 11100000_b) == 11000000_b) + else if (((str[0]) & 0b11100000) == 0b11000000) { if (!str[1] || - ((str[1] & 11000000_b) != 10000000_b)) + ((str[1] & 0b11000000) != 0b10000000)) return false; str += 2; } // 1 byte: 0xxxxxxx - else if ((str[0] & 10000000_b) != 0) + else if ((str[0] & 0b10000000) != 0) return false; else str++; @@ -85,12 +84,12 @@ namespace utils while (*str) { // 4 bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - if ((str[0] & 11111000_b) == 11110000_b) + if ((str[0] & 0b11111000) == 0b11110000) { - codepoint = ((str[0] & 00000111_b) << 18); - codepoint |= ((str[1] & 00111111_b) << 12); - codepoint |= ((str[2] & 00111111_b) << 6 ); - codepoint |= ((str[3] & 00111111_b) << 0 ); + codepoint = ((str[0] & 0b00000111) << 18); + codepoint |= ((str[1] & 0b00111111) << 12); + codepoint |= ((str[2] & 0b00111111) << 6 ); + codepoint |= ((str[3] & 0b00111111) << 0 ); if (codepoint.to_ulong() <= 0x10FFFF) { ::memcpy(r, str, 4); @@ -99,11 +98,11 @@ namespace utils str += 4; } // 3 bytes: 1110xxx 10xxxxxx 10xxxxxx - else if ((str[0] & 11110000_b) == 11100000_b) + else if ((str[0] & 0b11110000) == 0b11100000) { - codepoint = ((str[0] & 00001111_b) << 12); - codepoint |= ((str[1] & 00111111_b) << 6); - codepoint |= ((str[2] & 00111111_b) << 0 ); + codepoint = ((str[0] & 0b00001111) << 12); + codepoint |= ((str[1] & 0b00111111) << 6); + codepoint |= ((str[2] & 0b00111111) << 0 ); if (codepoint.to_ulong() <= 0xD7FF || (codepoint.to_ulong() >= 0xE000 && codepoint.to_ulong() <= 0xFFFD)) { @@ -113,7 +112,7 @@ namespace utils str += 3; } // 2 bytes: 110xxxxx 10xxxxxx - else if (((str[0]) & 11100000_b) == 11000000_b) + else if (((str[0]) & 0b11100000) == 0b11000000) { // All 2 bytes char are valid, don't even bother calculating // the codepoint @@ -122,9 +121,9 @@ namespace utils str += 2; } // 1 byte: 0xxxxxxx - else if ((str[0] & 10000000_b) == 0) + else if ((str[0] & 0b10000000) == 0) { - codepoint = ((str[0] & 01111111_b)); + codepoint = ((str[0] & 0b01111111)); if (codepoint.to_ulong() == 0x09 || codepoint.to_ulong() == 0x0A || codepoint.to_ulong() == 0x0D || -- cgit v1.2.3 From 5999e6e0c32e6897b88f59f0743b4bb1fc9c521c Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 27 May 2014 01:12:46 +0200 Subject: Introduce the timed events --- src/utils/timed_events.cpp | 54 ++++++++++++++++++ src/utils/timed_events.hpp | 111 +++++++++++++++++++++++++++++++++++++ src/utils/timed_events_manager.cpp | 55 ++++++++++++++++++ 3 files changed, 220 insertions(+) create mode 100644 src/utils/timed_events.cpp create mode 100644 src/utils/timed_events.hpp create mode 100644 src/utils/timed_events_manager.cpp (limited to 'src/utils') diff --git a/src/utils/timed_events.cpp b/src/utils/timed_events.cpp new file mode 100644 index 0000000..10ef4c1 --- /dev/null +++ b/src/utils/timed_events.cpp @@ -0,0 +1,54 @@ +#include + +TimedEvent::TimedEvent(std::chrono::steady_clock::time_point&& time_point, + std::function callback): + time_point(std::move(time_point)), + callback(callback), + repeat(false), + repeat_delay(0) +{ +} + +TimedEvent::TimedEvent(std::chrono::milliseconds&& duration, + std::function callback): + time_point(std::chrono::steady_clock::now() + duration), + callback(callback), + repeat(true), + repeat_delay(std::move(duration)) +{ +} + +TimedEvent::TimedEvent(TimedEvent&& other): + time_point(std::move(other.time_point)), + callback(std::move(other.callback)), + repeat(other.repeat), + repeat_delay(std::move(other.repeat_delay)) +{ +} + +TimedEvent::~TimedEvent() +{ +} + +bool TimedEvent::is_after(const TimedEvent& other) const +{ + return this->is_after(other.time_point); +} + +bool TimedEvent::is_after(const std::chrono::steady_clock::time_point& time_point) const +{ + return this->time_point >= time_point; +} + +std::chrono::milliseconds TimedEvent::get_timeout() const +{ + auto now = std::chrono::steady_clock::now(); + if (now > this->time_point) + return std::chrono::milliseconds(0); + return std::chrono::duration_cast(this->time_point - now); +} + +void TimedEvent::execute() +{ + this->callback(); +} diff --git a/src/utils/timed_events.hpp b/src/utils/timed_events.hpp new file mode 100644 index 0000000..9be747d --- /dev/null +++ b/src/utils/timed_events.hpp @@ -0,0 +1,111 @@ +#ifndef TIMED_EVENTS_HPP +# define TIMED_EVENTS_HPP + +#include +#include +#include + +using namespace std::literals::chrono_literals; + +namespace utils { +static constexpr std::chrono::milliseconds no_timeout = std::chrono::milliseconds(-1); +} + +class TimedEventsManager; + +/** + * A callback with an associated date. + */ + +class TimedEvent +{ + friend class TimedEventsManager; +public: + /** + * An event the occurs only once, at the given time_point + */ + explicit TimedEvent(std::chrono::steady_clock::time_point&& time_point, + std::function callback); + explicit TimedEvent(std::chrono::milliseconds&& duration, + std::function callback); + + explicit TimedEvent(TimedEvent&&); + ~TimedEvent(); + /** + * Whether or not this event happens after the other one. + */ + bool is_after(const TimedEvent& other) const; + bool is_after(const std::chrono::steady_clock::time_point& time_point) const; + /** + * Return the duration difference between now and the event time point. + * If the difference would be negative (i.e. the event is expired), the + * returned value is 0 instead. The value cannot then be negative. + */ + std::chrono::milliseconds get_timeout() const; + void execute(); + +private: + /** + * The next time point at which the event is executed. + */ + std::chrono::steady_clock::time_point time_point; + /** + * The function to execute. + */ + const std::function callback; + /** + * Whether or not this events repeats itself until it is destroyed. + */ + const bool repeat; + /** + * This value is added to the time_point each time the event is executed, + * if repeat is true. Otherwise it is ignored. + */ + const std::chrono::milliseconds repeat_delay; + + TimedEvent(const TimedEvent&) = delete; + TimedEvent& operator=(const TimedEvent&) = delete; + TimedEvent& operator=(TimedEvent&&) = delete; +}; + +/** + * A class managing a list of TimedEvents. + * They are sorted, new events can be added, removed, fetch, etc. + */ + +class TimedEventsManager +{ +public: + explicit TimedEventsManager(); + ~TimedEventsManager(); + /** + * Add an event to the list of managed events. The list is sorted after + * this call. + */ + void add_event(TimedEvent&& event); + /** + * Returns the duration, in milliseconds, between now and the next + * available event. If the event is already expired (the duration is + * negative), 0 is returned instead (as in “it's not too late, execute it + * now”) + * Returns a negative value if no event is available. + */ + std::chrono::milliseconds get_timeout() const; + /** + * Execute all the expired events (if their expiration time is exactly + * now, or before now). The event is then removed from the list. If the + * event does repeat, its expiration time is updated and it is reinserted + * in the list at the correct position. + * Returns the number of executed events. + */ + std::size_t execute_expired_events(); + +private: + std::list events; + TimedEventsManager(const TimedEventsManager&) = delete; + TimedEventsManager(TimedEventsManager&&) = delete; + TimedEventsManager& operator=(const TimedEventsManager&) = delete; + TimedEventsManager& operator=(TimedEventsManager&&) = delete; +}; + +#endif // TIMED_EVENTS_HPP diff --git a/src/utils/timed_events_manager.cpp b/src/utils/timed_events_manager.cpp new file mode 100644 index 0000000..c3e260c --- /dev/null +++ b/src/utils/timed_events_manager.cpp @@ -0,0 +1,55 @@ +#include + +TimedEventsManager::TimedEventsManager() +{ +} + +TimedEventsManager::~TimedEventsManager() +{ +} + +void TimedEventsManager::add_event(TimedEvent&& event) +{ + for (auto it = this->events.begin(); it != this->events.end(); ++it) + { + if (it->is_after(event)) + { + this->events.emplace(it, std::move(event)); + return; + } + } + this->events.emplace_back(std::move(event)); +} + +std::chrono::milliseconds TimedEventsManager::get_timeout() const +{ + if (this->events.empty()) + return utils::no_timeout; + return this->events.front().get_timeout() + std::chrono::milliseconds(1); +} + +std::size_t TimedEventsManager::execute_expired_events() +{ + std::size_t count = 0; + const auto now = std::chrono::steady_clock::now(); + for (auto it = this->events.begin(); it != this->events.end();) + { + if (!it->is_after(now)) + { + TimedEvent copy(std::move(*it)); + it = this->events.erase(it); + ++count; + copy.execute(); + if (copy.repeat) + { + copy.time_point += copy.repeat_delay; + this->add_event(std::move(copy)); + } + continue; + } + else + break; + } + return count; +} + -- cgit v1.2.3 From 5cca518c2d946144f4fee1b15dcfd3884850dcb1 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 30 May 2014 15:42:01 +0200 Subject: Timed events can have a name, and can be canceled based on their name --- src/utils/timed_events.cpp | 18 +++++++++++++----- src/utils/timed_events.hpp | 20 ++++++++++++++++++-- src/utils/timed_events_manager.cpp | 20 ++++++++++++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) (limited to 'src/utils') diff --git a/src/utils/timed_events.cpp b/src/utils/timed_events.cpp index 10ef4c1..5010a3f 100644 --- a/src/utils/timed_events.cpp +++ b/src/utils/timed_events.cpp @@ -1,20 +1,22 @@ #include TimedEvent::TimedEvent(std::chrono::steady_clock::time_point&& time_point, - std::function callback): + std::function callback, const std::string& name): time_point(std::move(time_point)), callback(callback), repeat(false), - repeat_delay(0) + repeat_delay(0), + name(name) { } TimedEvent::TimedEvent(std::chrono::milliseconds&& duration, - std::function callback): + std::function callback, const std::string& name): time_point(std::chrono::steady_clock::now() + duration), callback(callback), repeat(true), - repeat_delay(std::move(duration)) + repeat_delay(std::move(duration)), + name(name) { } @@ -22,7 +24,8 @@ TimedEvent::TimedEvent(TimedEvent&& other): time_point(std::move(other.time_point)), callback(std::move(other.callback)), repeat(other.repeat), - repeat_delay(std::move(other.repeat_delay)) + repeat_delay(std::move(other.repeat_delay)), + name(std::move(other.name)) { } @@ -52,3 +55,8 @@ void TimedEvent::execute() { this->callback(); } + +const std::string& TimedEvent::get_name() const +{ + return this->name; +} diff --git a/src/utils/timed_events.hpp b/src/utils/timed_events.hpp index 9be747d..f601cae 100644 --- a/src/utils/timed_events.hpp +++ b/src/utils/timed_events.hpp @@ -25,9 +25,9 @@ public: * An event the occurs only once, at the given time_point */ explicit TimedEvent(std::chrono::steady_clock::time_point&& time_point, - std::function callback); + std::function callback, const std::string& name=""); explicit TimedEvent(std::chrono::milliseconds&& duration, - std::function callback); + std::function callback, const std::string& name=""); explicit TimedEvent(TimedEvent&&); ~TimedEvent(); @@ -43,6 +43,7 @@ public: */ std::chrono::milliseconds get_timeout() const; void execute(); + const std::string& get_name() const; private: /** @@ -62,6 +63,12 @@ private: * if repeat is true. Otherwise it is ignored. */ const std::chrono::milliseconds repeat_delay; + /** + * A name that is used to identify that event. If you want to find your + * event (for example if you want to cancel it), the name should be + * unique. + */ + const std::string name; TimedEvent(const TimedEvent&) = delete; TimedEvent& operator=(const TimedEvent&) = delete; @@ -99,6 +106,15 @@ public: * Returns the number of executed events. */ std::size_t execute_expired_events(); + /** + * Remove (and thus cancel) all the timed events with the given name. + * Returns the number of canceled events. + */ + std::size_t cancel(const std::string& name); + /** + * Return the number of managed events. + */ + std::size_t size() const; private: std::list events; diff --git a/src/utils/timed_events_manager.cpp b/src/utils/timed_events_manager.cpp index c3e260c..a03444e 100644 --- a/src/utils/timed_events_manager.cpp +++ b/src/utils/timed_events_manager.cpp @@ -53,3 +53,23 @@ std::size_t TimedEventsManager::execute_expired_events() return count; } +std::size_t TimedEventsManager::cancel(const std::string& name) +{ + std::size_t res = 0; + for (auto it = this->events.begin(); it != this->events.end();) + { + if (it->get_name() == name) + { + it = this->events.erase(it); + res++; + } + else + ++it; + } + return res; +} + +std::size_t TimedEventsManager::size() const +{ + return this->events.size(); +} -- cgit v1.2.3 From 5c9d2c23ba6a401bc9494a6023491bbf3ade8d34 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 30 May 2014 15:51:43 +0200 Subject: TimedEventsManager is now a singleton --- src/utils/timed_events.hpp | 6 +++++- src/utils/timed_events_manager.cpp | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/utils') diff --git a/src/utils/timed_events.hpp b/src/utils/timed_events.hpp index f601cae..aafe532 100644 --- a/src/utils/timed_events.hpp +++ b/src/utils/timed_events.hpp @@ -83,8 +83,11 @@ private: class TimedEventsManager { public: - explicit TimedEventsManager(); ~TimedEventsManager(); + /** + * Return the unique instance of this class + */ + static TimedEventsManager& instance(); /** * Add an event to the list of managed events. The list is sorted after * this call. @@ -117,6 +120,7 @@ public: std::size_t size() const; private: + explicit TimedEventsManager(); std::list events; TimedEventsManager(const TimedEventsManager&) = delete; TimedEventsManager(TimedEventsManager&&) = delete; diff --git a/src/utils/timed_events_manager.cpp b/src/utils/timed_events_manager.cpp index a03444e..2c75e48 100644 --- a/src/utils/timed_events_manager.cpp +++ b/src/utils/timed_events_manager.cpp @@ -1,5 +1,11 @@ #include +TimedEventsManager& TimedEventsManager::instance() +{ + static TimedEventsManager inst; + return inst; +} + TimedEventsManager::TimedEventsManager() { } -- cgit v1.2.3 From 48ed47207cabe98ad7720048f03b7b09f5cf24cb Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 28 Jun 2014 18:38:08 +0200 Subject: Add missing include in timed_events.hpp fix #2552 --- src/utils/timed_events.hpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/utils') diff --git a/src/utils/timed_events.hpp b/src/utils/timed_events.hpp index aafe532..4e2800c 100644 --- a/src/utils/timed_events.hpp +++ b/src/utils/timed_events.hpp @@ -2,6 +2,7 @@ # define TIMED_EVENTS_HPP #include +#include #include #include -- cgit v1.2.3 From c20bdd68796c0fc31441ffe059a462a0d423cc77 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 12 Nov 2014 07:52:07 +0100 Subject: Add utils::revstr --- src/utils/revstr.cpp | 9 +++++++++ src/utils/revstr.hpp | 11 +++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/utils/revstr.cpp create mode 100644 src/utils/revstr.hpp (limited to 'src/utils') diff --git a/src/utils/revstr.cpp b/src/utils/revstr.cpp new file mode 100644 index 0000000..87fd801 --- /dev/null +++ b/src/utils/revstr.cpp @@ -0,0 +1,9 @@ +#include + +namespace utils +{ + std::string revstr(const std::string& original) + { + return {original.rbegin(), original.rend()}; + } +} diff --git a/src/utils/revstr.hpp b/src/utils/revstr.hpp new file mode 100644 index 0000000..0f00076 --- /dev/null +++ b/src/utils/revstr.hpp @@ -0,0 +1,11 @@ +#ifndef REVSTRP_INCLUDED +# define REVSTR_INCLUDED + +#include + +namespace utils +{ + std::string revstr(const std::string& original); +} + +#endif // REVSTR_INCLUDED -- cgit v1.2.3 From 720e31a5113c25e48d7754bb812ab84c6c31d1d9 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 17 Dec 2014 13:37:57 +0100 Subject: Fix a few issues reported by static analyzers --- src/utils/encoding.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/utils') diff --git a/src/utils/encoding.cpp b/src/utils/encoding.cpp index dc0101c..3e3580c 100644 --- a/src/utils/encoding.cpp +++ b/src/utils/encoding.cpp @@ -197,6 +197,7 @@ namespace utils case E2BIG: // This should never happen done = true; + break; default: // This should happen even neverer done = true; -- cgit v1.2.3 From 51c28a2dbb1506cbd73c97cdb1e2ddb7fba017b1 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 26 Jan 2015 21:12:40 +0100 Subject: Fix the include guard of revstr.hpp --- src/utils/revstr.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/utils') diff --git a/src/utils/revstr.hpp b/src/utils/revstr.hpp index 0f00076..27c9e3e 100644 --- a/src/utils/revstr.hpp +++ b/src/utils/revstr.hpp @@ -1,5 +1,5 @@ -#ifndef REVSTRP_INCLUDED -# define REVSTR_INCLUDED +#ifndef REVSTR_HPP_INCLUDED +# define REVSTR_HPP_INCLUDED #include @@ -8,4 +8,4 @@ namespace utils std::string revstr(const std::string& original); } -#endif // REVSTR_INCLUDED +#endif // REVSTR_HPP_INCLUDED -- cgit v1.2.3 From 7115aa3b7f22f95e5e614ffc74c467844c08d965 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 24 Feb 2015 16:28:30 +0100 Subject: Add a reload add-hoc command --- src/utils/reload.cpp | 13 +++++++++++++ src/utils/reload.hpp | 10 ++++++++++ 2 files changed, 23 insertions(+) create mode 100644 src/utils/reload.cpp create mode 100644 src/utils/reload.hpp (limited to 'src/utils') diff --git a/src/utils/reload.cpp b/src/utils/reload.cpp new file mode 100644 index 0000000..6600c75 --- /dev/null +++ b/src/utils/reload.cpp @@ -0,0 +1,13 @@ +#include +#include + +void reload_process() +{ + // Closing the config will just force it to be reopened the next time + // a configuration option is needed + Config::close(); + // Destroy the logger instance, to be recreated the next time a log + // line needs to be written + Logger::instance().reset(); + log_debug("Configuration and logger reloaded."); +} diff --git a/src/utils/reload.hpp b/src/utils/reload.hpp new file mode 100644 index 0000000..16d64f7 --- /dev/null +++ b/src/utils/reload.hpp @@ -0,0 +1,10 @@ +#ifndef RELOAD_HPP_INCLUDED +#define RELOAD_HPP_INCLUDED + +/** + * Reload the server's configuration, and close the logger (so that it + * closes its files etc, to take into account the new configuration) + */ +void reload_process(); + +#endif /* RELOAD_HPP_INCLUDED */ -- cgit v1.2.3 From 2df0ebf2dfed1dcbf80c92bff8361e2a04581bec Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 25 Feb 2015 18:35:30 +0100 Subject: Add support for a fixed_irc_server configuration This option lets the administrator choose a specific IRC server, and only that server can be used with this biboumi instance. In this mode, JIDs to use are changed like this: - #chan%irc.example.com@biboumi.example.com -> #chan@biboumi.example.com - user!irc.example.com@biboumi.example.com -> user!@biboumi.example.com - #chan%irc.example.com@biboumi.example.com/Nick -> #chan@biboumi.example.com/Nick - %irc.example.com@biboumi.example.com -> no equivalent - irc.example.com@biboumi.example.com -> no equivalent --- src/utils/empty_if_fixed_server.cpp | 8 ++++++++ src/utils/empty_if_fixed_server.hpp | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/utils/empty_if_fixed_server.cpp create mode 100644 src/utils/empty_if_fixed_server.hpp (limited to 'src/utils') diff --git a/src/utils/empty_if_fixed_server.cpp b/src/utils/empty_if_fixed_server.cpp new file mode 100644 index 0000000..85fd86d --- /dev/null +++ b/src/utils/empty_if_fixed_server.cpp @@ -0,0 +1,8 @@ +// #include + +// #include + +// namespace utils +// { +// inline std::string empty_if_fixed_server(std::string&& str) +// } diff --git a/src/utils/empty_if_fixed_server.hpp b/src/utils/empty_if_fixed_server.hpp new file mode 100644 index 0000000..8739fd9 --- /dev/null +++ b/src/utils/empty_if_fixed_server.hpp @@ -0,0 +1,26 @@ +#ifndef EMPTY_IF_FIXED_SERVER_HPP_INCLUDED +#define EMPTY_IF_FIXED_SERVER_HPP_INCLUDED + +#include + +#include + +namespace utils +{ + inline std::string empty_if_fixed_server(std::string&& str) + { + if (!Config::get("fixed_irc_server", "").empty()) + return {}; + return str; + } + + inline std::string empty_if_fixed_server(const std::string& str) + { + if (!Config::get("fixed_irc_server", "").empty()) + return {}; + return str; + } + +} + +#endif /* EMPTY_IF_FIXED_SERVER_HPP_INCLUDED */ -- cgit v1.2.3 From c307df85c8e7d9bcd4570269bf13c3e92c3f5954 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 25 Feb 2015 19:05:04 +0100 Subject: Do not handle the "%" char in a special way, in the fixed_server mode Also fix some doc --- src/utils/empty_if_fixed_server.cpp | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 src/utils/empty_if_fixed_server.cpp (limited to 'src/utils') diff --git a/src/utils/empty_if_fixed_server.cpp b/src/utils/empty_if_fixed_server.cpp deleted file mode 100644 index 85fd86d..0000000 --- a/src/utils/empty_if_fixed_server.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// #include - -// #include - -// namespace utils -// { -// inline std::string empty_if_fixed_server(std::string&& str) -// } -- cgit v1.2.3 From d600a2843f1dbe3b1ba2dead9a020cc73d7d10ae Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 27 Feb 2015 12:16:09 +0100 Subject: Remove all the libs that are now in louloulibs --- src/utils/encoding.cpp | 221 ------------------------------------- src/utils/encoding.hpp | 29 ----- src/utils/reload.cpp | 13 --- src/utils/reload.hpp | 10 -- src/utils/revstr.cpp | 9 -- src/utils/revstr.hpp | 11 -- src/utils/scopeguard.hpp | 89 --------------- src/utils/sha1.cpp | 154 -------------------------- src/utils/sha1.hpp | 35 ------ src/utils/split.cpp | 18 --- src/utils/split.hpp | 13 --- src/utils/timed_events.cpp | 62 ----------- src/utils/timed_events.hpp | 132 ---------------------- src/utils/timed_events_manager.cpp | 81 -------------- src/utils/tolower.cpp | 13 --- src/utils/tolower.hpp | 11 -- 16 files changed, 901 deletions(-) delete mode 100644 src/utils/encoding.cpp delete mode 100644 src/utils/encoding.hpp delete mode 100644 src/utils/reload.cpp delete mode 100644 src/utils/reload.hpp delete mode 100644 src/utils/revstr.cpp delete mode 100644 src/utils/revstr.hpp delete mode 100644 src/utils/scopeguard.hpp delete mode 100644 src/utils/sha1.cpp delete mode 100644 src/utils/sha1.hpp delete mode 100644 src/utils/split.cpp delete mode 100644 src/utils/split.hpp delete mode 100644 src/utils/timed_events.cpp delete mode 100644 src/utils/timed_events.hpp delete mode 100644 src/utils/timed_events_manager.cpp delete mode 100644 src/utils/tolower.cpp delete mode 100644 src/utils/tolower.hpp (limited to 'src/utils') diff --git a/src/utils/encoding.cpp b/src/utils/encoding.cpp deleted file mode 100644 index 3e3580c..0000000 --- a/src/utils/encoding.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include - -#include - -#include - -#include -#include -#include - -#include - -#include - -/** - * The UTF-8-encoded character used as a place holder when a character conversion fails. - * This is U+FFFD � "replacement character" - */ -static const char* invalid_char = "\xef\xbf\xbd"; -static const size_t invalid_char_len = 3; - -namespace utils -{ - /** - * Based on http://en.wikipedia.org/wiki/UTF-8#Description - */ - bool is_valid_utf8(const char* s) - { - if (!s) - return false; - - const unsigned char* str = reinterpret_cast(s); - - while (*str) - { - // 4 bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - if ((str[0] & 0b11111000) == 0b11110000) - { - if (!str[1] || !str[2] || !str[3] - || ((str[1] & 0b11000000) != 0b10000000) - || ((str[2] & 0b11000000) != 0b10000000) - || ((str[3] & 0b11000000) != 0b10000000)) - return false; - str += 4; - } - // 3 bytes: 1110xxx 10xxxxxx 10xxxxxx - else if ((str[0] & 0b11110000) == 0b11100000) - { - if (!str[1] || !str[2] - || ((str[1] & 0b11000000) != 0b10000000) - || ((str[2] & 0b11000000) != 0b10000000)) - return false; - str += 3; - } - // 2 bytes: 110xxxxx 10xxxxxx - else if (((str[0]) & 0b11100000) == 0b11000000) - { - if (!str[1] || - ((str[1] & 0b11000000) != 0b10000000)) - return false; - str += 2; - } - // 1 byte: 0xxxxxxx - else if ((str[0] & 0b10000000) != 0) - return false; - else - str++; - } - return true; - } - - std::string remove_invalid_xml_chars(const std::string& original) - { - // The given string MUST be a valid utf-8 string - unsigned char* res = new unsigned char[original.size()]; - ScopeGuard sg([&res]() { delete[] res;}); - - // pointer where we write valid chars - unsigned char* r = res; - - const unsigned char* str = reinterpret_cast(original.c_str()); - std::bitset<20> codepoint; - - while (*str) - { - // 4 bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - if ((str[0] & 0b11111000) == 0b11110000) - { - codepoint = ((str[0] & 0b00000111) << 18); - codepoint |= ((str[1] & 0b00111111) << 12); - codepoint |= ((str[2] & 0b00111111) << 6 ); - codepoint |= ((str[3] & 0b00111111) << 0 ); - if (codepoint.to_ulong() <= 0x10FFFF) - { - ::memcpy(r, str, 4); - r += 4; - } - str += 4; - } - // 3 bytes: 1110xxx 10xxxxxx 10xxxxxx - else if ((str[0] & 0b11110000) == 0b11100000) - { - codepoint = ((str[0] & 0b00001111) << 12); - codepoint |= ((str[1] & 0b00111111) << 6); - codepoint |= ((str[2] & 0b00111111) << 0 ); - if (codepoint.to_ulong() <= 0xD7FF || - (codepoint.to_ulong() >= 0xE000 && codepoint.to_ulong() <= 0xFFFD)) - { - ::memcpy(r, str, 3); - r += 3; - } - str += 3; - } - // 2 bytes: 110xxxxx 10xxxxxx - else if (((str[0]) & 0b11100000) == 0b11000000) - { - // All 2 bytes char are valid, don't even bother calculating - // the codepoint - ::memcpy(r, str, 2); - r += 2; - str += 2; - } - // 1 byte: 0xxxxxxx - else if ((str[0] & 0b10000000) == 0) - { - codepoint = ((str[0] & 0b01111111)); - if (codepoint.to_ulong() == 0x09 || - codepoint.to_ulong() == 0x0A || - codepoint.to_ulong() == 0x0D || - codepoint.to_ulong() >= 0x20) - { - ::memcpy(r, str, 1); - r += 1; - } - str += 1; - } - else - throw std::runtime_error("Invalid UTF-8 passed to remove_invalid_xml_chars"); - } - return std::string(reinterpret_cast(res), r-res); - } - - std::string convert_to_utf8(const std::string& str, const char* charset) - { - std::string res; - - const iconv_t cd = iconv_open("UTF-8", charset); - if (cd == (iconv_t)-1) - throw std::runtime_error("Cannot convert into UTF-8"); - - // Make sure cd is always closed when we leave this function - ScopeGuard sg([&]{ iconv_close(cd); }); - - size_t inbytesleft = str.size(); - - // iconv will not attempt to modify this buffer, but some plateform - // require a char** anyway -#ifdef ICONV_SECOND_ARGUMENT_IS_CONST - const char* inbuf_ptr = str.c_str(); -#else - char* inbuf_ptr = const_cast(str.c_str()); -#endif - - size_t outbytesleft = str.size() * 4; - char* outbuf = new char[outbytesleft]; - char* outbuf_ptr = outbuf; - - // Make sure outbuf is always deleted when we leave this function - sg.add_callback([&]{ delete[] outbuf; }); - - bool done = false; - while (done == false) - { - size_t error = iconv(cd, &inbuf_ptr, &inbytesleft, &outbuf_ptr, &outbytesleft); - if ((size_t)-1 == error) - { - switch (errno) - { - case EILSEQ: - // Invalid byte found. Insert a placeholder instead of the - // converted character, jump one byte and continue - memcpy(outbuf_ptr, invalid_char, invalid_char_len); - outbuf_ptr += invalid_char_len; - inbytesleft--; - inbuf_ptr++; - break; - case EINVAL: - // A multibyte sequence is not terminated, but we can't - // provide any more data, so we just add a placeholder to - // indicate that the character is not properly converted, - // and we stop the conversion - memcpy(outbuf_ptr, invalid_char, invalid_char_len); - outbuf_ptr += invalid_char_len; - outbuf_ptr++; - done = true; - break; - case E2BIG: - // This should never happen - done = true; - break; - default: - // This should happen even neverer - done = true; - break; - } - } - else - { - // The conversion finished without any error, stop converting - done = true; - } - } - // Terminate the converted buffer, and copy that buffer it into the - // string we return - *outbuf_ptr = '\0'; - res = outbuf; - return res; - } - -} - diff --git a/src/utils/encoding.hpp b/src/utils/encoding.hpp deleted file mode 100644 index a3bccfc..0000000 --- a/src/utils/encoding.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef ENCODING_INCLUDED -# define ENCODING_INCLUDED - -#include - -namespace utils -{ - /** - * Returns true if the given null-terminated string is valid utf-8. - * - * Based on http://en.wikipedia.org/wiki/UTF-8#Description - */ - bool is_valid_utf8(const char* s); - /** - * Remove all invalid codepoints from the given utf-8-encoded string. - * The value returned is a copy of the string, without the removed chars. - * - * See http://www.w3.org/TR/xml/#charsets for the list of valid characters - * in XML. - */ - std::string remove_invalid_xml_chars(const std::string& original); - /** - * Convert the given string (encoded is "encoding") into valid utf-8. - * If some decoding fails, insert an utf-8 placeholder character instead. - */ - std::string convert_to_utf8(const std::string& str, const char* encoding); -} - -#endif // ENCODING_INCLUDED diff --git a/src/utils/reload.cpp b/src/utils/reload.cpp deleted file mode 100644 index 6600c75..0000000 --- a/src/utils/reload.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - -void reload_process() -{ - // Closing the config will just force it to be reopened the next time - // a configuration option is needed - Config::close(); - // Destroy the logger instance, to be recreated the next time a log - // line needs to be written - Logger::instance().reset(); - log_debug("Configuration and logger reloaded."); -} diff --git a/src/utils/reload.hpp b/src/utils/reload.hpp deleted file mode 100644 index 16d64f7..0000000 --- a/src/utils/reload.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef RELOAD_HPP_INCLUDED -#define RELOAD_HPP_INCLUDED - -/** - * Reload the server's configuration, and close the logger (so that it - * closes its files etc, to take into account the new configuration) - */ -void reload_process(); - -#endif /* RELOAD_HPP_INCLUDED */ diff --git a/src/utils/revstr.cpp b/src/utils/revstr.cpp deleted file mode 100644 index 87fd801..0000000 --- a/src/utils/revstr.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -namespace utils -{ - std::string revstr(const std::string& original) - { - return {original.rbegin(), original.rend()}; - } -} diff --git a/src/utils/revstr.hpp b/src/utils/revstr.hpp deleted file mode 100644 index 27c9e3e..0000000 --- a/src/utils/revstr.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef REVSTR_HPP_INCLUDED -# define REVSTR_HPP_INCLUDED - -#include - -namespace utils -{ - std::string revstr(const std::string& original); -} - -#endif // REVSTR_HPP_INCLUDED diff --git a/src/utils/scopeguard.hpp b/src/utils/scopeguard.hpp deleted file mode 100644 index df78831..0000000 --- a/src/utils/scopeguard.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef SCOPEGUARD_HPP -#define SCOPEGUARD_HPP - -#include -#include - -/** - * A class to be used to make sure some functions are called when the scope - * is left, because they will be called in the ScopeGuard's destructor. It - * can for example be used to delete some pointer whenever any exception is - * called. Example: - - * { - * ScopeGuard scope; - * int* number = new int(2); - * scope.add_callback([number]() { delete number; }); - * // Do some other stuff with the number. But these stuff might throw an exception: - * throw std::runtime_error("Some error not caught here, but in our caller"); - * return true; - * } - - * In this example, our pointer will always be deleted, even when the - * exception is thrown. If we want the functions to be called only when the - * scope is left because of an unexpected exception, we can use - * ScopeGuard::disable(); - */ - -namespace utils -{ - -class ScopeGuard -{ -public: - /** - * The constructor can take a callback. But additional callbacks can be - * added later with add_callback() - */ - explicit ScopeGuard(std::function&& func): - enabled(true) - { - this->add_callback(std::move(func)); - } - /** - * default constructor, the scope guard is enabled but empty, use - * add_callback() - */ - explicit ScopeGuard(): - enabled(true) - { - } - /** - * Call all callbacks in the desctructor, unless it has been disabled. - */ - ~ScopeGuard() - { - if (this->enabled) - for (auto& func: this->callbacks) - func(); - } - /** - * Add a callback to be called in our destructor, one scope guard can be - * used for more than one task, if needed. - */ - void add_callback(std::function&& func) - { - this->callbacks.emplace_back(std::move(func)); - } - /** - * Disable that scope guard, nothing will be done when the scope is - * exited. - */ - void disable() - { - this->enabled = false; - } - -private: - bool enabled; - std::vector> callbacks; - - ScopeGuard(const ScopeGuard&) = delete; - ScopeGuard& operator=(ScopeGuard&&) = delete; - ScopeGuard(ScopeGuard&&) = delete; - ScopeGuard& operator=(const ScopeGuard&) = delete; -}; - -} - -#endif diff --git a/src/utils/sha1.cpp b/src/utils/sha1.cpp deleted file mode 100644 index 76476df..0000000 --- a/src/utils/sha1.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* This code is public-domain - it is based on libcrypt - * placed in the public domain by Wei Dai and other contributors. - */ - -#include "sha1.hpp" - -#define SHA1_K0 0x5a827999 -#define SHA1_K20 0x6ed9eba1 -#define SHA1_K40 0x8f1bbcdc -#define SHA1_K60 0xca62c1d6 - -const uint8_t sha1InitState[] = { - 0x01,0x23,0x45,0x67, // H0 - 0x89,0xab,0xcd,0xef, // H1 - 0xfe,0xdc,0xba,0x98, // H2 - 0x76,0x54,0x32,0x10, // H3 - 0xf0,0xe1,0xd2,0xc3 // H4 -}; - -void sha1_init(sha1nfo *s) { - memcpy(s->state.b,sha1InitState,HASH_LENGTH); - s->byteCount = 0; - s->bufferOffset = 0; -} - -uint32_t sha1_rol32(uint32_t number, uint8_t bits) { - return ((number << bits) | (number >> (32-bits))); -} - -void sha1_hashBlock(sha1nfo *s) { - uint8_t i; - uint32_t a,b,c,d,e,t; - - a=s->state.w[0]; - b=s->state.w[1]; - c=s->state.w[2]; - d=s->state.w[3]; - e=s->state.w[4]; - for (i=0; i<80; i++) { - if (i>=16) { - t = s->buffer.w[(i+13)&15] ^ s->buffer.w[(i+8)&15] ^ s->buffer.w[(i+2)&15] ^ s->buffer.w[i&15]; - s->buffer.w[i&15] = sha1_rol32(t,1); - } - if (i<20) { - t = (d ^ (b & (c ^ d))) + SHA1_K0; - } else if (i<40) { - t = (b ^ c ^ d) + SHA1_K20; - } else if (i<60) { - t = ((b & c) | (d & (b | c))) + SHA1_K40; - } else { - t = (b ^ c ^ d) + SHA1_K60; - } - t+=sha1_rol32(a,5) + e + s->buffer.w[i&15]; - e=d; - d=c; - c=sha1_rol32(b,30); - b=a; - a=t; - } - s->state.w[0] += a; - s->state.w[1] += b; - s->state.w[2] += c; - s->state.w[3] += d; - s->state.w[4] += e; -} - -void sha1_addUncounted(sha1nfo *s, uint8_t data) { - s->buffer.b[s->bufferOffset ^ 3] = data; - s->bufferOffset++; - if (s->bufferOffset == BLOCK_LENGTH) { - sha1_hashBlock(s); - s->bufferOffset = 0; - } -} - -void sha1_writebyte(sha1nfo *s, uint8_t data) { - ++s->byteCount; - sha1_addUncounted(s, data); -} - -void sha1_write(sha1nfo *s, const char *data, size_t len) { - for (;len--;) sha1_writebyte(s, (uint8_t) *data++); -} - -void sha1_pad(sha1nfo *s) { - // Implement SHA-1 padding (fips180-2 §5.1.1) - - // Pad with 0x80 followed by 0x00 until the end of the block - sha1_addUncounted(s, 0x80); - while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00); - - // Append length in the last 8 bytes - sha1_addUncounted(s, 0); // We're only using 32 bit lengths - sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths - sha1_addUncounted(s, 0); // So zero pad the top bits - sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8 - sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as - sha1_addUncounted(s, s->byteCount >> 13); // byte. - sha1_addUncounted(s, s->byteCount >> 5); - sha1_addUncounted(s, s->byteCount << 3); -} - -uint8_t* sha1_result(sha1nfo *s) { - int i; - // Pad to complete the last block - sha1_pad(s); - - // Swap byte order back - for (i=0; i<5; i++) { - uint32_t a,b; - a=s->state.w[i]; - b=a<<24; - b|=(a<<8) & 0x00ff0000; - b|=(a>>8) & 0x0000ff00; - b|=a>>24; - s->state.w[i]=b; - } - - // Return pointer to hash (20 characters) - return s->state.b; -} - -#define HMAC_IPAD 0x36 -#define HMAC_OPAD 0x5c - -void sha1_initHmac(sha1nfo *s, const uint8_t* key, int keyLength) { - uint8_t i; - memset(s->keyBuffer, 0, BLOCK_LENGTH); - if (keyLength > BLOCK_LENGTH) { - // Hash long keys - sha1_init(s); - for (;keyLength--;) sha1_writebyte(s, *key++); - memcpy(s->keyBuffer, sha1_result(s), HASH_LENGTH); - } else { - // Block length keys are used as is - memcpy(s->keyBuffer, key, keyLength); - } - // Start inner hash - sha1_init(s); - for (i=0; ikeyBuffer[i] ^ HMAC_IPAD); - } -} - -uint8_t* sha1_resultHmac(sha1nfo *s) { - uint8_t i; - // Complete inner hash - memcpy(s->innerHash,sha1_result(s),HASH_LENGTH); - // Calculate outer hash - sha1_init(s); - for (i=0; ikeyBuffer[i] ^ HMAC_OPAD); - for (i=0; iinnerHash[i]); - return sha1_result(s); -} diff --git a/src/utils/sha1.hpp b/src/utils/sha1.hpp deleted file mode 100644 index d02de75..0000000 --- a/src/utils/sha1.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* This code is public-domain - it is based on libcrypt - * placed in the public domain by Wei Dai and other contributors. - */ - -#include -#include - -#define HASH_LENGTH 20 -#define BLOCK_LENGTH 64 - -union _buffer { - uint8_t b[BLOCK_LENGTH]; - uint32_t w[BLOCK_LENGTH/4]; -}; - -union _state { - uint8_t b[HASH_LENGTH]; - uint32_t w[HASH_LENGTH/4]; -}; - -typedef struct sha1nfo { - union _buffer buffer; - uint8_t bufferOffset; - union _state state; - uint32_t byteCount; - uint8_t keyBuffer[BLOCK_LENGTH]; - uint8_t innerHash[HASH_LENGTH]; -} sha1nfo; - -void sha1_init(sha1nfo *s); -void sha1_writebyte(sha1nfo *s, uint8_t data); -void sha1_write(sha1nfo *s, const char *data, size_t len); -uint8_t* sha1_result(sha1nfo *s); -void sha1_initHmac(sha1nfo *s, const uint8_t* key, int keyLength); -uint8_t* sha1_resultHmac(sha1nfo *s); diff --git a/src/utils/split.cpp b/src/utils/split.cpp deleted file mode 100644 index afe4300..0000000 --- a/src/utils/split.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include - -namespace utils -{ - std::vector split(const std::string& s, const char delim, const bool allow_empty) - { - std::vector ret; - std::stringstream ss(s); - std::string item; - while (std::getline(ss, item, delim)) - { - if (item.empty() && !allow_empty) - continue ; - ret.emplace_back(std::move(item)); - } - return ret; - } -} diff --git a/src/utils/split.hpp b/src/utils/split.hpp deleted file mode 100644 index 9fee90a..0000000 --- a/src/utils/split.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef SPLIT_INCLUDED -# define SPLIT_INCLUDED - -#include -#include -#include - -namespace utils -{ - std::vector split(const std::string &s, const char delim, const bool allow_empty=true); -} - -#endif // SPLIT_INCLUDED diff --git a/src/utils/timed_events.cpp b/src/utils/timed_events.cpp deleted file mode 100644 index 5010a3f..0000000 --- a/src/utils/timed_events.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include - -TimedEvent::TimedEvent(std::chrono::steady_clock::time_point&& time_point, - std::function callback, const std::string& name): - time_point(std::move(time_point)), - callback(callback), - repeat(false), - repeat_delay(0), - name(name) -{ -} - -TimedEvent::TimedEvent(std::chrono::milliseconds&& duration, - std::function callback, const std::string& name): - time_point(std::chrono::steady_clock::now() + duration), - callback(callback), - repeat(true), - repeat_delay(std::move(duration)), - name(name) -{ -} - -TimedEvent::TimedEvent(TimedEvent&& other): - time_point(std::move(other.time_point)), - callback(std::move(other.callback)), - repeat(other.repeat), - repeat_delay(std::move(other.repeat_delay)), - name(std::move(other.name)) -{ -} - -TimedEvent::~TimedEvent() -{ -} - -bool TimedEvent::is_after(const TimedEvent& other) const -{ - return this->is_after(other.time_point); -} - -bool TimedEvent::is_after(const std::chrono::steady_clock::time_point& time_point) const -{ - return this->time_point >= time_point; -} - -std::chrono::milliseconds TimedEvent::get_timeout() const -{ - auto now = std::chrono::steady_clock::now(); - if (now > this->time_point) - return std::chrono::milliseconds(0); - return std::chrono::duration_cast(this->time_point - now); -} - -void TimedEvent::execute() -{ - this->callback(); -} - -const std::string& TimedEvent::get_name() const -{ - return this->name; -} diff --git a/src/utils/timed_events.hpp b/src/utils/timed_events.hpp deleted file mode 100644 index 4e2800c..0000000 --- a/src/utils/timed_events.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef TIMED_EVENTS_HPP -# define TIMED_EVENTS_HPP - -#include -#include -#include -#include - -using namespace std::literals::chrono_literals; - -namespace utils { -static constexpr std::chrono::milliseconds no_timeout = std::chrono::milliseconds(-1); -} - -class TimedEventsManager; - -/** - * A callback with an associated date. - */ - -class TimedEvent -{ - friend class TimedEventsManager; -public: - /** - * An event the occurs only once, at the given time_point - */ - explicit TimedEvent(std::chrono::steady_clock::time_point&& time_point, - std::function callback, const std::string& name=""); - explicit TimedEvent(std::chrono::milliseconds&& duration, - std::function callback, const std::string& name=""); - - explicit TimedEvent(TimedEvent&&); - ~TimedEvent(); - /** - * Whether or not this event happens after the other one. - */ - bool is_after(const TimedEvent& other) const; - bool is_after(const std::chrono::steady_clock::time_point& time_point) const; - /** - * Return the duration difference between now and the event time point. - * If the difference would be negative (i.e. the event is expired), the - * returned value is 0 instead. The value cannot then be negative. - */ - std::chrono::milliseconds get_timeout() const; - void execute(); - const std::string& get_name() const; - -private: - /** - * The next time point at which the event is executed. - */ - std::chrono::steady_clock::time_point time_point; - /** - * The function to execute. - */ - const std::function callback; - /** - * Whether or not this events repeats itself until it is destroyed. - */ - const bool repeat; - /** - * This value is added to the time_point each time the event is executed, - * if repeat is true. Otherwise it is ignored. - */ - const std::chrono::milliseconds repeat_delay; - /** - * A name that is used to identify that event. If you want to find your - * event (for example if you want to cancel it), the name should be - * unique. - */ - const std::string name; - - TimedEvent(const TimedEvent&) = delete; - TimedEvent& operator=(const TimedEvent&) = delete; - TimedEvent& operator=(TimedEvent&&) = delete; -}; - -/** - * A class managing a list of TimedEvents. - * They are sorted, new events can be added, removed, fetch, etc. - */ - -class TimedEventsManager -{ -public: - ~TimedEventsManager(); - /** - * Return the unique instance of this class - */ - static TimedEventsManager& instance(); - /** - * Add an event to the list of managed events. The list is sorted after - * this call. - */ - void add_event(TimedEvent&& event); - /** - * Returns the duration, in milliseconds, between now and the next - * available event. If the event is already expired (the duration is - * negative), 0 is returned instead (as in “it's not too late, execute it - * now”) - * Returns a negative value if no event is available. - */ - std::chrono::milliseconds get_timeout() const; - /** - * Execute all the expired events (if their expiration time is exactly - * now, or before now). The event is then removed from the list. If the - * event does repeat, its expiration time is updated and it is reinserted - * in the list at the correct position. - * Returns the number of executed events. - */ - std::size_t execute_expired_events(); - /** - * Remove (and thus cancel) all the timed events with the given name. - * Returns the number of canceled events. - */ - std::size_t cancel(const std::string& name); - /** - * Return the number of managed events. - */ - std::size_t size() const; - -private: - explicit TimedEventsManager(); - std::list events; - TimedEventsManager(const TimedEventsManager&) = delete; - TimedEventsManager(TimedEventsManager&&) = delete; - TimedEventsManager& operator=(const TimedEventsManager&) = delete; - TimedEventsManager& operator=(TimedEventsManager&&) = delete; -}; - -#endif // TIMED_EVENTS_HPP diff --git a/src/utils/timed_events_manager.cpp b/src/utils/timed_events_manager.cpp deleted file mode 100644 index 2c75e48..0000000 --- a/src/utils/timed_events_manager.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include - -TimedEventsManager& TimedEventsManager::instance() -{ - static TimedEventsManager inst; - return inst; -} - -TimedEventsManager::TimedEventsManager() -{ -} - -TimedEventsManager::~TimedEventsManager() -{ -} - -void TimedEventsManager::add_event(TimedEvent&& event) -{ - for (auto it = this->events.begin(); it != this->events.end(); ++it) - { - if (it->is_after(event)) - { - this->events.emplace(it, std::move(event)); - return; - } - } - this->events.emplace_back(std::move(event)); -} - -std::chrono::milliseconds TimedEventsManager::get_timeout() const -{ - if (this->events.empty()) - return utils::no_timeout; - return this->events.front().get_timeout() + std::chrono::milliseconds(1); -} - -std::size_t TimedEventsManager::execute_expired_events() -{ - std::size_t count = 0; - const auto now = std::chrono::steady_clock::now(); - for (auto it = this->events.begin(); it != this->events.end();) - { - if (!it->is_after(now)) - { - TimedEvent copy(std::move(*it)); - it = this->events.erase(it); - ++count; - copy.execute(); - if (copy.repeat) - { - copy.time_point += copy.repeat_delay; - this->add_event(std::move(copy)); - } - continue; - } - else - break; - } - return count; -} - -std::size_t TimedEventsManager::cancel(const std::string& name) -{ - std::size_t res = 0; - for (auto it = this->events.begin(); it != this->events.end();) - { - if (it->get_name() == name) - { - it = this->events.erase(it); - res++; - } - else - ++it; - } - return res; -} - -std::size_t TimedEventsManager::size() const -{ - return this->events.size(); -} diff --git a/src/utils/tolower.cpp b/src/utils/tolower.cpp deleted file mode 100644 index 3e518bd..0000000 --- a/src/utils/tolower.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include - -namespace utils -{ - std::string tolower(const std::string& original) - { - std::string res; - res.reserve(original.size()); - for (const char c: original) - res += static_cast(std::tolower(c)); - return res; - } -} diff --git a/src/utils/tolower.hpp b/src/utils/tolower.hpp deleted file mode 100644 index 0019182..0000000 --- a/src/utils/tolower.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef TOLOWER_INCLUDED -# define TOLOWER_INCLUDED - -#include - -namespace utils -{ - std::string tolower(const std::string& original); -} - -#endif // SPLIT_INCLUDED -- cgit v1.2.3 From 81f8f45b371d1a0ef72c2768fbd1f9188fe83616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 4 Jul 2016 17:53:53 +0200 Subject: Replace all include guards by #pragma once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s $CURRENT_YEAR --- src/utils/empty_if_fixed_server.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/utils') diff --git a/src/utils/empty_if_fixed_server.hpp b/src/utils/empty_if_fixed_server.hpp index 8739fd9..9ccf5fd 100644 --- a/src/utils/empty_if_fixed_server.hpp +++ b/src/utils/empty_if_fixed_server.hpp @@ -1,5 +1,5 @@ -#ifndef EMPTY_IF_FIXED_SERVER_HPP_INCLUDED -#define EMPTY_IF_FIXED_SERVER_HPP_INCLUDED +#pragma once + #include @@ -23,4 +23,4 @@ namespace utils } -#endif /* EMPTY_IF_FIXED_SERVER_HPP_INCLUDED */ + -- cgit v1.2.3 From 9fb2e116c47a9d4e2866d34450d12dcb90d4a26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 12 Jul 2016 01:15:34 +0200 Subject: Move reload.*pp from louloulibs to src --- src/utils/reload.cpp | 28 ++++++++++++++++++++++++++++ src/utils/reload.hpp | 4 ++++ 2 files changed, 32 insertions(+) create mode 100644 src/utils/reload.cpp create mode 100644 src/utils/reload.hpp (limited to 'src/utils') diff --git a/src/utils/reload.cpp b/src/utils/reload.cpp new file mode 100644 index 0000000..7125a75 --- /dev/null +++ b/src/utils/reload.cpp @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include + +void open_database() +{ + const auto db_filename = Config::get("db_name", xdg_data_path("biboumi.sqlite")); + log_info("Opening database: ", db_filename); + Database::open(db_filename); + log_info("database successfully opened."); +} + +void reload_process() +{ + Config::read_conf(); + // Destroy the logger instance, to be recreated the next time a log + // line needs to be written + Logger::instance().reset(); + log_info("Configuration and logger reloaded."); + try { + open_database(); + } catch (const litesql::DatabaseError&) { + log_warning("Re-using the previous database."); + } +} + diff --git a/src/utils/reload.hpp b/src/utils/reload.hpp new file mode 100644 index 0000000..408426a --- /dev/null +++ b/src/utils/reload.hpp @@ -0,0 +1,4 @@ +#pragma once + +void open_database(); +void reload_process(); -- cgit v1.2.3 From 24824a5015e77aced8adf8afc35b82984e8b84fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 18 Jul 2016 09:53:15 +0200 Subject: In reload.cpp, only build the database things if litesql is used --- src/utils/reload.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/utils') diff --git a/src/utils/reload.cpp b/src/utils/reload.cpp index 7125a75..348c5b5 100644 --- a/src/utils/reload.cpp +++ b/src/utils/reload.cpp @@ -4,12 +4,16 @@ #include #include +#include "biboumi.h" + void open_database() { +#ifdef USE_DATABASE const auto db_filename = Config::get("db_name", xdg_data_path("biboumi.sqlite")); log_info("Opening database: ", db_filename); Database::open(db_filename); log_info("database successfully opened."); +#endif } void reload_process() @@ -19,10 +23,12 @@ void reload_process() // line needs to be written Logger::instance().reset(); log_info("Configuration and logger reloaded."); +#ifdef USE_DATABASE try { open_database(); } catch (const litesql::DatabaseError&) { log_warning("Re-using the previous database."); } +#endif } -- cgit v1.2.3