Browse Source

Merge branch 'master' into Release_2.1

android-build
heck 1 year ago
parent
commit
ba3f8d141d
47 changed files with 1343 additions and 1137 deletions
  1. +41
    -0
      .clang-format
  2. +0
    -154
      Adapter.cc
  3. +0
    -110
      Adapter.hxx
  4. +9
    -32
      Makefile
  5. +3
    -2
      Makefile.conf
  6. +0
    -0
      README.md
  7. +0
    -26
      call_with_lock.hh
  8. +0
    -23
      constant_time_algo.cc
  9. +0
    -135
      message_cache.hh
  10. +0
    -40
      pEpLog.cc
  11. +0
    -25
      slurp.cc
  12. +242
    -0
      src/Adapter.cc
  13. +35
    -17
      src/Adapter.hh
  14. +148
    -0
      src/Adapter.hxx
  15. +37
    -0
      src/Makefile
  16. +3
    -5
      src/Semaphore.hh
  17. +2
    -3
      src/call_with_lock.cc
  18. +26
    -0
      src/call_with_lock.hh
  19. +19
    -15
      src/callback_dispatcher.cc
  20. +6
    -8
      src/callback_dispatcher.hh
  21. +21
    -0
      src/constant_time_algo.cc
  22. +2
    -3
      src/constant_time_algo.hh
  23. +20
    -27
      src/locked_queue.hh
  24. +114
    -139
      src/message_cache.cc
  25. +128
    -0
      src/message_cache.hh
  26. +43
    -0
      src/pEpLog.cc
  27. +11
    -10
      src/pEpLog.hh
  28. +26
    -29
      src/passphrase_cache.cc
  29. +12
    -12
      src/passphrase_cache.hh
  30. +4
    -5
      src/passphrase_cache.hxx
  31. +0
    -0
      src/pc_container.hh
  32. +21
    -0
      src/slurp.cc
  33. +1
    -2
      src/slurp.hh
  34. +23
    -0
      src/status_to_string.cc
  35. +2
    -3
      src/status_to_string.hh
  36. +0
    -25
      status_to_string.cc
  37. +3
    -4
      test/Makefile
  38. +33
    -26
      test/framework.cc
  39. +7
    -6
      test/framework.hh
  40. +13
    -9
      test/test_adapter.cc
  41. +51
    -37
      test/test_adapter_cxx.cc
  42. +14
    -11
      test/test_ensure_passphrase.cc
  43. +42
    -41
      test/test_leave_device_group.cc
  44. +80
    -91
      test/test_library.cc
  45. +36
    -17
      test/test_message_cache.cc
  46. +49
    -31
      test/test_passphrase_cache.cc
  47. +16
    -14
      test/test_semaphore.cc

+ 41
- 0
.clang-format View File

@ -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

+ 0
- 154
Adapter.cc View File

@ -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;
}
}
}
}

+ 0
- 110
Adapter.hxx View File

@ -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

+ 9
- 32
Makefile View File

@ -3,45 +3,22 @@
# This file may be used under the terms of the GNU General Public License version 3
# see LICENSE.txt
include Makefile.conf
.PHONY: src test install uninstall clean
TARGET=libpEpAdapter.a
all: src
.PHONY: install uninstall clean
src:
$(MAKE) -C src
SOURCE=$(wildcard *.cc)
HEADERS=$(wildcard *.hh *.hxx)
OBJECTS=$(subst .cc,.o,$(SOURCE))
DEPENDS=$(subst .cc,.d,$(SOURCE))
CXXFLAGS+= -MMD -MP
all: $(TARGET)
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPENDS)
endif
lib: $(TARGET)
all: lib
test: lib
test: src
$(MAKE) -C test
$(TARGET): $(OBJECTS)
$(AR) -rc $@ $^
clean:
rm -vf $(TARGET) $(OBJECTS) $(DEPENDS)
rm -f *.d.*
$(MAKE) -C src clean
$(MAKE) -C test clean
install: $(TARGET)
mkdir -p $(PREFIX)/include/pEp
mkdir -p $(PREFIX)/lib
cp -v $(HEADERS) $(PREFIX)/include/pEp/
cp -v $(TARGET) $(PREFIX)/lib/
install:
$(MAKE) -C src install
uninstall:
cd $(PREFIX)/include/pEp && rm -vf $(HEADERS)
cd $(PREFIX)/lib && rm -vf $(TARGET)
$(MAKE) -C src uninstall

+ 3
- 2
Makefile.conf View File

