COM-48 Implement timeout, and signal the app to poll inbox faster when waiting
authorMarkus Schaber <markus@pep-security.net>
Wed, 01 Feb 2017 21:37:07 +0100
changeset 2324c6d44bed519
parent 231 fbe8c644918f
child 233 27848ed0067c
COM-48 Implement timeout, and signal the app to poll inbox faster when waiting
on KeySync queue with a timeout.

First implementation draft.
CpEpEngine.cpp
CpEpEngine.h
pEpCOMServerAdapter.idl
     1.1 --- a/CpEpEngine.cpp	Mon Jan 23 16:51:15 2017 +0100
     1.2 +++ b/CpEpEngine.cpp	Wed Feb 01 21:37:07 2017 +0100
     1.3 @@ -227,6 +227,90 @@
     1.4      return result;
     1.5  }
     1.6  
     1.7 +STDMETHODIMP CpEpEngine::GetMessageTrustwords(
     1.8 +    /* [in] */ struct TextMessage *msg,
     1.9 +    /* [in] */ struct pEpIdentity *receivedBy,
    1.10 +    /* [in] */ SAFEARRAY *keylist,
    1.11 +    /* [defaultvalue][in] */ BSTR lang,
    1.12 +    /* [defaultvalue][in] */ VARIANT_BOOL full,
    1.13 +    /* [retval][out] */ BSTR *words) {
    1.14 +    assert(msg);
    1.15 +    assert(receivedBy);
    1.16 +    assert(words);
    1.17 +
    1.18 +    if (!(msg && receivedBy && words))
    1.19 +    {
    1.20 +        return E_INVALIDARG;
    1.21 +    }
    1.22 +
    1.23 +    HRESULT result = S_OK;
    1.24 +
    1.25 +    pEp_identity * _received_by = NULL;
    1.26 +    ::message * _msg = NULL;
    1.27 +    ::stringlist_t *_keylist = NULL;
    1.28 +    string _lang;
    1.29 +    *words = NULL;
    1.30 +
    1.31 +    try {
    1.32 +        _received_by = new_identity(receivedBy);
    1.33 +        _msg = text_message_to_C(msg);
    1.34 +
    1.35 +        if (keylist) {
    1.36 +            _keylist = new_stringlist(keylist);
    1.37 +        }
    1.38 +
    1.39 +        if (lang) {
    1.40 +            _lang = utf8_string(lang);
    1.41 +            if (_lang.length() == 0) {
    1.42 +                _lang = "en";
    1.43 +            }
    1.44 +            else if (_lang.length() != 2) {
    1.45 +                result = E_INVALIDARG;
    1.46 +            }
    1.47 +        }
    1.48 +        else {
    1.49 +            _lang = "en";
    1.50 +        }
    1.51 +    }
    1.52 +    catch (bad_alloc&) {
    1.53 +        result = E_OUTOFMEMORY;
    1.54 +    }
    1.55 +    catch (exception& ex) {
    1.56 +        result = FAIL(ex.what());
    1.57 +    }
    1.58 +
    1.59 +    char* _words = NULL;
    1.60 +    if (result == S_OK) {
    1.61 +        auto status = ::get_message_trustwords(
    1.62 +            get_session(),
    1.63 +            _msg,
    1.64 +            _keylist,
    1.65 +            _received_by,
    1.66 +            _lang.c_str(),
    1.67 +            &_words,
    1.68 +            full != 0 /* convert variant bool to C bool */);
    1.69 +
    1.70 +        if (status == PEP_OUT_OF_MEMORY) {
    1.71 +            result = E_OUTOFMEMORY;
    1.72 +        }
    1.73 +        else if (status == PEP_TRUSTWORD_NOT_FOUND) {
    1.74 +            result = FAIL(L"GetTrustwords: Trustword not found", status);
    1.75 +        }
    1.76 +        else if (!words) {
    1.77 +            result = FAIL(L"GetTrustwords: _words == NULL", status);
    1.78 +        }
    1.79 +        else {
    1.80 +            *words = utf16_bstr(_words);
    1.81 +        }
    1.82 +    }
    1.83 +
    1.84 +    ::pEp_free(_words);
    1.85 +    ::free_message(_msg);
    1.86 +    ::free_stringlist(_keylist);
    1.87 +    ::free_identity(_received_by);
    1.88 +
    1.89 +    return result;
    1.90 +}
    1.91  
    1.92  STDMETHODIMP CpEpEngine::GetCrashdumpLog(LONG maxlines, BSTR * log)
    1.93  {
    1.94 @@ -1044,14 +1128,24 @@
    1.95      res = CoGetInterfaceAndReleaseStream(marshaled_callbacks, IID_IpEpEngineCallbacks, &vp);
    1.96      assert(SUCCEEDED(res));
    1.97  
    1.98 +    self->client_last_signalled_polling_state = false;
    1.99      self->client_callbacks_on_sync_thread = static_cast<IpEpEngineCallbacks*>(vp);
   1.100  
   1.101 +    res = self->client_callbacks_on_sync_thread->QueryInterface(
   1.102 +        &self->client_callbacks2_on_sync_thread);
   1.103 +    if (res != S_OK)
   1.104 +        self->client_callbacks2_on_sync_thread = NULL;
   1.105 +
   1.106      ::do_sync_protocol(self->keysync_session, self);
   1.107  
   1.108      self->client_callbacks_on_sync_thread->Release();
   1.109  
   1.110      self->client_callbacks_on_sync_thread = NULL;
   1.111  
   1.112 +    if (self->client_callbacks2_on_sync_thread)
   1.113 +        self->client_callbacks2_on_sync_thread->Release();
   1.114 +    self->client_callbacks2_on_sync_thread = NULL;
   1.115 +
   1.116      CoUninitialize();
   1.117  }
   1.118  
   1.119 @@ -1120,43 +1214,75 @@
   1.120  {
   1.121  	// sanity check
   1.122  	assert(management);
   1.123 -	if (!management)
   1.124 +	if (!(management))
   1.125  		return NULL;
   1.126  
   1.127  	CpEpEngine* me = (CpEpEngine*)management;
   1.128  
   1.129 +    if ((timeout && *timeout)
   1.130 +        && me->client_callbacks2_on_sync_thread
   1.131 +        && me->client_last_signalled_polling_state == false)
   1.132 +    {
   1.133 +        me->client_callbacks2_on_sync_thread->NeedFastPolling(VARIANT_TRUE);
   1.134 +        me->client_last_signalled_polling_state == true;
   1.135 +    }
   1.136 +    else if (!(timeout && *timeout)
   1.137 +        && me->client_callbacks2_on_sync_thread
   1.138 +        && me->client_last_signalled_polling_state == true)
   1.139 +    {
   1.140 +        me->client_callbacks2_on_sync_thread->NeedFastPolling(VARIANT_FALSE);
   1.141 +        me->client_last_signalled_polling_state == false;
   1.142 +    }
   1.143 +
   1.144  	// acquire the lock
   1.145  	std::unique_lock<std::mutex> lock(me->keysync_mutex);
   1.146 +    
   1.147 +    if (timeout && *timeout) {
   1.148 +        auto end_time = std::chrono::steady_clock::now()
   1.149 +            + std::chrono::seconds(*timeout);
   1.150  
   1.151 -	// as long as we're supposed to be active 
   1.152 -	// (we won't wait for the queue to empty currently...)
   1.153 -	while (!me->keysync_abort_requested)
   1.154 -	{
   1.155 -		// If the queue is empty, wait for a signal, and try again.
   1.156 -		if (me->keysync_queue.empty())
   1.157 -		{
   1.158 -			me->keysync_condition.wait(lock);
   1.159 -			continue;
   1.160 -		}
   1.161 +        while (me->keysync_queue.empty() && !me->keysync_abort_requested)
   1.162 +        {
   1.163 +            auto status = me->keysync_condition.wait_until(lock, end_time);
   1.164  
   1.165 -		// Pop the message and return it.
   1.166 -		void* msg = me->keysync_queue.front();
   1.167 -		assert(msg);
   1.168 +            if (status == std::cv_status::timeout)
   1.169 +            {
   1.170 +                *timeout = 1; // Signal timeout
   1.171 +                return NULL;
   1.172 +            }            
   1.173 +        }
   1.174 +    }
   1.175 +    else 
   1.176 +    {
   1.177 +        while (me->keysync_queue.empty() && !me->keysync_abort_requested)
   1.178 +        {
   1.179 +            me->keysync_condition.wait(lock);
   1.180 +        }
   1.181 +    }
   1.182  
   1.183 -		me->keysync_queue.pop();
   1.184 +    if (me->keysync_abort_requested) {
   1.185 +        // we acknowledge that we're quitting...
   1.186 +        me->keysync_abort_requested = false;
   1.187  
   1.188 -		return msg;
   1.189 -	}
   1.190 +        // We signal the main thread that we got his signal
   1.191 +        // so it can gain the mutex again and call join() on us.
   1.192 +        me->keysync_condition.notify_all();
   1.193  
   1.194 -	// we acknowledge that we're quitting...
   1.195 -	me->keysync_abort_requested = false;
   1.196 +        // and tell the pep engine we're done.
   1.197 +        if (timeout)
   1.198 +            *timeout = 0; // signal for termination.
   1.199 +        return NULL;
   1.200 +    }
   1.201  
   1.202 -	// We signal the main thread that we got his signal
   1.203 -	// so it can gain the mutex again and call join() on us.
   1.204 -	me->keysync_condition.notify_all();
   1.205 +    assert(!me->keysync_queue.empty());	
   1.206  
   1.207 -	// and tell the pep engine we're done.
   1.208 -	return NULL;
   1.209 +	// Pop the message and return it.
   1.210 +	void* msg = me->keysync_queue.front();
   1.211 +	assert(msg);
   1.212 +
   1.213 +	me->keysync_queue.pop();
   1.214 +
   1.215 +	return msg;
   1.216  }
   1.217  
   1.218  
     2.1 --- a/CpEpEngine.h	Mon Jan 23 16:51:15 2017 +0100
     2.2 +++ b/CpEpEngine.h	Wed Feb 01 21:37:07 2017 +0100
     2.3 @@ -24,7 +24,7 @@
     2.4      public CComObjectRootEx<CComObjectThreadModel>,
     2.5  	public CComCoClass<CpEpEngine, &CLSID_pEpEngine>,
     2.6  	public ISupportErrorInfo,
     2.7 -	public IpEpEngine
     2.8 +	public IpEpEngine2
     2.9  {
    2.10  protected:
    2.11      static int examine_identity(pEp_identity *ident, void *management);
    2.12 @@ -127,6 +127,8 @@
    2.13  
    2.14  	IpEpEngineCallbacks* client_callbacks = NULL;
    2.15      IpEpEngineCallbacks* client_callbacks_on_sync_thread = NULL;
    2.16 +    IpEpEngineCallbacks2* client_callbacks2_on_sync_thread = NULL;
    2.17 +    bool client_last_signalled_polling_state = true;
    2.18  
    2.19  	// Keysync members
    2.20      static int inject_sync_msg(void *msg, void* management);
    2.21 @@ -158,6 +160,13 @@
    2.22      STDMETHOD(Log)(BSTR title, BSTR entity, BSTR description, BSTR comment);
    2.23      STDMETHOD(Trustwords)(BSTR fpr, BSTR lang, LONG max_words, BSTR * words);
    2.24      STDMETHOD(GetTrustwords)(struct pEpIdentity *id1, struct pEpIdentity *id2, BSTR lang, VARIANT_BOOL full, BSTR *words);
    2.25 +    STDMETHOD(GetMessageTrustwords)(
    2.26 +        /* [in] */ struct TextMessage *msg,
    2.27 +        /* [in] */ struct pEpIdentity *receivedBy,
    2.28 +        /* [in] */ SAFEARRAY *keylist,
    2.29 +        /* [defaultvalue][in] */ BSTR lang,
    2.30 +        /* [defaultvalue][in] */ VARIANT_BOOL full,
    2.31 +        /* [retval][out] */ BSTR *words);
    2.32      STDMETHOD(GetCrashdumpLog)(LONG maxlines, BSTR * log);
    2.33      STDMETHOD(GetEngineVersion)(BSTR * engineVersion);
    2.34      STDMETHOD(GetLanguageList)(BSTR * languages);
     3.1 --- a/pEpCOMServerAdapter.idl	Mon Jan 23 16:51:15 2017 +0100
     3.2 +++ b/pEpCOMServerAdapter.idl	Wed Feb 01 21:37:07 2017 +0100
     3.3 @@ -15,7 +15,7 @@
     3.4      pointer_default(unique)
     3.5  ]
     3.6  interface IpEpEngineCallbacks : IUnknown {
     3.7 -	typedef [v1_enum] enum SyncHandshakeSignal {
     3.8 +	typedef [v1_enum] enum SyncHandshakeSignal {
     3.9          SyncNotifyUndefined = 0,
    3.10          SyncNotifyInitAddOurDevice = 1,
    3.11          SyncNotifyInitAddOtherDevice = 2,
    3.12 @@ -23,7 +23,7 @@
    3.13          SyncNotifyTimeout = 4,
    3.14          SyncNotifyAcceptedDeviceAdded = 5,
    3.15          SyncNotifyAcceptedGroupCreated = 6
    3.16 -	} SyncHandshakeSignal;
    3.17 +	} SyncHandshakeSignal;
    3.18  
    3.19      typedef [v1_enum] enum SyncHandshakeResult {
    3.20          SyncHandshakeCancel = -1,
    3.21 @@ -35,6 +35,17 @@
    3.22      [id(2)] HRESULT NotifyHandshake([in] struct pEpIdentity * self, [in] struct pEpIdentity * partner, [in] SyncHandshakeSignal signal, [out, retval] SyncHandshakeResult * result);
    3.23  };
    3.24  
    3.25 +[
    3.26 +    object,
    3.27 +    uuid(64E964B2-880A-4E92-B0B5-66FF4286A3B3),
    3.28 +    oleautomation,
    3.29 +    nonextensible,
    3.30 +    pointer_default(unique)
    3.31 +]
    3.32 +interface IpEpEngineCallbacks2 : IpEpEngineCallbacks 
    3.33 +{
    3.34 +    [id(3)] HRESULT NeedFastPolling([in] VARIANT_BOOL enableFastPolling);
    3.35 +};
    3.36  
    3.37  [
    3.38      object,
    3.39 @@ -255,6 +266,25 @@
    3.40  };
    3.41  
    3.42  [
    3.43 +    object,
    3.44 +    uuid(8A042123-D433-4DEA-ADA2-2E5E61A00292),
    3.45 +    oleautomation,
    3.46 +    nonextensible,
    3.47 +    pointer_default(unique)
    3.48 +]
    3.49 +interface IpEpEngine2 : IpEpEngine
    3.50 +{
    3.51 +    HRESULT GetMessageTrustwords(
    3.52 +        [in] struct TextMessage *msg,
    3.53 +        [in] struct pEpIdentity * receivedBy,
    3.54 +        [in] SAFEARRAY(BSTR) keylist,
    3.55 +        [in, defaultvalue("en")] BSTR lang,
    3.56 +        [in, defaultvalue(0)] VARIANT_BOOL full,
    3.57 +        [out, retval] BSTR * words
    3.58 +    );
    3.59 +};
    3.60 +
    3.61 +[
    3.62      uuid(564A4350-419E-47F1-B0DF-6FCCF0CD0BBC),
    3.63      version(1.0),
    3.64  ]
    3.65 @@ -266,7 +296,8 @@
    3.66          uuid(5FF6682B-727B-4DFE-A68D-28982874C0C7)
    3.67      ]
    3.68      coclass pEpEngine {
    3.69 -        [default] interface IpEpEngine;
    3.70 -        interface IpEpEngineCallbacks;
    3.71 +        [default] interface IpEpEngine2;
    3.72 +        interface IpEpEngine;
    3.73 +        interface IpEpEngineCallbacks2;
    3.74      };
    3.75  };