
47 changed files with 1343 additions and 1137 deletions
@ -0,0 +1,41 @@ |
|||||
|
BasedOnStyle: LLVM |
||||
|
Language: Cpp |
||||
|
Standard: c++14 |
||||
|
DerivePointerAlignment: true |
||||
|
SortIncludes: false |
||||
|
ReflowComments: false |
||||
|
PointerAlignment: Left |
||||
|
AlignAfterOpenBracket: AlwaysBreak |
||||
|
AlignOperands: AlignAfterOperator |
||||
|
BreakConstructorInitializers: AfterColon |
||||
|
AlignTrailingComments: true |
||||
|
AllowAllArgumentsOnNextLine: false |
||||
|
AllowAllParametersOfDeclarationOnNextLine: false |
||||
|
AllowShortEnumsOnASingleLine: false |
||||
|
AllowShortFunctionsOnASingleLine: Empty |
||||
|
AllowShortIfStatementsOnASingleLine: Never |
||||
|
AllowShortLoopsOnASingleLine: false |
||||
|
AlwaysBreakTemplateDeclarations: Yes |
||||
|
BinPackArguments: false |
||||
|
BinPackParameters: false |
||||
|
ExperimentalAutoDetectBinPacking: true |
||||
|
BreakBeforeBraces: Custom |
||||
|
BraceWrapping: |
||||
|
AfterFunction: true |
||||
|
ColumnLimit: 100 |
||||
|
AllowAllConstructorInitializersOnNextLine: false |
||||
|
AlwaysBreakAfterDefinitionReturnType: None |
||||
|
AlwaysBreakAfterReturnType: None |
||||
|
PenaltyBreakBeforeFirstCallParameter: 0 |
||||
|
PenaltyReturnTypeOnItsOwnLine: 1000000 |
||||
|
PenaltyBreakAssignment: 1000000 |
||||
|
PenaltyExcessCharacter: 10 |
||||
|
IndentCaseLabels: true |
||||
|
IndentWidth: 4 |
||||
|
MaxEmptyLinesToKeep: 2 |
||||
|
NamespaceIndentation: All |
||||
|
SpaceAfterTemplateKeyword: false |
||||
|
AccessModifierOffset: -4 |
||||
|
AllowShortBlocksOnASingleLine: Always |
||||
|
IndentPPDirectives: BeforeHash |
||||
|
Cpp11BracedListStyle: false |
@ -1,154 +0,0 @@ |
|||||
// This file is under GNU General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#include "Adapter.hh" |
|
||||
#include <sstream> |
|
||||
#include <iomanip> |
|
||||
#include <assert.h> |
|
||||
#include "status_to_string.hh" |
|
||||
#include "pEpLog.hh" |
|
||||
#include "passphrase_cache.hh" |
|
||||
|
|
||||
using namespace std; |
|
||||
|
|
||||
thread_local pEp::Adapter::Session pEp::Adapter::session; |
|
||||
|
|
||||
namespace pEp { |
|
||||
void throw_status(PEP_STATUS status) |
|
||||
{ |
|
||||
if (status == PEP_STATUS_OK) |
|
||||
return; |
|
||||
if (status >= 0x400 && status <= 0x4ff) |
|
||||
return; |
|
||||
if (status == PEP_STATEMACHINE_CANNOT_SEND) |
|
||||
return; |
|
||||
if (status == PEP_OUT_OF_MEMORY) |
|
||||
throw bad_alloc(); |
|
||||
if (status == PEP_ILLEGAL_VALUE) |
|
||||
throw invalid_argument("illegal value"); |
|
||||
|
|
||||
string _status = status_to_string(status); |
|
||||
throw RuntimeError(_status, status); |
|
||||
} |
|
||||
|
|
||||
RuntimeError::RuntimeError(const std::string& _text, PEP_STATUS _status) |
|
||||
: std::runtime_error(_text.c_str()), text(_text), status(_status) |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
|
|
||||
namespace Adapter { |
|
||||
messageToSend_t _messageToSend = nullptr; |
|
||||
notifyHandshake_t _notifyHandshake = nullptr; |
|
||||
std::thread _sync_thread; |
|
||||
|
|
||||
::utility::locked_queue< SYNC_EVENT, ::free_Sync_event > sync_evt_q; |
|
||||
std::mutex m; |
|
||||
|
|
||||
std::thread::id sync_thread_id() |
|
||||
{ |
|
||||
return _sync_thread.get_id(); |
|
||||
} |
|
||||
|
|
||||
int _inject_sync_event(SYNC_EVENT ev, void *management) |
|
||||
{ |
|
||||
try { |
|
||||
if (ev == nullptr) { |
|
||||
sync_evt_q.clear(); |
|
||||
sync_evt_q.push_back(ev); |
|
||||
} |
|
||||
else { |
|
||||
sync_evt_q.push_front(ev); |
|
||||
} |
|
||||
} |
|
||||
catch (exception&) { |
|
||||
return 1; |
|
||||
} |
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
PEP_STATUS _ensure_passphrase(PEP_SESSION session, const char *fpr) |
|
||||
{ |
|
||||
return passphrase_cache.ensure_passphrase(session, fpr); |
|
||||
} |
|
||||
|
|
||||
// threshold: max waiting time in seconds
|
|
||||
SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold) |
|
||||
{ |
|
||||
SYNC_EVENT syncEvent = nullptr; |
|
||||
const bool success = sync_evt_q.try_pop_front(syncEvent, std::chrono::seconds(threshold)); |
|
||||
|
|
||||
if (!success) { |
|
||||
return new_sync_timeout_event(); |
|
||||
} |
|
||||
|
|
||||
return syncEvent; |
|
||||
} |
|
||||
|
|
||||
bool on_sync_thread() |
|
||||
{ |
|
||||
return _sync_thread.get_id() == this_thread::get_id(); |
|
||||
} |
|
||||
|
|
||||
PEP_SESSION Session::operator()(session_action action) |
|
||||
{ |
|
||||
std::lock_guard<mutex> lock(m); |
|
||||
|
|
||||
PEP_STATUS status = PEP_STATUS_OK; |
|
||||
|
|
||||
switch (action) { |
|
||||
case release: |
|
||||
if (_session.get()) { |
|
||||
_session = nullptr; |
|
||||
} |
|
||||
break; |
|
||||
|
|
||||
case init: |
|
||||
if (!_session.get()) { |
|
||||
PEP_SESSION session_; |
|
||||
status = ::init(&session_, _messageToSend, _inject_sync_event, _ensure_passphrase); |
|
||||
throw_status(status); |
|
||||
_session = SessionPtr{session_, ::release}; |
|
||||
} |
|
||||
break; |
|
||||
|
|
||||
default: |
|
||||
status = PEP_ILLEGAL_VALUE; |
|
||||
} |
|
||||
|
|
||||
throw_status(status); |
|
||||
return _session.get(); |
|
||||
} |
|
||||
|
|
||||
void shutdown() |
|
||||
{ |
|
||||
pEpLog("called"); |
|
||||
if (_sync_thread.joinable()) { |
|
||||
pEpLog("sync_is_running - injecting null event"); |
|
||||
_inject_sync_event(nullptr, nullptr); |
|
||||
_sync_thread.join(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
bool is_sync_running() |
|
||||
{ |
|
||||
return _sync_thread.joinable(); |
|
||||
} |
|
||||
|
|
||||
bool in_shutdown() |
|
||||
{ |
|
||||
SYNC_EVENT ev; |
|
||||
try { |
|
||||
ev = sync_evt_q.back(); |
|
||||
} |
|
||||
catch (std::underflow_error&) { |
|
||||
return false; |
|
||||
} |
|
||||
if (ev) { |
|
||||
return false; |
|
||||
} else { |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
@ -1,110 +0,0 @@ |
|||||
// This file is under GNU General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#ifndef LIBPEPADAPTER_ADAPTER_HXX |
|
||||
#define LIBPEPADAPTER_ADAPTER_HXX |
|
||||
|
|
||||
#include <thread> |
|
||||
#include "locked_queue.hh" |
|
||||
#include <cassert> |
|
||||
#include "pEpLog.hh" |
|
||||
#include <atomic> |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace Adapter { |
|
||||
using std::function; |
|
||||
|
|
||||
extern messageToSend_t _messageToSend; |
|
||||
extern notifyHandshake_t _notifyHandshake; |
|
||||
extern std::thread _sync_thread; |
|
||||
|
|
||||
extern ::utility::locked_queue< SYNC_EVENT, ::free_Sync_event > sync_evt_q; |
|
||||
extern std::mutex m; |
|
||||
|
|
||||
SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold); |
|
||||
|
|
||||
static std::exception_ptr _ex; |
|
||||
static std::atomic_bool register_done{false}; |
|
||||
|
|
||||
template< class T > |
|
||||
void sync_thread(T *obj, function< void(T *) > _startup, function< void(T *) > _shutdown) |
|
||||
{ |
|
||||
pEpLog("called"); |
|
||||
_ex = nullptr; |
|
||||
assert(_messageToSend); |
|
||||
assert(_notifyHandshake); |
|
||||
if (obj && _startup) { |
|
||||
_startup(obj); |
|
||||
} |
|
||||
|
|
||||
pEpLog("creating session"); |
|
||||
session(); |
|
||||
|
|
||||
{ |
|
||||
//TODO: Do we need to use a passphraseWrap here???
|
|
||||
pEpLog("register_sync_callbacks()"); |
|
||||
PEP_STATUS status = register_sync_callbacks(session(), nullptr, |
|
||||
_notifyHandshake, _retrieve_next_sync_event); |
|
||||
pEpLog("register_sync_callbacks() return:" << status); |
|
||||
try { |
|
||||
throw_status(status); |
|
||||
register_done.store(true); |
|
||||
} |
|
||||
catch (...) { |
|
||||
_ex = std::current_exception(); |
|
||||
register_done.store(true); |
|
||||
return; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
pEpLog("sync protocol loop started"); |
|
||||
do_sync_protocol(session(), (void *)obj); |
|
||||
pEpLog("sync protocol loop ended"); |
|
||||
unregister_sync_callbacks(session()); |
|
||||
|
|
||||
session(release); |
|
||||
|
|
||||
if (obj && _shutdown) { |
|
||||
_shutdown(obj); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
template< class T > |
|
||||
void startup( |
|
||||
messageToSend_t messageToSend, |
|
||||
notifyHandshake_t notifyHandshake, |
|
||||
T *obj, |
|
||||
function< void(T *) > _startup, |
|
||||
function< void(T *) > _shutdown) |
|
||||
{ |
|
||||
pEpLog("called"); |
|
||||
if (messageToSend) { |
|
||||
_messageToSend = messageToSend; |
|
||||
} |
|
||||
|
|
||||
if (notifyHandshake) { |
|
||||
_notifyHandshake = notifyHandshake; |
|
||||
} |
|
||||
pEpLog("creating session"); |
|
||||
session(); |
|
||||
|
|
||||
if (!_sync_thread.joinable()) { |
|
||||
register_done.store(false); |
|
||||
pEpLog("creating sync-thread"); |
|
||||
|
|
||||
_sync_thread = std::thread(sync_thread<T>, obj, _startup, _shutdown); |
|
||||
while (register_done.load() == false) { |
|
||||
pEpLog("waiting for sync-thread to init..."); |
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
|
||||
} |
|
||||
|
|
||||
if (_ex) { |
|
||||
pEpLog("exception pending, rethrowing"); |
|
||||
std::rethrow_exception(_ex); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
#endif //LIBPEPADAPTER_ADAPTER_HXX
|
|
@ -1,26 +0,0 @@ |
|||||
// This file is under GNU General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#ifndef LIBPEPADAPTER_CALL_WITH_LOCK_HH |
|
||||
#define LIBPEPADAPTER_CALL_WITH_LOCK_HH |
|
||||
|
|
||||
#include <mutex> |
|
||||
|
|
||||
namespace pEp |
|
||||
{ |
|
||||
extern std::mutex call_with_lock_mutex; |
|
||||
|
|
||||
// TODO: use && and std::forward<> to avoid copying of the arguments.
|
|
||||
// It is not relevant, yet, because at the moment we use this function template only
|
|
||||
// for init() and release() which have cheap-to-copy pointer parameters only
|
|
||||
template<class R, class... Args> |
|
||||
R call_with_lock( R(*fn)(Args...), Args... args) |
|
||||
{ |
|
||||
std::lock_guard<std::mutex> L(call_with_lock_mutex); |
|
||||
return fn(args...); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
} |
|
||||
|
|
||||
#endif // LIBPEPADAPTER_CALL_WITH_LOCK_HH
|
|
@ -1,23 +0,0 @@ |
|||||
// This file is under GNU General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#include "constant_time_algo.hh" |
|
||||
|
|
||||
namespace pEp |
|
||||
{ |
|
||||
bool constant_time_equal(const std::string& a, const std::string& b) |
|
||||
{ |
|
||||
if(a.size() != b.size()) |
|
||||
return false; |
|
||||
|
|
||||
unsigned d = 0; |
|
||||
for(std::size_t idx = 0; idx<a.size(); ++idx) |
|
||||
{ |
|
||||
d |= ( static_cast<unsigned>(a[idx]) ^ static_cast<unsigned>(b[idx]) ); |
|
||||
} |
|
||||
|
|
||||
// if d is still 0, the strings are equal.
|
|
||||
return d == 0; |
|
||||
} |
|
||||
|
|
||||
} // end of namespace pEp
|
|
@ -1,135 +0,0 @@ |
|||||
// This file is under GNU General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#ifndef LIBPEPADAPTER_MESSAGE_CACHE_HH |
|
||||
#define LIBPEPADAPTER_MESSAGE_CACHE_HH |
|
||||
|
|
||||
#include <string> |
|
||||
#include <unordered_map> |
|
||||
#include <mutex> |
|
||||
#include <pEp/message_api.h> |
|
||||
#include <pEp/mime.h> |
|
||||
|
|
||||
namespace pEp { |
|
||||
class MessageCache { |
|
||||
struct cache_entry { |
|
||||
cache_entry(::message *s, ::message *d) |
|
||||
: src(s), dst(d) { } |
|
||||
|
|
||||
::message *src; |
|
||||
::message *dst; |
|
||||
}; |
|
||||
|
|
||||
using cache = std::unordered_map<std::string, cache_entry>; |
|
||||
|
|
||||
cache _cache; |
|
||||
std::mutex _mtx; |
|
||||
long long id_range = 42; |
|
||||
long long next_id = 23; |
|
||||
|
|
||||
public: |
|
||||
MessageCache(); |
|
||||
|
|
||||
enum which { msg_src = 0, msg_dst = 1 }; |
|
||||
|
|
||||
static PEP_STATUS cache_mime_decode_message( |
|
||||
const char *mimetext, |
|
||||
size_t size, |
|
||||
message **msg, |
|
||||
bool* has_possible_pEp_msg |
|
||||
); |
|
||||
|
|
||||
static PEP_STATUS cache_mime_encode_message( |
|
||||
int one, |
|
||||
const message * msg, |
|
||||
bool omit_fields, |
|
||||
char **mimetext, |
|
||||
bool has_pEp_msg_attachment |
|
||||
); |
|
||||
|
|
||||
static PEP_STATUS cache_decrypt_message( |
|
||||
PEP_SESSION session, |
|
||||
message *src, |
|
||||
message **dst, |
|
||||
stringlist_t **keylist, |
|
||||
PEP_rating *rating, |
|
||||
PEP_decrypt_flags_t *flags |
|
||||
); |
|
||||
|
|
||||
static PEP_STATUS cache_encrypt_message( |
|
||||
PEP_SESSION session, |
|
||||
message *src, |
|
||||
stringlist_t *extra, |
|
||||
message **dst, |
|
||||
PEP_enc_format enc_format, |
|
||||
PEP_encrypt_flags_t flags |
|
||||
); |
|
||||
|
|
||||
static PEP_STATUS cache_encrypt_message_for_self( |
|
||||
PEP_SESSION session, |
|
||||
pEp_identity* target_id, |
|
||||
message *src, |
|
||||
stringlist_t* extra, |
|
||||
message **dst, |
|
||||
PEP_enc_format enc_format, |
|
||||
PEP_encrypt_flags_t flags |
|
||||
); |
|
||||
|
|
||||
|
|
||||
static PEP_STATUS cache_release(std::string id); |
|
||||
static void removeCacheID(::message* msg); |
|
||||
|
|
||||
protected: |
|
||||
void release(std::string id); |
|
||||
|
|
||||
PEP_STATUS mime_decode_message( |
|
||||
const char *mimetext, |
|
||||
size_t size, |
|
||||
message **msg, |
|
||||
bool* has_possible_pEp_msg |
|
||||
); |
|
||||
|
|
||||
PEP_STATUS mime_encode_message( |
|
||||
which one, |
|
||||
const message * src, |
|
||||
bool omit_fields, |
|
||||
char **mimetext, |
|
||||
bool has_pEp_msg_attachment |
|
||||
); |
|
||||
|
|
||||
PEP_STATUS decrypt_message( |
|
||||
PEP_SESSION session, |
|
||||
message *src, |
|
||||
message **dst, |
|
||||
stringlist_t **keylist, |
|
||||
PEP_rating *rating, |
|
||||
PEP_decrypt_flags_t *flags |
|
||||
); |
|
||||
|
|
||||
PEP_STATUS encrypt_message( |
|
||||
PEP_SESSION session, |
|
||||
message *src, |
|
||||
stringlist_t *extra, |
|
||||
message **dst, |
|
||||
PEP_enc_format enc_format, |
|
||||
PEP_encrypt_flags_t flags |
|
||||
); |
|
||||
|
|
||||
PEP_STATUS encrypt_message_for_self( |
|
||||
PEP_SESSION session, |
|
||||
pEp_identity* target_id, |
|
||||
message *src, |
|
||||
stringlist_t* extra, |
|
||||
message **dst, |
|
||||
PEP_enc_format enc_format, |
|
||||
PEP_encrypt_flags_t flags |
|
||||
); |
|
||||
|
|
||||
void generateCacheID(::message* msg); |
|
||||
static std::string cacheID(const ::message* msg); |
|
||||
}; |
|
||||
|
|
||||
extern MessageCache message_cache; |
|
||||
}; |
|
||||
|
|
||||
#endif // LIBPEPADAPTER_MESSAGE_CACHE_HH
|
|
@ -1,40 +0,0 @@ |
|||||
// This file is under GNU General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#include "pEpLog.hh" |
|
||||
#include <iostream> |
|
||||
#include <sstream> |
|
||||
#include <mutex> |
|
||||
#include <atomic> |
|
||||
|
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace Adapter { |
|
||||
namespace pEpLog { |
|
||||
|
|
||||
std::mutex mtx; |
|
||||
|
|
||||
std::atomic_bool is_enabled{false}; |
|
||||
|
|
||||
void set_enabled(bool enabled) { |
|
||||
is_enabled.store(enabled); |
|
||||
} |
|
||||
|
|
||||
bool get_enabled() { |
|
||||
return is_enabled.load(); |
|
||||
} |
|
||||
|
|
||||
void log(std::string msg) { |
|
||||
if (is_enabled.load()) { |
|
||||
std::lock_guard<std::mutex> l(mtx); |
|
||||
#ifdef ANDROID |
|
||||
__android_log_print(ANDROID_LOG_DEBUG, "pEpDebugLog", "%s", msg.c_str()); |
|
||||
#else |
|
||||
std::cout << msg << std::endl; //std::endl also flushes
|
|
||||
#endif |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} // pEpLog
|
|
||||
} // Adapter
|
|
||||
} // pEp
|
|
@ -1,25 +0,0 @@ |
|||||
// This file is under GNU General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#include "slurp.hh" |
|
||||
#include <fstream> |
|
||||
#include <sstream> |
|
||||
#include <stdexcept> |
|
||||
|
|
||||
namespace pEp |
|
||||
{ |
|
||||
|
|
||||
std::string slurp(const std::string& filename) |
|
||||
{ |
|
||||
std::ifstream input(filename.c_str(), std::ios_base::binary); |
|
||||
if(!input) |
|
||||
{ |
|
||||
throw std::runtime_error("Cannot read file \"" + filename + "\"! "); |
|
||||
} |
|
||||
|
|
||||
std::stringstream sstr; |
|
||||
sstr << input.rdbuf(); |
|
||||
return sstr.str(); |
|
||||
} |
|
||||
|
|
||||
} // end of namespace pEp
|
|
@ -0,0 +1,242 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "Adapter.hh" |
||||
|
#include <sstream> |
||||
|
#include <iomanip> |
||||
|
#include <assert.h> |
||||
|
#include "status_to_string.hh" |
||||
|
#include "pEpLog.hh" |
||||
|
#include "passphrase_cache.hh" |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
thread_local pEp::Adapter::Session pEp::Adapter::session; |
||||
|
|
||||
|
namespace pEp { |
||||
|
void throw_status(::PEP_STATUS status) |
||||
|
{ |
||||
|
if (status == ::PEP_STATUS_OK) { |
||||
|
return; |
||||
|
} |
||||
|
if (status >= 0x400 && status <= 0x4ff) { |
||||
|
return; |
||||
|
} |
||||
|
if (status == ::PEP_STATEMACHINE_CANNOT_SEND) { |
||||
|
return; |
||||
|
} |
||||
|
if (status == ::PEP_OUT_OF_MEMORY) { |
||||
|
throw bad_alloc(); |
||||
|
} |
||||
|
if (status == ::PEP_ILLEGAL_VALUE) { |
||||
|
throw invalid_argument("illegal value"); |
||||
|
} |
||||
|
|
||||
|
string _status = status_to_string(status); |
||||
|
throw RuntimeError(_status, status); |
||||
|
} |
||||
|
|
||||
|
RuntimeError::RuntimeError(const std::string &_text, ::PEP_STATUS _status) |
||||
|
: std::runtime_error(_text.c_str()), text(_text), status(_status) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
namespace Adapter { |
||||
|
// private
|
||||
|
SyncModes _sync_mode = SyncModes::Async; |
||||
|
::messageToSend_t _messageToSend = nullptr; |
||||
|
::notifyHandshake_t _notifyHandshake = nullptr; |
||||
|
bool _adapter_manages_sync_thread = false; |
||||
|
::inject_sync_event_t _inject_action = _queue_sync_event; |
||||
|
std::thread _sync_thread; |
||||
|
::utility::locked_queue<SYNC_EVENT, ::free_Sync_event> sync_evt_q; |
||||
|
std::mutex mut; |
||||
|
|
||||
|
// private
|
||||
|
std::thread::id sync_thread_id() |
||||
|
{ |
||||
|
return _sync_thread.get_id(); |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
void sync_initialize( |
||||
|
SyncModes mode, |
||||
|
::messageToSend_t messageToSend, |
||||
|
::notifyHandshake_t notifyHandshake, |
||||
|
bool adapter_manages_sync_thread) |
||||
|
{ |
||||
|
_messageToSend = messageToSend; |
||||
|
_notifyHandshake = notifyHandshake; |
||||
|
_adapter_manages_sync_thread = adapter_manages_sync_thread; |
||||
|
set_sync_mode(mode); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
void set_sync_mode(SyncModes mode) |
||||
|
{ |
||||
|
// std::lock_guard<mutex> lock(mut);
|
||||
|
_sync_mode = mode; |
||||
|
if (_sync_mode == SyncModes::Sync) { |
||||
|
// init sesssion with inject_sync = process
|
||||
|
// stop sync
|
||||
|
session(release); |
||||
|
_inject_action = _process_sync_event; |
||||
|
session(init); |
||||
|
::register_sync_callbacks(session(), nullptr, _notifyHandshake, _retrieve_next_sync_event); |
||||
|
if(!_adapter_manages_sync_thread) { |
||||
|
shutdown(); |
||||
|
} else { |
||||
|
// The adapter need to shutdown sync thread
|
||||
|
} |
||||
|
} |
||||
|
if (_sync_mode == SyncModes::Async) { |
||||
|
// init session with inject_sync = queue
|
||||
|
// start sync thread
|
||||
|
session(release); |
||||
|
_inject_action = _queue_sync_event; |
||||
|
session(init); |
||||
|
if(!_adapter_manages_sync_thread) { |
||||
|
if (!is_sync_running()) { |
||||
|
startup<void>(_messageToSend, _notifyHandshake, nullptr, nullptr); |
||||
|
} |
||||
|
} else { |
||||
|
// The adapter need to do sync thread start up
|
||||
|
} |
||||
|
} |
||||
|
if (_sync_mode == SyncModes::Off) { |
||||
|
// init sesssion with inject_sync = null
|
||||
|
// stop sync thread
|
||||
|
if(!_adapter_manages_sync_thread) { |
||||
|
shutdown(); |
||||
|
} else { |
||||
|
// Adapter needs to shutdown sync thread
|
||||
|
} |
||||
|
session(release); |
||||
|
_inject_action = _queue_sync_event; |
||||
|
session(init); |
||||
|
} |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// private
|
||||
|
int _process_sync_event(::SYNC_EVENT ev, void *management) |
||||
|
{ |
||||
|
if (ev != nullptr) { |
||||
|
::do_sync_protocol_step(session(), nullptr, ev); |
||||
|
return 0; |
||||
|
} else { |
||||
|
return 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// private
|
||||
|
int _queue_sync_event(::SYNC_EVENT ev, void *management) |
||||
|
{ |
||||
|
try { |
||||
|
if (ev == nullptr) { |
||||
|
sync_evt_q.clear(); |
||||
|
sync_evt_q.push_back(ev); |
||||
|
} else { |
||||
|
sync_evt_q.push_front(ev); |
||||
|
} |
||||
|
} catch (exception &) { |
||||
|
return 1; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// private
|
||||
|
PEP_STATUS _ensure_passphrase(::PEP_SESSION session, const char *fpr) |
||||
|
{ |
||||
|
return passphrase_cache.ensure_passphrase(session, fpr); |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
::SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold) |
||||
|
{ |
||||
|
::SYNC_EVENT syncEvent = nullptr; |
||||
|
const bool success = sync_evt_q.try_pop_front(syncEvent, std::chrono::seconds(threshold)); |
||||
|
|
||||
|
if (!success) { |
||||
|
return ::new_sync_timeout_event(); |
||||
|
} |
||||
|
|
||||
|
return syncEvent; |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
bool on_sync_thread() |
||||
|
{ |
||||
|
return _sync_thread.get_id() == this_thread::get_id(); |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
::PEP_SESSION Session::operator()(session_action action) |
||||
|
{ |
||||
|
std::lock_guard<mutex> lock(mut); |
||||
|
|
||||
|
::PEP_STATUS status = ::PEP_STATUS_OK; |
||||
|
|
||||
|
switch (action) { |
||||
|
case release: |
||||
|
if (_session.get()) { |
||||
|
_session = nullptr; |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case init: |
||||
|
if (!_session.get()) { |
||||
|
::PEP_SESSION session_; |
||||
|
status = ::init(&session_, _messageToSend, _inject_action, _ensure_passphrase); |
||||
|
throw_status(status); |
||||
|
_session = SessionPtr{session_, ::release}; |
||||
|
} |
||||
|
break; |
||||
|
default: |
||||
|
status = ::PEP_ILLEGAL_VALUE; |
||||
|
} |
||||
|
|
||||
|
throw_status(status); |
||||
|
return _session.get(); |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
void shutdown() |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
if (_sync_thread.joinable()) { |
||||
|
pEpLog("sync_is_running - injecting null event"); |
||||
|
_queue_sync_event(nullptr, nullptr); |
||||
|
_sync_thread.join(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
bool is_sync_running() |
||||
|
{ |
||||
|
if(!_adapter_manages_sync_thread) { |
||||
|
return _sync_thread.joinable(); |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// public
|
||||
|
// Works even if adapter is managing sync thread, BUT must be using this queue
|
||||
|
bool in_shutdown() |
||||
|
{ |
||||
|
SYNC_EVENT ev; |
||||
|
try { |
||||
|
ev = sync_evt_q.back(); |
||||
|
} catch (std::underflow_error &) { |
||||
|
return false; |
||||
|
} |
||||
|
if (ev) { |
||||
|
return false; |
||||
|
} else { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
@ -0,0 +1,148 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef LIBPEPADAPTER_ADAPTER_HXX |
||||
|
#define LIBPEPADAPTER_ADAPTER_HXX |
||||
|
|
||||
|
#include <thread> |
||||
|
#include "locked_queue.hh" |
||||
|
#include <cassert> |
||||
|
#include "pEpLog.hh" |
||||
|
#include <atomic> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Adapter { |
||||
|
using std::function; |
||||
|
|
||||
|
extern ::messageToSend_t _messageToSend; |
||||
|
extern ::notifyHandshake_t _notifyHandshake; |
||||
|
extern std::thread _sync_thread; |
||||
|
|
||||
|
extern ::utility::locked_queue<::SYNC_EVENT, ::free_Sync_event> sync_evt_q; |
||||
|
extern std::mutex mut; |
||||
|
|
||||
|
::SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold); |
||||
|
|
||||
|
static std::exception_ptr _ex; |
||||
|
static std::atomic_bool register_done{false}; |
||||
|
|
||||
|
/*
|
||||
|
* Sync Thread |
||||
|
* 1. Execute registered startup function |
||||
|
* 2. Create session for the sync thread (registers: messageToSend, inject_sync_event, ensure_passphrase) |
||||
|
* 3. register_sync_callbacks() (registers: _notifyHandshake, _retrieve_next_sync_event) |
||||
|
* 4. Enter Sync Event Dispatching Loop (do_sync_protocol()) |
||||
|
* 5. unregister_sync_callbacks() |
||||
|
* 6. Release the session |
||||
|
* 7. Execute registered shutdown function |
||||
|
*/ |
||||
|
// private
|
||||
|
template<class T> |
||||
|
void sync_thread(T *obj, function<void(T *)> _startup, function<void(T *)> _shutdown) |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
_ex = nullptr; |
||||
|
assert(_messageToSend); |
||||
|
assert(_notifyHandshake); |
||||
|
|
||||
|
// 1. Execute registered startup function
|
||||
|
if (obj && _startup) { |
||||
|
_startup(obj); |
||||
|
} |
||||
|
|
||||
|
pEpLog("creating session for the sync thread"); |
||||
|
// 2. Create session for the sync thread
|
||||
|
session(); |
||||
|
|
||||
|
// 3. register_sync_callbacks()
|
||||
|
{ |
||||
|
// TODO: Do we need to use a passphraseWrap here???
|
||||
|
pEpLog("register_sync_callbacks()"); |
||||
|
::PEP_STATUS status = ::register_sync_callbacks( |
||||
|
session(), |
||||
|
nullptr, |
||||
|
_notifyHandshake, |
||||
|
_retrieve_next_sync_event); |
||||
|
|
||||
|
pEpLog("register_sync_callbacks() return:" << status); |
||||
|
// Convert status into exception and store it
|
||||
|
// set register_done AFTER that
|
||||
|
try { |
||||
|
throw_status(status); |
||||
|
register_done.store(true); |
||||
|
} catch (...) { |
||||
|
_ex = std::current_exception(); |
||||
|
register_done.store(true); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
pEpLog("sync protocol loop started"); |
||||
|
// 4. Enter Sync Event Dispatching Loop (do_sync_protocol())
|
||||
|
::do_sync_protocol(session(), (void *)obj); |
||||
|
pEpLog("sync protocol loop ended"); |
||||
|
|
||||
|
// 5. unregister_sync_callbacks()
|
||||
|
unregister_sync_callbacks(session()); |
||||
|
|
||||
|
// 6. Release the session
|
||||
|
// TODO: Maybe do that AFTER shutdown?
|
||||
|
session(release); |
||||
|
|
||||
|
// 7. Execute registered shutdown function
|
||||
|
if (obj && _shutdown) { |
||||
|
_shutdown(obj); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
* Sync Thread Startup |
||||
|
* 1. ensure session for the main thread (registers: messageToSend, _queue_sync_event, _ensure_passphrase) |
||||
|
* 2. Start the sync thread |
||||
|
* 3. Defer execution until sync thread register_sync_callbacks() has returned |
||||
|
* 4. Throw pending exception from the sync thread |
||||
|
*/ |
||||
|
// private
|
||||
|
template<class T> |
||||
|
void startup( |
||||
|
::messageToSend_t messageToSend, |
||||
|
::notifyHandshake_t notifyHandshake, |
||||
|
T *obj, |
||||
|
function<void(T *)> _startup, |
||||
|
function<void(T *)> _shutdown) |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
if (messageToSend) { |
||||
|
_messageToSend = messageToSend; |
||||
|
} |
||||
|
|
||||
|
if (notifyHandshake) { |
||||
|
_notifyHandshake = notifyHandshake; |
||||
|
} |
||||
|
pEpLog("ensure session for the main thread"); |
||||
|
// 1. re-initialize session for the main thread (registers: messageToSend, _queue_sync_event, _ensure_passphrase)
|
||||
|
session(release); |
||||
|
session(init); |
||||
|
|
||||
|
if (!_sync_thread.joinable()) { |
||||
|
register_done.store(false); |
||||
|
pEpLog("creating sync-thread"); |
||||
|
// 2. Start the sync thread
|
||||
|
_sync_thread = std::thread(sync_thread<T>, obj, _startup, _shutdown); |
||||
|
// 3. Defer execution until sync thread register_sync_callbacks() has returned
|
||||
|
while (register_done.load() == false) { |
||||
|
pEpLog("waiting for sync-thread to init..."); |
||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
||||
|
} |
||||
|
|
||||
|
// 4. Throw pending exception from the sync thread
|
||||
|
if (_ex) { |
||||
|
pEpLog("exception pending, rethrowing"); |
||||
|
std::rethrow_exception(_ex); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#endif //LIBPEPADAPTER_ADAPTER_HXX
|
@ -0,0 +1,37 @@ |
|||||
|
# Copyright 2018, pEp Foundation
|
||||
|
# This file is part of lib pEp Adapter
|
||||
|
# This file may be used under the terms of the GNU General Public License version 3
|
||||
|
# see LICENSE.txt
|
||||
|
|
||||
|
include ../Makefile.conf |
||||
|
|
||||
|
SOURCE=$(wildcard *.cc) |
||||
|
HEADERS=$(wildcard *.hh *.hxx) |
||||
|
OBJECTS=$(subst .cc,.o,$(SOURCE)) |
||||
|
DEPENDS=$(subst .cc,.d,$(SOURCE)) |
||||
|
CXXFLAGS+= -MMD -MP |
||||
|
|
||||
|
ifneq ($(MAKECMDGOALS),clean) |
||||
|
-include $(DEPENDS) |
||||
|
endif |
||||
|
|
||||
|
.PHONY: install uninstall clean |
||||
|
|
||||
|
all: $(TARGET) |
||||
|
|
||||
|
$(TARGET): $(OBJECTS) |
||||
|
$(AR) -rc $@ $^ |
||||
|
|
||||
|
clean: |
||||
|
rm -vf $(TARGET) $(OBJECTS) $(DEPENDS) |
||||
|
rm -f *.d.* |
||||
|
|
||||
|
install: $(TARGET) |
||||
|
mkdir -p $(PREFIX)/include/pEp |
||||
|
mkdir -p $(PREFIX)/lib |
||||
|
cp -v $(HEADERS) $(PREFIX)/include/pEp/ |
||||
|
cp -v $(TARGET) $(PREFIX)/lib/ |
||||
|
|
||||
|
uninstall: |
||||
|
cd $(PREFIX)/include/pEp && rm -vf $(HEADERS) |
||||
|
cd $(PREFIX)/lib && rm -vf $(TARGET) |
@ -0,0 +1,26 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef LIBPEPADAPTER_CALL_WITH_LOCK_HH |
||||
|
#define LIBPEPADAPTER_CALL_WITH_LOCK_HH |
||||
|
|
||||
|
#include <mutex> |
||||
|
|
||||
|
namespace pEp { |
||||
|
extern std::mutex call_with_lock_mutex; |
||||
|
|
||||
|
// TODO: use && and std::forward<> to avoid copying of the arguments.
|
||||
|
// It is not relevant, yet, because at the moment we use this function
|
||||
|
// template only for init() and release() which have cheap-to-copy pointer
|
||||
|
// parameters only
|
||||
|
template<class R, class... Args> |
||||
|
R call_with_lock(R (*fn)(Args...), Args... args) |
||||
|
{ |
||||
|
std::lock_guard<std::mutex> L(call_with_lock_mutex); |
||||
|
return fn(args...); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#endif // LIBPEPADAPTER_CALL_WITH_LOCK_HH
|
@ -0,0 +1,21 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "constant_time_algo.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
bool constant_time_equal(const std::string &a, const std::string &b) |
||||
|
{ |
||||
|
if (a.size() != b.size()) |
||||
|
return false; |
||||
|
|
||||
|
unsigned d = 0; |
||||
|
for (std::size_t idx = 0; idx < a.size(); ++idx) { |
||||
|
d |= (static_cast<unsigned>(a[idx]) ^ static_cast<unsigned>(b[idx])); |
||||
|
} |
||||
|
|
||||
|
// if d is still 0, the strings are equal.
|
||||
|
return d == 0; |
||||
|
} |
||||
|
|
||||
|
} // end of namespace pEp
|
@ -0,0 +1,128 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef LIBPEPADAPTER_MESSAGE_CACHE_HH |
||||
|
#define LIBPEPADAPTER_MESSAGE_CACHE_HH |
||||
|
|
||||
|
#include <string> |
||||
|
#include <unordered_map> |
||||
|
#include <mutex> |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/mime.h> |
||||
|
|
||||
|
namespace pEp { |
||||
|
class MessageCache { |
||||
|
struct cache_entry { |
||||
|
cache_entry(::message *s, ::message *d) : src(s), dst(d) {} |
||||
|
|
||||
|
::message *src; |
||||
|
::message *dst; |
||||
|
}; |
||||
|
|
||||
|
using cache = std::unordered_map<std::string, cache_entry>; |
||||
|
|
||||
|
cache _cache; |
||||
|
std::mutex _mtx; |
||||
|
long long id_range = 42; |
||||
|
long long next_id = 23; |
||||
|
|
||||
|
public: |
||||
|
MessageCache(); |
||||
|
|
||||
|
enum which |
||||
|
{ |
||||
|
msg_src = 0, |
||||
|
msg_dst = 1 |
||||
|
}; |
||||
|
|
||||
|
static PEP_STATUS cache_mime_decode_message( |
||||
|
const char *mimetext, |
||||
|
size_t size, |
||||
|
message **msg, |
||||
|
bool *has_possible_pEp_msg); |
||||
|
|
||||
|
static PEP_STATUS cache_mime_encode_message( |
||||
|
int one, |
||||
|
const message *msg, |
||||
|
bool omit_fields, |
||||
|
char **mimetext, |
||||
|
bool has_pEp_msg_attachment); |
||||
|
|
||||
|
static PEP_STATUS cache_decrypt_message( |
||||
|
PEP_SESSION session, |
||||
|
message *src, |
||||
|
message **dst, |
||||
|
stringlist_t **keylist, |
||||
|
PEP_rating *rating, |
||||
|
PEP_decrypt_flags_t *flags); |
||||
|
|
||||
|
static PEP_STATUS cache_encrypt_message( |
||||
|
PEP_SESSION session, |
||||
|
message *src, |
||||
|
stringlist_t *extra, |
||||
|
message **dst, |
||||
|
PEP_enc_format enc_format, |
||||
|
PEP_encrypt_flags_t flags); |
||||
|
|
||||
|
static PEP_STATUS cache_encrypt_message_for_self( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *target_id, |
||||
|
message *src, |
||||
|
stringlist_t *extra, |
||||
|
message **dst, |
||||
|
PEP_enc_format enc_format, |
||||
|
PEP_encrypt_flags_t flags); |
||||
|
|
||||
|
|
||||
|
static PEP_STATUS cache_release(std::string id); |
||||
|
static void removeCacheID(::message *msg); |
||||
|
|
||||
|
protected: |
||||
|
void release(std::string id); |
||||
|
|
||||
|
PEP_STATUS mime_decode_message( |
||||
|
const char *mimetext, |
||||
|
size_t size, |
||||
|
message **msg, |
||||
|
bool *has_possible_pEp_msg); |
||||
|
|
||||
|
PEP_STATUS mime_encode_message( |
||||
|
which one, |
||||
|
const message *src, |
||||
|
bool omit_fields, |
||||
|
char **mimetext, |
||||
|
bool has_pEp_msg_attachment); |
||||
|
|
||||
|
PEP_STATUS decrypt_message( |
||||
|
PEP_SESSION session, |
||||
|
message *src, |
||||
|
message **dst, |
||||
|
stringlist_t **keylist, |
||||
|
PEP_rating *rating, |
||||
|
PEP_decrypt_flags_t *flags); |
||||
|
|
||||
|
PEP_STATUS encrypt_message( |
||||
|
PEP_SESSION session, |
||||
|
message *src, |
||||
|
stringlist_t *extra, |
||||
|
message **dst, |
||||
|
PEP_enc_format enc_format, |
||||
|
PEP_encrypt_flags_t flags); |
||||
|
|
||||
|
PEP_STATUS encrypt_message_for_self( |
||||
|
PEP_SESSION session, |
||||
|
pEp_identity *target_id, |
||||
|
message *src, |
||||
|
stringlist_t *extra, |
||||
|
message **dst, |
||||
|
PEP_enc_format enc_format, |
||||
|
PEP_encrypt_flags_t flags); |
||||
|
|
||||
|
void generateCacheID(::message *msg); |
||||
|
static std::string cacheID(const ::message *msg); |
||||
|
}; |
||||
|
|
||||
|
extern MessageCache message_cache; |
||||
|
}; // namespace pEp
|
||||
|
|
||||
|
#endif // LIBPEPADAPTER_MESSAGE_CACHE_HH
|
@ -0,0 +1,43 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "pEpLog.hh" |
||||
|
#include <iostream> |
||||
|
#include <sstream> |
||||
|
#include <mutex> |
||||
|
#include <atomic> |
||||
|
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Adapter { |
||||
|
namespace pEpLog { |
||||
|
|
||||
|
std::mutex mtx; |
||||
|
|
||||
|
std::atomic_bool is_enabled{false}; |
||||
|
|
||||
|
void set_enabled(bool enabled) |
||||
|
{ |
||||
|
is_enabled.store(enabled); |
||||
|
} |
||||
|
|
||||
|
bool get_enabled() |
||||
|
{ |
||||
|
return is_enabled.load(); |
||||
|
} |
||||
|
|
||||
|
void log(std::string msg) |
||||
|
{ |
||||
|
if (is_enabled.load()) { |
||||
|
std::lock_guard<std::mutex> l(mtx); |
||||
|
#ifdef ANDROID |
||||
|
__android_log_print(ANDROID_LOG_DEBUG, "pEpDebugLog", "%s", msg.c_str()); |
||||
|
#else |
||||
|
std::cout << msg << std::endl; //std::endl also flushes
|
||||
|
#endif |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} // namespace pEpLog
|
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
@ -0,0 +1,21 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "slurp.hh" |
||||
|
#include <fstream> |
||||
|
#include <sstream> |
||||
|
#include <stdexcept> |
||||
|
|
||||
|
namespace pEp { |
||||
|
std::string slurp(const std::string& filename) |
||||
|
{ |
||||
|
std::ifstream input(filename.c_str(), std::ios_base::binary); |
||||
|
if (!input) { |
||||
|
throw std::runtime_error("Cannot read file \"" + filename + "\"! "); |
||||
|
} |
||||
|
|
||||
|
std::stringstream sstr; |
||||
|
sstr << input.rdbuf(); |
||||
|
return sstr.str(); |
||||
|
} |
||||
|
} // end of namespace pEp
|
@ -0,0 +1,23 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "status_to_string.hh" |
||||
|
#include <sstream> |
||||
|
|
||||
|
|
||||
|
namespace pEp { |
||||
|
|
||||
|
// in pEpEngine.h positive values are hex, negative are decimal. :-o
|
||||
|
// TODO: the code should be generated!
|
||||
|
std::string status_to_string(PEP_STATUS status) |
||||
|
{ |
||||
|
std::stringstream ss; |
||||
|
if (status > 0) { |
||||
|
ss << "0x" << std::hex << status; |
||||
|
} else { |
||||
|
ss << status; |
||||
|
} |
||||
|
return ss.str() + " \"" + pEp_status_to_string(status) + '"'; |
||||
|
} |
||||
|
|
||||
|
} // end of namespace pEp
|
@ -1,25 +0,0 @@ |
|||||
// This file is under GNU General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#include "status_to_string.hh" |
|
||||
#include <sstream> |
|
||||
|
|
||||
|
|
||||
namespace pEp |
|
||||
{ |
|
||||
|
|
||||
// in pEpEngine.h positive values are hex, negative are decimal. :-o
|
|
||||
// TODO: the code should be generated!
|
|
||||
std::string status_to_string(PEP_STATUS status) |
|
||||
{ |
|
||||
std::stringstream ss; |
|
||||
if(status>0) |
|
||||
{ |
|
||||
ss << "0x" << std::hex << status; |
|
||||
}else{ |
|
||||
ss << status; |
|
||||
} |
|
||||
return ss.str() + " \"" + pEp_status_to_string(status) + '"'; |
|
||||
} |
|
||||
|
|
||||
} // end of namespace pEp
|
|
@ -1,116 +1,105 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
#include "pc_container.hh" |
#include "pc_container.hh" |
||||
#include <cstdio> |
#include <cstdio> |
||||
#include <cstdlib> |
#include <cstdlib> |
||||
#include <iostream> |
#include <iostream> |
||||
#include <thread> |
#include <thread> |
||||
|
|
||||
|
|
||||
using namespace pEp; |
using namespace pEp; |
||||
|
|
||||
|
|
||||
// Producer's data:
|
// Producer's data:
|
||||
class P |
class P { |
||||
{ |
|
||||
public: |
public: |
||||
P(int i) |
P(int i) : data{ new char[64] } |
||||
: data{new char[64]} |
{ |
||||
{ |
snprintf(data, 63, "%i", i); |
||||
snprintf(data, 63, "%i", i); |
} |
||||
} |
|
||||
|
P(const P&) = delete; |
||||
P(const P&) = delete; |
void operator=(const P&) = delete; |
||||
void operator=(const P&) = delete; |
|
||||
|
~P() |
||||
~P() |
{ |
||||
{ |
std::cerr << "~P(): data=" << (data ? data : "(NULL)") << '\n'; |
||||
std::cerr << "~P(): data=" << (data ? data : "(NULL)" ) << '\n'; |
delete[] data; |
||||
delete[] data; |
} |
||||
} |
|
||||
|
char* data; |
||||
char* data; |
|
||||
}; |
}; |
||||
|
|
||||
|
|
||||
// Consumer's data:
|
// Consumer's data:
|
||||
class C |
class C { |
||||
{ |
|
||||
public: |
public: |
||||
C(int _i) : i(_i) {} |
C(int _i) : i(_i) {} |
||||
int i; |
int i; |
||||
}; |
}; |
||||
|
|
||||
pc_container<P,C> pc; |
pc_container<P, C> pc; |
||||
|
|
||||
void consumer_thread() |
void consumer_thread() |
||||
{ |
{ |
||||
bool keep_running = true; |
bool keep_running = true; |
||||
int sum = 0; |
int sum = 0; |
||||
while(keep_running) |
while (keep_running) { |
||||
{ |
for (auto& q : pc) { |
||||
for(auto& q : pc) |
switch (q.state()) { |
||||
{ |
case PC_State::Created: { |
||||
switch(q.state()) |
const int value = atoi(q.pdata->data); |
||||
{ |
if (value < 0) { |
||||
case PC_State::Created: |
std::cerr << "Q\n"; |
||||
{ |
keep_running = false; |
||||
const int value = atoi( q.pdata->data ); |
} else { |
||||
if(value<0) |
std::cerr << "C"; |
||||
{ |
q.cdata = new C(value); |
||||
std::cerr << "Q\n"; |
sum += q.cdata->i; |
||||
keep_running = false; |
} |
||||
}else{ |
break; |
||||
std::cerr << "C"; |
} |
||||
q.cdata = new C( value ); |
case PC_State::Deleted: { |
||||
sum += q.cdata->i; |
std::cerr << "D"; |
||||
} |
sum -= q.cdata->i; |
||||
break; |
delete q.cdata; |
||||
} |
break; |
||||
case PC_State::Deleted: |
} |
||||
{ |
case PC_State::Changed: { |
||||
std::cerr << "D"; |
std::cerr << "X"; |
||||
sum -= q.cdata->i; |
sum -= q.cdata->i; |
||||
delete q.cdata; |
delete q.cdata; |
||||
break; |
q.cdata = new C(atoi(q.pdata->data)); |
||||
} |
sum += q.cdata->i; |
||||
case PC_State::Changed: |
break; |
||||
{ |
} |
||||
std::cerr << "X"; |
default: |
||||
sum -= q.cdata->i; |
throw "Illegal state"; |
||||
delete q.cdata; |
} |
||||
q.cdata = new C( atoi( q.pdata->data ) ); |
} |
||||
sum += q.cdata->i; |
} |
||||
break; |
|
||||
} |
std::cout << "Consumer sum: " << sum << ".\n"; |
||||
default: throw "Illegal state"; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
std::cout << "Consumer sum: " << sum << ".\n"; |
|
||||
} |
} |
||||
|
|
||||
int main() |
int main() |
||||
{ |
{ |
||||
for(int i=0; i<10; ++i) |
for (int i = 0; i < 10; ++i) { |
||||
{ |
pc.insert(new P(i)); |
||||
pc.insert( new P(i) ); |
} |
||||
} |
|
||||
|
|
||||
std::thread t{ &consumer_thread }; |
std::thread t{ &consumer_thread }; |
||||
|
|
||||
for(int i=10; i<100; ++i) |
for (int i = 10; i < 100; ++i) { |
||||
{ |
pc.insert(new P(i)); |
||||
pc.insert( new P(i) ); |
} |
||||
} |
|
||||
|
|
||||
while( !pc.empty() ) |
while (!pc.empty()) { |
||||
{ |
auto q = pc.begin(); |
||||
auto q = pc.begin(); |
delete q->pdata; |
||||
delete q->pdata; |
pc.erase(q); |
||||
pc.erase( q ); |
} |
||||
} |
|
||||
|
|
||||
pc.insert( new P(-1) ); |
pc.insert(new P(-1)); |
||||
|
|
||||
t.join(); |
t.join(); |
||||
} |
} |
||||
|
Loading…
Reference in new issue