@ -1,10 +1,11 @@
# Copyright 2018, pEp Foundation
# This file is part of lib pEp Adapter
# This file is part of libpEpAdapter
# This file may be used under the terms of the GNU General Public License version 3
# see LICENSE.txt
HERE:=$(dir $(lastword $(MAKEFILE_LIST)))
TARGET=libpEpAdapter.a
# Defaults
DEBUG=1
@ -12,7 +13,7 @@ PREFIX?=$(HOME)
ENGINE_LIB_PATH=$(PREFIX)/lib
ENGINE_INC_PATH=$(PREFIX)/include
CXXFLAGS+=-std=c++11 -fPIC
CXXFLAGS+=-std=c++14 -fPIC
# Build target
BUILD_FOR:=$(shell uname)


readme.md → README.md View File


+ 0
- 26
call_with_lock.hh View File

@ -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

+ 0
- 23
constant_time_algo.cc View File

@ -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

+ 0
- 135
message_cache.hh View File

@ -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

+ 0
- 40
pEpLog.cc View File

@ -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

+ 0
- 25
slurp.cc View File

@ -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

+ 242
- 0
src/Adapter.cc View File

@ -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

Adapter.hh → src/Adapter.hh View File


+ 148
- 0
src/Adapter.hxx View File

@ -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

+ 37
- 0
src/Makefile View File

@ -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)

Semaphore.hh → src/Semaphore.hh View File


call_with_lock.cc → src/call_with_lock.cc View File


+ 26
- 0
src/call_with_lock.hh View File

@ -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

callback_dispatcher.cc → src/callback_dispatcher.cc View File


callback_dispatcher.hh → src/callback_dispatcher.hh View File


+ 21
- 0
src/constant_time_algo.cc View File

@ -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

constant_time_algo.hh → src/constant_time_algo.hh View File


locked_queue.hh → src/locked_queue.hh View File


message_cache.cc → src/message_cache.cc View File


+ 128
- 0
src/message_cache.hh View File

@ -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

+ 43
- 0
src/pEpLog.cc View File

@ -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

pEpLog.hh → src/pEpLog.hh View File


passphrase_cache.cc → src/passphrase_cache.cc View File


passphrase_cache.hh → src/passphrase_cache.hh View File


passphrase_cache.hxx → src/passphrase_cache.hxx View File


pc_container.hh → src/pc_container.hh View File


+ 21
- 0
src/slurp.cc View File

@ -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

slurp.hh → src/slurp.hh View File


+ 23
- 0
src/status_to_string.cc View File

@ -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

status_to_string.hh → src/status_to_string.hh View File


+ 0
- 25
status_to_string.cc View File

@ -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

+ 3
- 4
test/Makefile View File

@ -1,9 +1,8 @@
include ../Makefile.conf
LDFLAGS=-L../ $(ENGINE_LIB)
LDFLAGS=-L../src $(ENGINE_LIB)
LDLIBS=-lstdc++ -lpEpEngine -lpEpAdapter
CXXFLAGS+=-I../ $(ENGINE_INC) -std=c++11 -DENGINE_TEST=$(ENGINE_TEST)
CXXFLAGS:=-I../src -DENGINE_TEST=$(ENGINE_TEST) $(CXXFLAGS)
SRC=$(wildcard test_*.cc)
TST=$(subst .cc,,$(SRC))
@ -13,7 +12,7 @@ $(TST): framework.o
.PHONY: clean rmtestdata
clean:
clean:
rm -f $(TST)
rm -Rf *.dSYM
rm -f *.o


+ 33
- 26
test/framework.cc View File

