COM-29: Rework keysync as discussed on IRC yesterday. keysync
authorMarkus Schaber <markus@pep-security.net>
Mon, 03 Oct 2016 18:46:57 +0200
branchkeysync
changeset 169d776268c12a7
parent 168 269a3bacc5d7
child 170 fcee0c1b316e
COM-29: Rework keysync as discussed on IRC yesterday.
CpEpEngine.cpp
CpEpEngine.h
pEpCOMServerAdapter.idl
     1.1 --- a/CpEpEngine.cpp	Sun Oct 02 15:39:00 2016 +0200
     1.2 +++ b/CpEpEngine.cpp	Mon Oct 03 18:46:57 2016 +0200
     1.3 @@ -1289,47 +1289,48 @@
     1.4  
     1.5  // keysync api
     1.6  
     1.7 -std::mutex CpEpEngine::keysync_mutex;
     1.8 -std::condition_variable CpEpEngine::keysync_condition;
     1.9 -std::thread *CpEpEngine::keysync_thread = NULL;
    1.10 -std::queue<void*> CpEpEngine::keysync_queue;
    1.11 -bool CpEpEngine::keysync_thread_running = FALSE;
    1.12 -bool CpEpEngine::keysync_abort_requested = FALSE;
    1.13 -PEP_SESSION CpEpEngine::keysync_session;
    1.14 -
    1.15 -STDMETHODIMP CpEpEngine::start_keysync()
    1.16 +void CpEpEngine::start_keysync()
    1.17  {
    1.18  	// acquire the lock
    1.19  	std::unique_lock<std::mutex> lock(keysync_mutex);
    1.20  
    1.21  	// Check if we're already running.
    1.22 -	if (keysync_thread_running)
    1.23 -		return S_OK;
    1.24 +	if (keysync_thread_running) 
    1.25 +	{
    1.26 +		// If we have pending aborts, we need to wake up those threads
    1.27 +		// and cancel the pending abort.
    1.28 +		if (keysync_abort_requested) 
    1.29 +		{
    1.30 +			keysync_abort_requested = false;
    1.31 +			keysync_condition.notify_all();
    1.32 +		}
    1.33 +		return;
    1.34 +	}
    1.35  
    1.36 -	// Check if a concurrent abort was requested and is in progress
    1.37 -	if (keysync_abort_requested)
    1.38 -		return S_FALSE;
    1.39 +	// Ensure we are not aborting the new thread due to a
    1.40 +	// left over flag.
    1.41 +	keysync_abort_requested = false;
    1.42  
    1.43 +	// Init our keysync session
    1.44  	PEP_STATUS status = ::init(&keysync_session);
    1.45 +	::register_sync_callbacks(m_session, (void*)this, messageToSend, showHandshake, inject_sync_msg, retreive_next_sync_msg);
    1.46  	assert(status = PEP_STATUS_OK);
    1.47  
    1.48 -	// we pass the address of our mutex as management pointer, to do safety checks.
    1.49 -	keysync_thread = new thread(::do_sync_protocol, keysync_session, &keysync_mutex);
    1.50 +	// Star the keysync thread
    1.51 +	keysync_thread = new thread(::do_sync_protocol, keysync_session, this);
    1.52  
    1.53  	// flag to signal we're running
    1.54  	keysync_thread_running = true;
    1.55 -
    1.56 -	return S_OK;
    1.57  }
    1.58  
    1.59 -STDMETHODIMP CpEpEngine::stop_keysync()
    1.60 +void CpEpEngine::stop_keysync()
    1.61  {
    1.62  	// acquire the lock
    1.63  	std::unique_lock<std::mutex> lock(keysync_mutex);
    1.64  
    1.65 -	// check whether we're actually running, or there's a concurrent abort
    1.66 +	// check whether we're not running, or there's a concurrent abort
    1.67  	if (keysync_abort_requested || !keysync_thread_running)
    1.68 -		return S_OK;
    1.69 +		return;
    1.70  
    1.71  	// signal that we're gonna abort
    1.72  	keysync_abort_requested = true;
    1.73 @@ -1338,15 +1339,19 @@
    1.74  	keysync_condition.notify_all();
    1.75  
    1.76  	// Wait for the other thread to finish and clean up
    1.77 -	while (keysync_thread_running)
    1.78 +	while (keysync_thread_running && keysync_abort_requested)
    1.79  		keysync_condition.wait(lock);
    1.80  
    1.81 +	if (!keysync_abort_requested)
    1.82 +		return; // someone called start_keysync() while we were trying to stop it...
    1.83 +
    1.84  	// wait for the thread to end
    1.85  	keysync_thread->join();
    1.86  
    1.87  	// clean up
    1.88  	delete keysync_thread;
    1.89  	keysync_thread = NULL;
    1.90 +	::unregister_sync_callbacks(keysync_session);
    1.91  	release(keysync_session);
    1.92  	keysync_abort_requested = false;
    1.93  }
    1.94 @@ -1356,59 +1361,61 @@
    1.95  	// check argument
    1.96  	if (!msg)
    1.97  		return E_INVALIDARG;
    1.98 -
    1.99 -	// sanity check
   1.100 -	if (management != &keysync_mutex)
   1.101 +	if (!management)
   1.102  		return ERROR_INVALID_HANDLE;
   1.103  
   1.104 +	CpEpEngine* me = (CpEpEngine*)management;
   1.105 +
   1.106  	// acquire the lock
   1.107 -	std::unique_lock<std::mutex> lock(keysync_mutex);
   1.108 +	std::unique_lock<std::mutex> lock(me->keysync_mutex);
   1.109  
   1.110  	// check whether we're running:
   1.111 -	if (keysync_abort_requested || !keysync_thread_running)
   1.112 +	if (me->keysync_abort_requested || !me->keysync_thread_running)
   1.113  		return E_ASYNC_OPERATION_NOT_STARTED;
   1.114  
   1.115  	// queue the message
   1.116 -	keysync_queue.push(msg);
   1.117 +	me->keysync_queue.push(msg);
   1.118  
   1.119  	// notify the receivers
   1.120 -	keysync_condition.notify_all();
   1.121 +	me->keysync_condition.notify_all();
   1.122  }
   1.123  
   1.124  void * CpEpEngine::retreive_next_sync_msg(void * management)
   1.125  {
   1.126  	// sanity check
   1.127 -	assert(management == &keysync_mutex);
   1.128 +	assert(management);
   1.129 +
   1.130 +	CpEpEngine* me = (CpEpEngine*)management;
   1.131  
   1.132  	// acquire the lock
   1.133 -	std::unique_lock<std::mutex> lock(keysync_mutex);
   1.134 +	std::unique_lock<std::mutex> lock(me->keysync_mutex);
   1.135  
   1.136  	// as long as we're supposed to be active 
   1.137  	// (we won't wait for the queue to empty currently...)
   1.138 -	while (!keysync_abort_requested)
   1.139 +	while (!me->keysync_abort_requested)
   1.140  	{
   1.141  		// If the queue is empty, wait for a signal, and try again.
   1.142 -		if (keysync_queue.empty())
   1.143 +		if (me->keysync_queue.empty())
   1.144  		{
   1.145 -			keysync_condition.wait(lock);
   1.146 +			me->keysync_condition.wait(lock);
   1.147  			continue;
   1.148  		}
   1.149  
   1.150  		// Pop the message and return it.
   1.151 -		void* msg = keysync_queue.front();
   1.152 +		void* msg = me->keysync_queue.front();
   1.153  		assert(msg);
   1.154  
   1.155 -		keysync_queue.pop();
   1.156 -		
   1.157 +		me->keysync_queue.pop();
   1.158 +
   1.159  		return msg;
   1.160  	}
   1.161  
   1.162  	// we acknowledge that we're quitting...
   1.163 -	keysync_thread_running = false;
   1.164 +	me->keysync_thread_running = false;
   1.165  
   1.166  	// We signal the main thread that we got his signal
   1.167  	// so it can gain the mutex again and call join() on us.
   1.168 -	keysync_condition.notify_all();
   1.169 +	me->keysync_condition.notify_all();
   1.170  
   1.171  	// and tell the pep engine we're done.
   1.172  	return NULL;
   1.173 @@ -1424,6 +1431,7 @@
   1.174  
   1.175  	vec.push_back(new_callbacks);
   1.176  	new_callbacks->AddRef();
   1.177 +	start_keysync();
   1.178  
   1.179  	return S_OK;
   1.180  }
   1.181 @@ -1437,6 +1445,9 @@
   1.182  	if (position != vec.end()) {
   1.183  		vec.erase(position);
   1.184  		obsolete_callbacks->Release();
   1.185 +		if (vec.empty())
   1.186 +			stop_keysync();
   1.187 +
   1.188  		return S_OK;
   1.189  	}
   1.190  
     2.1 --- a/CpEpEngine.h	Sun Oct 02 15:39:00 2016 +0200
     2.2 +++ b/CpEpEngine.h	Mon Oct 03 18:46:57 2016 +0200
     2.3 @@ -44,6 +44,7 @@
     2.4  
     2.5      ~CpEpEngine()
     2.6      {
     2.7 +        stop_keysync();
     2.8          stop_keyserver_lookup();
     2.9          ::unregister_sync_callbacks(m_session);
    2.10          ::log_event(m_session, "Shutdown", "pEp COM Adapter", NULL, NULL);
    2.11 @@ -97,7 +98,7 @@
    2.12              me->session_mutex.unlock();
    2.13          }
    2.14  
    2.15 -        operator PEP_SESSION const () 
    2.16 +        operator PEP_SESSION const ()
    2.17          {
    2.18              return me->m_session;
    2.19          }
    2.20 @@ -141,8 +142,6 @@
    2.21      static PEP_STATUS messageToSend(void * obj, message *msg);
    2.22      static PEP_STATUS showHandshake(void * obj, pEp_identity *self, pEp_identity *partner);
    2.23  
    2.24 -	static int inject_sync_msg(void *msg, void* management);
    2.25 -	static void* retreive_next_sync_msg(void* management);
    2.26  
    2.27      HRESULT error(_bstr_t msg);
    2.28  
    2.29 @@ -166,19 +165,24 @@
    2.30  	vector<IpEpEngineCallbacks*> callback_vector;
    2.31  
    2.32  	// Keysync members
    2.33 -	static std::mutex keysync_mutex;
    2.34 -	static std::condition_variable keysync_condition;
    2.35 -	static std::thread *keysync_thread;
    2.36 -	static std::queue<void*> keysync_queue;
    2.37 -	static bool keysync_thread_running;
    2.38 -	static bool keysync_abort_requested;
    2.39 -	static PEP_SESSION keysync_session;
    2.40 +    static int inject_sync_msg(void *msg, void* management);
    2.41 +    static void* retreive_next_sync_msg(void* management);
    2.42 +    void start_keysync();
    2.43 +    void stop_keysync();
    2.44 +
    2.45 +    std::mutex keysync_mutex;
    2.46 +    std::condition_variable keysync_condition;
    2.47 +    std::thread *keysync_thread = NULL;
    2.48 +    std::queue<void*> keysync_queue;
    2.49 +    bool keysync_thread_running = false;
    2.50 +    bool keysync_abort_requested = false;
    2.51 +    PEP_SESSION keysync_session;
    2.52  
    2.53  public:
    2.54      // runtime config of the adapter
    2.55  
    2.56      STDMETHOD(verbose_logging)(VARIANT_BOOL enable);
    2.57 -    
    2.58 +
    2.59      // runtime config of the engine
    2.60  
    2.61      STDMETHOD(passive_mode)(VARIANT_BOOL enable);
    2.62 @@ -221,9 +225,6 @@
    2.63      STDMETHOD(key_reset_trust)(struct pEp_identity_s *ident);
    2.64      STDMETHOD(trust_personal_key)(struct pEp_identity_s *ident, struct pEp_identity_s *result);
    2.65  
    2.66 -	// keysync API
    2.67 -	STDMETHOD(start_keysync)();
    2.68 -	STDMETHOD(stop_keysync)();
    2.69  
    2.70      // Blacklist API
    2.71  
    2.72 @@ -244,7 +245,7 @@
    2.73  
    2.74  	STDMETHOD(register_callbacks)(IpEpEngineCallbacks *new_callback);
    2.75  	STDMETHOD(unregister_callbacks)(IpEpEngineCallbacks *obsolete_callback);
    2.76 -    
    2.77 +
    2.78      // PGP compatibility functions
    2.79      STDMETHOD(OpenPGP_list_keyinfo)(BSTR search_pattern, LPSAFEARRAY* keyinfo_list);
    2.80  
     3.1 --- a/pEpCOMServerAdapter.idl	Sun Oct 02 15:39:00 2016 +0200
     3.2 +++ b/pEpCOMServerAdapter.idl	Mon Oct 03 18:46:57 2016 +0200
     3.3 @@ -190,8 +190,6 @@
     3.4  
     3.5      HRESULT start_keyserver_lookup();
     3.6      HRESULT stop_keyserver_lookup();
     3.7 -	HRESULT start_keysync();
     3.8 -	HRESULT stop_keysync();
     3.9  
    3.10      HRESULT examine_identity([in] struct pEp_identity_s * ident);
    3.11      HRESULT myself([in] struct pEp_identity_s *ident, [out, retval] struct pEp_identity_s *result);