
14 changed files with 313 additions and 347 deletions
@ -0,0 +1,96 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "user_interface.hh" |
||||
|
#include <assert.h> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
Adapter::Adapter() |
||||
|
{ |
||||
|
session(init); |
||||
|
} |
||||
|
|
||||
|
Adapter::~Adapter() |
||||
|
{ |
||||
|
session(release); |
||||
|
} |
||||
|
|
||||
|
PEP_SESSION Adapter::session(session_action action) |
||||
|
{ |
||||
|
lock_guard<mutex> lock(mtx); |
||||
|
|
||||
|
thread_local static PEP_SESSION _session = nullptr; |
||||
|
thread_local int booked = 0; |
||||
|
PEP_STATUS status = PEP_STATUS_OK; |
||||
|
|
||||
|
switch (action) { |
||||
|
case release: |
||||
|
if (booked) |
||||
|
--booked; |
||||
|
if (!booked && _session) { |
||||
|
::release(_session); |
||||
|
_session = nullptr; |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case none: |
||||
|
if (_session) |
||||
|
break; |
||||
|
|
||||
|
case init: |
||||
|
++booked; |
||||
|
if (!_session) |
||||
|
status = ::init(&_session, _messageToSend, _inject_sync_event); |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
status = PEP_ILLEGAL_VALUE; |
||||
|
} |
||||
|
|
||||
|
if (status) |
||||
|
_throw_status(status); |
||||
|
|
||||
|
return _session; |
||||
|
} |
||||
|
|
||||
|
PyObject *Adapter::ui_object(PyObject *value) |
||||
|
{ |
||||
|
lock_guard<mutex> lock(mtx); |
||||
|
static PyObject *obj = nullptr; |
||||
|
if (value) |
||||
|
obj = value; |
||||
|
return obj; |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS Adapter::_messageToSend(struct _message *msg) |
||||
|
{ |
||||
|
if (!msg) |
||||
|
return PEP_ILLEGAL_VALUE; |
||||
|
|
||||
|
adapter.messageToSend(Message(msg)); |
||||
|
return PEP_STATUS_OK; |
||||
|
} |
||||
|
|
||||
|
int Adapter::_inject_sync_event(SYNC_EVENT ev, void *management) |
||||
|
{ |
||||
|
if (is_sync_thread(adapter.session())) { |
||||
|
PEP_STATUS status = do_sync_protocol_step(adapter.session(), adapter.ui_object(), ev); |
||||
|
return status == PEP_STATUS_OK ? 0 : 1; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
q.push_front(ev); |
||||
|
} |
||||
|
catch (exception&) { |
||||
|
return 1; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void Adapter_callback::messageToSend(Message msg) { |
||||
|
call_method< void >(_self, "messageToSend", msg); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,62 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include "pEpmodule.hh" |
||||
|
#include "locked_queue.hh" |
||||
|
#include "user_interface.hh" |
||||
|
#include <pEp/sync_api.h> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
using Message = pEp::PythonAdapter::Message; |
||||
|
|
||||
|
class Adapter { |
||||
|
public: |
||||
|
Adapter(); |
||||
|
virtual ~Adapter(); |
||||
|
|
||||
|
virtual void messageToSend(Message msg) { |
||||
|
throw runtime_error("override this method"); |
||||
|
} |
||||
|
|
||||
|
enum session_action { |
||||
|
none = 0, |
||||
|
init, |
||||
|
release |
||||
|
}; |
||||
|
|
||||
|
PEP_SESSION session(session_action action = none); |
||||
|
static ::utility::locked_queue< SYNC_EVENT > q; |
||||
|
|
||||
|
protected: |
||||
|
static PyObject *ui_object(PyObject *value = nullptr); |
||||
|
static PEP_STATUS _messageToSend(struct _message *msg); |
||||
|
static int _inject_sync_event(SYNC_EVENT ev, void *management); |
||||
|
|
||||
|
private: |
||||
|
static mutex mtx; |
||||
|
|
||||
|
// non copyable
|
||||
|
Adapter(const Adapter&) = delete; |
||||
|
Adapter& operator= (const Adapter&) = delete; |
||||
|
|
||||
|
friend class UserInterface_callback; |
||||
|
}; |
||||
|
|
||||
|
class Adapter_callback : public Adapter { |
||||
|
PyObject *_self; |
||||
|
public: |
||||
|
Adapter_callback(PyObject *self) : _self(self) { } |
||||
|
~Adapter_callback() { } |
||||
|
|
||||
|
void messageToSend(Message msg); |
||||
|
|
||||
|
// non copyable
|
||||
|
Adapter_callback(const Adapter_callback&) = delete; |
||||
|
Adapter_callback& operator= (const Adapter_callback&) = delete; |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
@ -1,186 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#include "sync_mixin.hh" |
|
||||
#ifndef NDEBUG |
|
||||
#include <pEp/KeySync_fsm.h> |
|
||||
#endif |
|
||||
#include <assert.h> |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
SyncMixIn_callback::SyncMixIn_callback(PyObject *self) : _self(self) |
|
||||
{ |
|
||||
PEP_STATUS status = register_sync_callbacks(session, (void *) this, |
|
||||
_messageToSend, _notifyHandshake, inject_sync_msg, |
|
||||
retrieve_next_sync_msg); |
|
||||
assert(status == PEP_STATUS_OK); |
|
||||
} |
|
||||
|
|
||||
SyncMixIn_callback::~SyncMixIn_callback() |
|
||||
{ |
|
||||
unregister_sync_callbacks(session); |
|
||||
} |
|
||||
|
|
||||
PEP_STATUS SyncMixIn::_messageToSend(void *obj, message *msg) |
|
||||
{ |
|
||||
if (!obj) |
|
||||
return PEP_SEND_FUNCTION_NOT_REGISTERED; |
|
||||
|
|
||||
if (!msg) |
|
||||
return PEP_ILLEGAL_VALUE; |
|
||||
|
|
||||
auto that = dynamic_cast< SyncMixIn_callback * >( |
|
||||
static_cast< SyncMixIn * > (obj)); |
|
||||
that->messageToSend(Message(msg)); |
|
||||
|
|
||||
return PEP_STATUS_OK; |
|
||||
} |
|
||||
|
|
||||
PEP_STATUS SyncMixIn::_notifyHandshake(void *obj, |
|
||||
pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal) |
|
||||
{ |
|
||||
if (!obj) |
|
||||
return PEP_SEND_FUNCTION_NOT_REGISTERED; |
|
||||
|
|
||||
if (!(me && partner)) |
|
||||
return PEP_ILLEGAL_VALUE; |
|
||||
|
|
||||
auto that = dynamic_cast< SyncMixIn_callback * >( |
|
||||
static_cast< SyncMixIn * > (obj)); |
|
||||
that->notifyHandshake(Identity(me), Identity(partner), signal); |
|
||||
|
|
||||
return PEP_STATUS_OK; |
|
||||
} |
|
||||
|
|
||||
void SyncMixIn::deliverHandshakeResult(Identity partner, int result) |
|
||||
{ |
|
||||
PEP_STATUS status = ::deliverHandshakeResult(session, partner, |
|
||||
(sync_handshake_result) result); |
|
||||
_throw_status(status); |
|
||||
} |
|
||||
|
|
||||
#ifndef NDEBUG |
|
||||
void SyncMixIn::_inject(int event, Identity partner, object extra) |
|
||||
{ |
|
||||
time_t timeout = 0; |
|
||||
PEP_STATUS status = fsm_DeviceState_inject(session, |
|
||||
(DeviceState_event) event, partner, NULL, &timeout); |
|
||||
_throw_status(status); |
|
||||
} |
|
||||
#endif |
|
||||
|
|
||||
jmp_buf SyncMixIn::env; |
|
||||
void *SyncMixIn::_msg; |
|
||||
|
|
||||
timeout_state_t SyncMixIn::timeout_state = timeout_stopped; |
|
||||
bool SyncMixIn::last_turn = false; |
|
||||
time_t SyncMixIn::remaining_time = 0; |
|
||||
|
|
||||
int SyncMixIn::inject_sync_msg(void *msg, void *management) |
|
||||
{ |
|
||||
assert(timeout_state != timeout_canceling); |
|
||||
if(timeout_state == timeout_canceling) return 0; |
|
||||
|
|
||||
assert(timeout_state != timeout_expiring); |
|
||||
if(timeout_state == timeout_expiring) return 0; |
|
||||
|
|
||||
_msg = msg; |
|
||||
int val = setjmp(env); |
|
||||
if (!val){ |
|
||||
if(timeout_state == timeout_running){ |
|
||||
// call python timeout timer cancel
|
|
||||
auto that = dynamic_cast< SyncMixIn_callback * >( |
|
||||
static_cast< SyncMixIn * > (management)); |
|
||||
remaining_time = that->cancelTimeout(); |
|
||||
timeout_state = timeout_canceling; |
|
||||
} |
|
||||
last_turn = false; |
|
||||
do_sync_protocol(session, management); |
|
||||
} |
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
void *SyncMixIn::retrieve_next_sync_msg(void *management, time_t *timeout) |
|
||||
{ |
|
||||
if (!last_turn){ |
|
||||
|
|
||||
assert(timeout_state != timeout_running); |
|
||||
if(timeout_state == timeout_running) return NULL; |
|
||||
|
|
||||
switch(timeout_state){ |
|
||||
case timeout_canceling : |
|
||||
*timeout = remaining_time; |
|
||||
break; |
|
||||
case timeout_expiring : |
|
||||
// "1" is arbitrary value !=0, since we don't
|
|
||||
// have original timeout value anymore
|
|
||||
*timeout = 1; |
|
||||
break; |
|
||||
default: |
|
||||
; |
|
||||
} |
|
||||
|
|
||||
timeout_state = timeout_stopped; |
|
||||
|
|
||||
last_turn = true; |
|
||||
return (void *) _msg; |
|
||||
|
|
||||
} else { |
|
||||
|
|
||||
assert(timeout_state == timeout_stopped); |
|
||||
if(timeout_state != timeout_stopped) return NULL; |
|
||||
|
|
||||
if (*timeout != 0) { |
|
||||
// call python timeout timer start
|
|
||||
auto that = dynamic_cast< SyncMixIn_callback * >( |
|
||||
static_cast< SyncMixIn * > (management)); |
|
||||
that->setTimeout(*timeout); |
|
||||
timeout_state = timeout_running; |
|
||||
} |
|
||||
} |
|
||||
longjmp(env, 1); |
|
||||
return (void *) 23; |
|
||||
} |
|
||||
|
|
||||
// to be called from python timeout timer - may GIL protect us
|
|
||||
void SyncMixIn::onTimeout(){ |
|
||||
assert(timeout_state != timeout_canceling); |
|
||||
if(timeout_state == timeout_canceling) return; |
|
||||
|
|
||||
assert(timeout_state != timeout_expiring); |
|
||||
if(timeout_state == timeout_expiring) return; |
|
||||
|
|
||||
_msg = NULL; |
|
||||
int val = setjmp(env); |
|
||||
if (!val){ |
|
||||
timeout_state = timeout_expiring; |
|
||||
|
|
||||
last_turn = false; |
|
||||
do_sync_protocol(session, (void*)this); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void SyncMixIn_callback::messageToSend(Message msg) |
|
||||
{ |
|
||||
call_method< void >(_self, "messageToSend", msg); |
|
||||
} |
|
||||
|
|
||||
void SyncMixIn_callback::notifyHandshake( |
|
||||
Identity me, Identity partner, sync_handshake_signal signal) |
|
||||
{ |
|
||||
call_method< void >(_self, "notifyHandshake", me, partner, signal); |
|
||||
} |
|
||||
|
|
||||
void SyncMixIn_callback::setTimeout(time_t timeout) |
|
||||
{ |
|
||||
call_method< void >(_self, "setTimeout", timeout); |
|
||||
} |
|
||||
|
|
||||
time_t SyncMixIn_callback::cancelTimeout() |
|
||||
{ |
|
||||
return call_method< time_t >(_self, "cancelTimeout"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
@ -1,86 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#pragma once |
|
||||
|
|
||||
#include "pEpmodule.hh" |
|
||||
#include <setjmp.h> |
|
||||
#include <pEp/sync_api.h> |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
|
|
||||
typedef enum _timeout_state_t { |
|
||||
timeout_stopped, |
|
||||
timeout_running, |
|
||||
timeout_canceling, |
|
||||
timeout_expiring |
|
||||
} timeout_state_t; |
|
||||
|
|
||||
class SyncMixIn { |
|
||||
public: |
|
||||
SyncMixIn() { } |
|
||||
virtual ~SyncMixIn() { } |
|
||||
|
|
||||
virtual void messageToSend(Message msg) { |
|
||||
throw runtime_error("override this method"); |
|
||||
} |
|
||||
|
|
||||
virtual void notifyHandshake( |
|
||||
pEp::PythonAdapter::Identity me, |
|
||||
pEp::PythonAdapter::Identity partner, |
|
||||
sync_handshake_signal signal) |
|
||||
{ |
|
||||
throw runtime_error("override this method"); |
|
||||
} |
|
||||
|
|
||||
virtual void deliverHandshakeResult( |
|
||||
pEp::PythonAdapter::Identity partner, int result); |
|
||||
#ifndef NDEBUG |
|
||||
virtual void _inject( |
|
||||
int event, |
|
||||
pEp::PythonAdapter::Identity partner, object extra); |
|
||||
#endif |
|
||||
virtual void setTimeout(time_t timeout){ |
|
||||
throw runtime_error("override this method"); |
|
||||
} |
|
||||
|
|
||||
virtual time_t cancelTimeout(){ |
|
||||
throw runtime_error("override this method"); |
|
||||
} |
|
||||
|
|
||||
virtual void onTimeout(); |
|
||||
|
|
||||
protected: |
|
||||
static PEP_STATUS _messageToSend(void *obj, message *msg); |
|
||||
static PEP_STATUS _notifyHandshake(void *obj, |
|
||||
pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal); |
|
||||
|
|
||||
static jmp_buf env; |
|
||||
static void *_msg; |
|
||||
static timeout_state_t timeout_state; |
|
||||
static bool last_turn; |
|
||||
static time_t remaining_time; |
|
||||
static int inject_sync_msg(void *msg, void *management); |
|
||||
static void *retrieve_next_sync_msg(void *management, time_t *timeout); |
|
||||
}; |
|
||||
|
|
||||
class SyncMixIn_callback : public SyncMixIn { |
|
||||
PyObject* const _self; |
|
||||
|
|
||||
public: |
|
||||
SyncMixIn_callback(PyObject *self); |
|
||||
~SyncMixIn_callback(); |
|
||||
|
|
||||
void messageToSend(Message msg); |
|
||||
void notifyHandshake( |
|
||||
pEp::PythonAdapter::Identity me, |
|
||||
pEp::PythonAdapter::Identity partner, |
|
||||
sync_handshake_signal signal); |
|
||||
|
|
||||
void setTimeout(time_t timeout); |
|
||||
time_t cancelTimeout(); |
|
||||
}; |
|
||||
} |
|
||||
} |
|
||||
|
|
@ -0,0 +1,66 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "user_interface.hh" |
||||
|
#include <assert.h> |
||||
|
#include <time.h> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
UserInterface_callback::UserInterface_callback(PyObject *self) : |
||||
|
_self(self) |
||||
|
{ |
||||
|
adapter.ui_object(self); |
||||
|
PEP_STATUS status = ::register_sync_callbacks(adapter.session(), |
||||
|
(void *) this, _notifyHandshake, retrieve_next_sync_event); |
||||
|
assert(status == PEP_STATUS_OK); |
||||
|
if (status) |
||||
|
_throw_status(status); |
||||
|
} |
||||
|
|
||||
|
UserInterface_callback::~UserInterface_callback() |
||||
|
{ |
||||
|
::unregister_sync_callbacks(adapter.session()); |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS UserInterface::_notifyHandshake(void *obj, |
||||
|
pEp_identity *me, pEp_identity *partner, |
||||
|
sync_handshake_signal signal |
||||
|
) |
||||
|
{ |
||||
|
if (!obj) |
||||
|
return PEP_SEND_FUNCTION_NOT_REGISTERED; |
||||
|
|
||||
|
if (!(me && partner)) |
||||
|
return PEP_ILLEGAL_VALUE; |
||||
|
|
||||
|
auto that = dynamic_cast< UserInterface_callback * >( |
||||
|
static_cast< UserInterface * > (obj)); |
||||
|
that->notifyHandshake(Identity(me), Identity(partner), signal); |
||||
|
|
||||
|
return PEP_STATUS_OK; |
||||
|
} |
||||
|
|
||||
|
void UserInterface::deliverHandshakeResult(Identity partner, |
||||
|
int result) |
||||
|
{ |
||||
|
PEP_STATUS status = ::deliverHandshakeResult(adapter.session(), |
||||
|
partner, (sync_handshake_result) result); |
||||
|
_throw_status(status); |
||||
|
} |
||||
|
|
||||
|
SYNC_EVENT UserInterface::retrieve_next_sync_event(void *management) |
||||
|
{ |
||||
|
while (adapter.q.empty()) |
||||
|
nanosleep((const struct timespec[]){{0, 100000000L}}, NULL); |
||||
|
return adapter.q.pop_front(); |
||||
|
} |
||||
|
|
||||
|
void UserInterface_callback::notifyHandshake( |
||||
|
Identity me, Identity partner, sync_handshake_signal signal) |
||||
|
{ |
||||
|
call_method< void >(_self, "notifyHandshake", me, partner, signal); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,48 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include "pEpmodule.hh" |
||||
|
#include <setjmp.h> |
||||
|
#include <pEp/sync_api.h> |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
class UserInterface { |
||||
|
public: |
||||
|
UserInterface() { } |
||||
|
virtual ~UserInterface() { } |
||||
|
|
||||
|
virtual void notifyHandshake( |
||||
|
pEp::PythonAdapter::Identity me, |
||||
|
pEp::PythonAdapter::Identity partner, |
||||
|
sync_handshake_signal signal) |
||||
|
{ |
||||
|
throw runtime_error("override this method"); |
||||
|
} |
||||
|
|
||||
|
virtual void deliverHandshakeResult( |
||||
|
pEp::PythonAdapter::Identity partner, int result); |
||||
|
|
||||
|
protected: |
||||
|
static PEP_STATUS _notifyHandshake(void *obj, pEp_identity *me, |
||||
|
pEp_identity *partner, sync_handshake_signal signal); |
||||
|
static SYNC_EVENT retrieve_next_sync_event( void *management); |
||||
|
}; |
||||
|
|
||||
|
class UserInterface_callback : public UserInterface { |
||||
|
PyObject *_self; |
||||
|
|
||||
|
public: |
||||
|
UserInterface_callback(PyObject *self); |
||||
|
~UserInterface_callback(); |
||||
|
|
||||
|
void notifyHandshake( |
||||
|
pEp::PythonAdapter::Identity me, |
||||
|
pEp::PythonAdapter::Identity partner, |
||||
|
sync_handshake_signal signal); |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
Loading…
Reference in new issue