@ -1,5 +1,7 @@
#include "framework.hh"
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "framework.hh"
#include <iostream>
#include <fstream>
#include <sstream>
@ -20,6 +22,8 @@
#include <pEp/sync_codec.h>
#include <pEp/distribution_codec.h>
#include <Adapter.hh>
pEp::Test::Transport pEp::Test::transport;
std::string pEp::Test::path;
extern std::thread pEp::Adapter::_sync_thread;
@ -28,7 +32,7 @@ namespace pEp {
namespace Test {
using namespace Adapter;
void setup(vector<string>& args)
void setup(vector<string> &args)
{
#ifdef WIN32
string dir = getenv("TEMP");
@ -45,17 +49,15 @@ namespace pEp {
cout << "usage: " << args[0] << " [--dir HOME]" << endl;
#endif
exit(0);
}
else if (args[1] == "--dir" && args.size() == 3) {
} else if (args[1] == "--dir" && args.size() == 3) {
dir = args[2];
}
else {
} else {
cerr << "illegal parameter" << endl;
exit(1);
}
}
char _path[MAXPATHLEN+1];
char _path[MAXPATHLEN + 1];
const char *templ = dir.c_str();
strcpy(_path, templ);
mkdtemp(_path);
@ -71,8 +73,8 @@ namespace pEp {
void setup(int argc, char **argv)
{
vector<string> args{(size_t) argc};
for (int i=0; i<argc; ++i)
vector<string> args{ (size_t)argc };
for (int i = 0; i < argc; ++i)
args[i] = argv[i];
setup(args);
@ -81,9 +83,12 @@ namespace pEp {
void import_key_from_file(string filename)
{
ifstream f(filename, ifstream::in);
string key{istreambuf_iterator<char>(f), istreambuf_iterator<char>()};
string key{ istreambuf_iterator<char>(f), istreambuf_iterator<char>() };
::identity_list *il = NULL;
PEP_STATUS status = ::import_key(session(), key.c_str(), key.length(), &il);
cout << key.c_str() << endl;
cout << key.length() << endl;
::PEP_STATUS status = ::import_key(session(), key.c_str(), key.length(), &il);
throw_status(status);
assert(status == PEP_KEY_IMPORTED);
::free_identity_list(il);
}
@ -95,14 +100,18 @@ namespace pEp {
Identity make_identity(::pEp_identity *ident)
{
return shared_ptr<::pEp_identity>(ident , ::free_identity);
return shared_ptr<::pEp_identity>(ident, ::free_identity);
}
Message mime_parse(string text)
{
::message *msg;
bool has_possible_pEp_msg;
PEP_STATUS status = ::mime_decode_message(text.c_str(), text.length(), &msg, &has_possible_pEp_msg);
::PEP_STATUS status = ::mime_decode_message(
text.c_str(),
text.length(),
&msg,
&has_possible_pEp_msg);
throw_status(status);
return make_message(msg);
}
@ -123,9 +132,9 @@ namespace pEp {
::message *_dst;
stringlist_t *keylist;
PEP_rating rating;
PEP_decrypt_flags_t flags = 0;
PEP_STATUS status = ::decrypt_message(session(), msg.get(), &_dst, &keylist, &rating, &flags);
::PEP_rating rating;
::PEP_decrypt_flags_t flags = 0;
::PEP_STATUS status = ::decrypt_message(session(), msg.get(), &_dst, &keylist, &rating, &flags);
throw_status(status);
Message dst;
@ -138,18 +147,17 @@ namespace pEp {
for (auto a = dst.get()->attachments; a && a->value; a = a->next) {
if (string("application/pEp.sync") == a->mime_type) {
char *_text;
status = PER_to_XER_Sync_msg(a->value, a->size, &_text);
status = ::PER_to_XER_Sync_msg(a->value, a->size, &_text);
throw_status(status);
text += _text;
pEp_free(_text);
::pEp_free(_text);
return text;
}
else if (string("application/pEp.distribution") == a->mime_type) {
} else if (string("application/pEp.distribution") == a->mime_type) {
char *_text;
status = PER_to_XER_Distribution_msg(a->value, a->size, &_text);
status = ::PER_to_XER_Distribution_msg(a->value, a->size, &_text);
throw_status(status);
text += _text;
pEp_free(_text);
::pEp_free(_text);
return text;
}
}
@ -171,11 +179,10 @@ namespace pEp {
return msg;
}
void Transport::send(Message msg)
{
mkdir(outbox_path.c_str(), 0770);
}
};
};
}; // namespace Test
}; // namespace pEp

+ 7
- 6
test/framework.hh View File

@ -1,5 +1,6 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef LIBPEPADAPTER_FRAMEWORK_HH
#define LIBPEPADAPTER_FRAMEWORK_HH
@ -7,22 +8,22 @@
#include <vector>
#include <memory>
#include "Adapter.hh"
#include <pEp/message.h>
namespace pEp {
namespace Test {
using namespace std;
// manually set up test
void setup(vector<string>& args);
void setup(vector<string> &args);
// call this in main() for auto set up
void setup(int argc=1, char **argv=nullptr);
void setup(int argc = 1, char **argv = nullptr);
void import_key_from_file(string filename);
using Message = shared_ptr<::message>;
using Identity= shared_ptr<::pEp_identity>;
using Identity = shared_ptr<::pEp_identity>;
// use this instead of constructor to auto assign ::free_message as
// deleter
@ -57,7 +58,7 @@ namespace pEp {
extern Transport transport;
extern string path;
};
};
}; // namespace Test
}; // namespace pEp
#endif // LIBPEPADAPTER_FRAMEWORK_HH

+ 13
- 9
test/test_adapter.cc View File

@ -6,11 +6,15 @@
#include <assert.h>
#include <unistd.h>
#include <sys/param.h>
#include <pEpLog.hh>
#include <Adapter.hh>
#include <pEp/sync_api.h>
#include <pEp/keymanagement.h>
#include "pEpLog.hh"
#include <pEp/message_api.h>
using namespace std;
using namespace pEp::Adapter;
using namespace pEp;
PEP_STATUS messageToSend(struct _message *msg)
{