|
|
@ -7,142 +7,150 @@ |
|
|
|
#include <assert.h> |
|
|
|
|
|
|
|
namespace pEp { |
|
|
|
using namespace std; |
|
|
|
|
|
|
|
void throw_status(PEP_STATUS status) |
|
|
|
{ |
|
|
|
if (status == PEP_STATUS_OK) |
|
|
|
return; |
|
|
|
if (status >= 0x400 && status <= 0x4ff) |
|
|
|
return; |
|
|
|
if (status == PEP_OUT_OF_MEMORY) |
|
|
|
throw bad_alloc(); |
|
|
|
if (status == PEP_ILLEGAL_VALUE) |
|
|
|
throw invalid_argument("illegal value"); |
|
|
|
|
|
|
|
stringstream build; |
|
|
|
build << setfill('0') << "p≡p 0x" << setw(4) << hex << status; |
|
|
|
throw runtime_error(build.str()); |
|
|
|
} |
|
|
|
|
|
|
|
messageToSend_t Adapter::_messageToSend = nullptr; |
|
|
|
notifyHandshake_t Adapter::_notifyHandshake = nullptr; |
|
|
|
std::thread *Adapter::_sync_thread = nullptr; |
|
|
|
|
|
|
|
Adapter::Adapter(messageToSend_t messageToSend, |
|
|
|
notifyHandshake_t notifyHandshake, void *obj) |
|
|
|
{ |
|
|
|
startup(messageToSend, notifyHandshake, obj); |
|
|
|
} |
|
|
|
|
|
|
|
void Adapter::startup(messageToSend_t messageToSend, |
|
|
|
notifyHandshake_t notifyHandshake, void *obj) |
|
|
|
{ |
|
|
|
if (messageToSend) |
|
|
|
_messageToSend = messageToSend; |
|
|
|
namespace Adapter { |
|
|
|
using namespace std; |
|
|
|
|
|
|
|
if (notifyHandshake) |
|
|
|
_notifyHandshake = notifyHandshake; |
|
|
|
static messageToSend_t _messageToSend = nullptr; |
|
|
|
static notifyHandshake_t _notifyHandshake = nullptr; |
|
|
|
static std::thread *_sync_thread = nullptr; |
|
|
|
|
|
|
|
session(); |
|
|
|
static ::utility::locked_queue< SYNC_EVENT >& queue() |
|
|
|
{ |
|
|
|
static ::utility::locked_queue< SYNC_EVENT > q; |
|
|
|
return q; |
|
|
|
} |
|
|
|
|
|
|
|
static std::mutex& mtx() |
|
|
|
{ |
|
|
|
lock_guard<mutex> lock(mtx()); |
|
|
|
static std::mutex m; |
|
|
|
return m; |
|
|
|
} |
|
|
|
|
|
|
|
if (!Adapter::_sync_thread) |
|
|
|
Adapter::_sync_thread = new thread(sync_thread, obj); |
|
|
|
void throw_status(PEP_STATUS status) |
|
|
|
{ |
|
|
|
if (status == PEP_STATUS_OK) |
|
|
|
return; |
|
|
|
if (status >= 0x400 && status <= 0x4ff) |
|
|
|
return; |
|
|
|
if (status == PEP_OUT_OF_MEMORY) |
|
|
|
throw bad_alloc(); |
|
|
|
if (status == PEP_ILLEGAL_VALUE) |
|
|
|
throw invalid_argument("illegal value"); |
|
|
|
|
|
|
|
stringstream build; |
|
|
|
build << setfill('0') << "p≡p 0x" << setw(4) << hex << status; |
|
|
|
throw runtime_error(build.str()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
PEP_SESSION Adapter::session(session_action action) |
|
|
|
{ |
|
|
|
lock_guard<mutex> lock(mtx()); |
|
|
|
static int _inject_sync_event(SYNC_EVENT ev, void *management) |
|
|
|
{ |
|
|
|
if (is_sync_thread(session())) { |
|
|
|
PEP_STATUS status = do_sync_protocol_step(session(), nullptr, ev); |
|
|
|
return status == PEP_STATUS_OK ? 0 : 1; |
|
|
|
} |
|
|
|
|
|
|
|
thread_local static PEP_SESSION _session = nullptr; |
|
|
|
PEP_STATUS status = PEP_STATUS_OK; |
|
|
|
try { |
|
|
|
queue().push_front(ev); |
|
|
|
} |
|
|
|
catch (exception&) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
switch (action) { |
|
|
|
case release: |
|
|
|
if (_session) { |
|
|
|
::release(_session); |
|
|
|
_session = nullptr; |
|
|
|
static SYNC_EVENT _retrieve_next_sync_event(void *management, time_t threshold) |
|
|
|
{ |
|
|
|
time_t started = time(nullptr); |
|
|
|
bool timeout = false; |
|
|
|
|
|
|
|
while (queue().empty()) { |
|
|
|
int i = 0; |
|
|
|
++i; |
|
|
|
if (i > 10) { |
|
|
|
if (time(nullptr) > started + threshold) { |
|
|
|
timeout = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
i = 0; |
|
|
|
} |
|
|
|
break; |
|
|
|
nanosleep((const struct timespec[]){{0, 100000000L}}, NULL); |
|
|
|
} |
|
|
|
|
|
|
|
case init: |
|
|
|
if (!_session) |
|
|
|
status = ::init(&_session, _messageToSend, _inject_sync_event); |
|
|
|
break; |
|
|
|
if (timeout) |
|
|
|
return new_sync_timeout_event(); |
|
|
|
|
|
|
|
default: |
|
|
|
status = PEP_ILLEGAL_VALUE; |
|
|
|
return queue().pop_front(); |
|
|
|
} |
|
|
|
|
|
|
|
throw_status(status); |
|
|
|
return _session; |
|
|
|
} |
|
|
|
static void sync_thread(void *obj) |
|
|
|
{ |
|
|
|
PEP_STATUS status = register_sync_callbacks(session(), nullptr, |
|
|
|
_notifyHandshake, _retrieve_next_sync_event); |
|
|
|
throw_status(status); |
|
|
|
|
|
|
|
void Adapter::shutdown() |
|
|
|
{ |
|
|
|
if (Adapter::_sync_thread) { |
|
|
|
_inject_sync_event(nullptr, nullptr); |
|
|
|
Adapter::_sync_thread->join(); |
|
|
|
delete Adapter::_sync_thread; |
|
|
|
Adapter::_sync_thread = nullptr; |
|
|
|
} |
|
|
|
session(release); |
|
|
|
} |
|
|
|
do_sync_protocol(session(), obj); |
|
|
|
unregister_sync_callbacks(session()); |
|
|
|
|
|
|
|
int Adapter::_inject_sync_event(SYNC_EVENT ev, void *management) |
|
|
|
{ |
|
|
|
if (is_sync_thread(session())) { |
|
|
|
PEP_STATUS status = do_sync_protocol_step(session(), nullptr, ev); |
|
|
|
return status == PEP_STATUS_OK ? 0 : 1; |
|
|
|
session(release); |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
queue().push_front(ev); |
|
|
|
} |
|
|
|
catch (exception&) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
void startup(messageToSend_t messageToSend, |
|
|
|
notifyHandshake_t notifyHandshake, void *obj) |
|
|
|
{ |
|
|
|
if (messageToSend) |
|
|
|
_messageToSend = messageToSend; |
|
|
|
|
|
|
|
SYNC_EVENT Adapter::_retrieve_next_sync_event(void *management, time_t threshold) |
|
|
|
{ |
|
|
|
time_t started = time(nullptr); |
|
|
|
bool timeout = false; |
|
|
|
|
|
|
|
while (queue().empty()) { |
|
|
|
int i = 0; |
|
|
|
++i; |
|
|
|
if (i > 10) { |
|
|
|
if (time(nullptr) > started + threshold) { |
|
|
|
timeout = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
i = 0; |
|
|
|
if (notifyHandshake) |
|
|
|
_notifyHandshake = notifyHandshake; |
|
|
|
|
|
|
|
session(); |
|
|
|
|
|
|
|
{ |
|
|
|
lock_guard<mutex> lock(mtx()); |
|
|
|
|
|
|
|
if (!_sync_thread) |
|
|
|
_sync_thread = new thread(sync_thread, obj); |
|
|
|
} |
|
|
|
nanosleep((const struct timespec[]){{0, 100000000L}}, NULL); |
|
|
|
} |
|
|
|
|
|
|
|
if (timeout) |
|
|
|
return new_sync_timeout_event(); |
|
|
|
PEP_SESSION session(session_action action) |
|
|
|
{ |
|
|
|
lock_guard<mutex> lock(mtx()); |
|
|
|
|
|
|
|
return queue().pop_front(); |
|
|
|
} |
|
|
|
thread_local static PEP_SESSION _session = nullptr; |
|
|
|
PEP_STATUS status = PEP_STATUS_OK; |
|
|
|
|
|
|
|
switch (action) { |
|
|
|
case release: |
|
|
|
if (_session) { |
|
|
|
::release(_session); |
|
|
|
_session = nullptr; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case init: |
|
|
|
if (!_session) |
|
|
|
status = ::init(&_session, _messageToSend, _inject_sync_event); |
|
|
|
break; |
|
|
|
|
|
|
|
void Adapter::sync_thread(void *obj) |
|
|
|
{ |
|
|
|
PEP_STATUS status = register_sync_callbacks(session(), nullptr, |
|
|
|
_notifyHandshake, _retrieve_next_sync_event); |
|
|
|
throw_status(status); |
|
|
|
default: |
|
|
|
status = PEP_ILLEGAL_VALUE; |
|
|
|
} |
|
|
|
|
|
|
|
do_sync_protocol(session(), obj); |
|
|
|
unregister_sync_callbacks(session()); |
|
|
|
throw_status(status); |
|
|
|
return _session; |
|
|
|
} |
|
|
|
|
|
|
|
session(release); |
|
|
|
void shutdown() |
|
|
|
{ |
|
|
|
if (_sync_thread) { |
|
|
|
_inject_sync_event(nullptr, nullptr); |
|
|
|
_sync_thread->join(); |
|
|
|
delete _sync_thread; |
|
|
|
_sync_thread = nullptr; |
|
|
|
} |
|
|
|
session(release); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|