Add protection against cynara_async_finish() call in callbacks 48/30348/5
authorMarcin Niesluchowski <m.niesluchow@samsung.com>
Fri, 14 Nov 2014 17:48:01 +0000 (18:48 +0100)
committerLukasz Wojciechowski <l.wojciechow@partner.samsung.com>
Fri, 14 Nov 2014 22:03:20 +0000 (14:03 -0800)
cynara_async_finish() called in callbacks is ignored in all cases.

Change-Id: I3c2268a0462413b279215f837e4603a7d6acb96d

src/client-async/api/ApiInterface.h
src/client-async/api/client-async-api.cpp
src/client-async/logic/Logic.cpp
src/client-async/logic/Logic.h
src/include/cynara-client-async.h

index 31478da..59c82fb 100644 (file)
@@ -42,6 +42,7 @@ public:
                               void *userResponseData) = 0;
     virtual int process(void) = 0;
     virtual int cancelRequest(cynara_check_id checkId) = 0;
+    virtual bool isFinishPermitted(void) = 0;
 };
 
 } // namespace Cynara
index 1e3479e..13e5a16 100644 (file)
@@ -61,6 +61,9 @@ int cynara_async_initialize(cynara_async **pp_cynara,
 
 CYNARA_API
 void cynara_async_finish(cynara_async *p_cynara) {
+    if (!p_cynara->impl->isFinishPermitted())
+        return;
+
     delete p_cynara;
 }
 
index 5e0157d..48b8bad 100644 (file)
@@ -43,7 +43,8 @@
 namespace Cynara {
 
 Logic::Logic(cynara_status_callback callback, void *userStatusData)
-    : m_statusCallback(callback, userStatusData), m_operationPermitted(true) {
+    : m_statusCallback(callback, userStatusData), m_operationPermitted(true),
+      m_inAnswerCancelResponseCallback(false) {
     m_socketClient = std::make_shared<SocketClientAsync>(
         PathConfig::SocketPath::client, std::make_shared<ProtocolClient>());
 
@@ -130,12 +131,21 @@ int Logic::cancelRequest(cynara_check_id checkId) {
     m_socketClient->appendRequest(std::make_shared<CancelRequest>(it->first));
 
     it->second.cancel();
+
+    bool onAnswerCancel = m_inAnswerCancelResponseCallback;
+    m_inAnswerCancelResponseCallback = true;
     it->second.callback().onCancel(it->first);
+    m_inAnswerCancelResponseCallback = onAnswerCancel;
+
     onStatusChange(m_socketClient->getSockFd(), cynara_async_status::CYNARA_STATUS_FOR_RW);
 
     return CYNARA_API_SUCCESS;
 }
 
+bool Logic::isFinishPermitted(void) {
+    return m_operationPermitted && !m_inAnswerCancelResponseCallback;
+}
+
 bool Logic::checkCacheValid(void) {
     return m_socketClient->isConnected();
 }
@@ -180,9 +190,13 @@ void Logic::processCheckResponse(CheckResponsePtr checkResponse) {
     CheckData checkData(std::move(it->second));
     m_sequenceContainer.release(it->first);
     m_checks.erase(it);
-    if (!checkData.cancelled())
+    if (!checkData.cancelled()) {
+        bool onAnswerCancel = m_inAnswerCancelResponseCallback;
+        m_inAnswerCancelResponseCallback = true;
         checkData.callback().onAnswer(
             static_cast<cynara_check_id>(checkResponse->sequenceNumber()), result);
+        m_inAnswerCancelResponseCallback = onAnswerCancel;
+    }
 }
 
 void Logic::processCancelResponse(CancelResponsePtr cancelResponse) {
index 6f30fdb..6d41412 100644 (file)
@@ -49,6 +49,7 @@ public:
                               void *userResponseData);
     virtual int process(void);
     virtual int cancelRequest(cynara_check_id checkId);
+    virtual bool isFinishPermitted(void);
 
 private:
     typedef std::map<ProtocolFrameSequenceNumber, CheckData> CheckMap;
@@ -60,6 +61,7 @@ private:
     CheckMap m_checks;
     SequenceContainer m_sequenceContainer;
     bool m_operationPermitted;
+    bool m_inAnswerCancelResponseCallback;
 
     bool checkCacheValid(void);
     void prepareRequestsToSend(void);
index b9675f1..d9b4d2f 100644 (file)
@@ -86,6 +86,7 @@ typedef enum {
  *    - probably cynara is unoperational (CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE)
  * Api functions called during this callback with CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE
  * or CYNARA_CALL_CAUSE_FINISH cause will return CYNARA_API_OPERATION_NOT_ALLOWED.
+ * cynara_async_finish() will be ignored if called from within this callback.
  *
  * \param[in] check_id Number identifying check request. Number is generated in
  *            cynara_async_create_request() and returned to user. It can be used to match
@@ -116,6 +117,7 @@ typedef void (*cynara_response_callback) (cynara_check_id check_id, cynara_async
  * so user should not use it in other way than waiting on it in event loop.
  * In particular user should not write to, read from or close this fd.
  * CYNARA_API_OPERATION_NOT_ALLOWED will be returned for every api function called in this callback.
+ * cynara_async_finish() will be ignored if called from within this callback.
  *
  * \param[in] old_fd Old descriptor which should be unregistered from event loop,
  *            Special value -1 is used when callback is called after first
@@ -207,6 +209,8 @@ int cynara_async_initialize(cynara_async **pp_cynara, const cynara_async_configu
  *
  * \par Important notes:
  * No other call to cynara-async-client library should be made after call to cynara_async_finish().
+ * cynara_async_finish() called from within cynara_response_callback or cynara_status_callback will
+ * be ignored.
  *
  * \param[in] p_cynara cynara_async structure. If NULL, then the call has no effect.
  */