From 29946e7cef5b2fd04531acdb8ab911eb85e2decf Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Thu, 18 Sep 2014 11:32:15 +0200 Subject: [PATCH] Add creating, sending and receiving check requests cynara_async_create_request() and cynara_async_process() functions work according to the API header excluding possibility to cancel request. Change-Id: I9818be674d58da5bd431a08b7faf47dfe0157289 --- src/client-async/CMakeLists.txt | 2 + src/client-async/callback/ResponseCallback.cpp | 50 ++++++++++ src/client-async/callback/ResponseCallback.h | 48 ++++++++++ src/client-async/check/CheckData.h | 65 +++++++++++++ src/client-async/logic/Logic.cpp | 122 +++++++++++++++++++++--- src/client-async/logic/Logic.h | 14 +++ src/client-async/sequence/SequenceContainer.cpp | 63 ++++++++++++ src/client-async/sequence/SequenceContainer.h | 48 ++++++++++ 8 files changed, 399 insertions(+), 13 deletions(-) create mode 100644 src/client-async/callback/ResponseCallback.cpp create mode 100644 src/client-async/callback/ResponseCallback.h create mode 100644 src/client-async/check/CheckData.h create mode 100644 src/client-async/sequence/SequenceContainer.cpp create mode 100644 src/client-async/sequence/SequenceContainer.h diff --git a/src/client-async/CMakeLists.txt b/src/client-async/CMakeLists.txt index 5b3d404..a9b9971 100644 --- a/src/client-async/CMakeLists.txt +++ b/src/client-async/CMakeLists.txt @@ -30,8 +30,10 @@ INCLUDE_DIRECTORIES( SET(LIB_CYNARA_ASYNC_SOURCES ${CYNARA_LIB_CYNARA_ASYNC_PATH}/api/client-async-api.cpp + ${CYNARA_LIB_CYNARA_ASYNC_PATH}/callback/ResponseCallback.cpp ${CYNARA_LIB_CYNARA_ASYNC_PATH}/callback/StatusCallback.cpp ${CYNARA_LIB_CYNARA_ASYNC_PATH}/logic/Logic.cpp + ${CYNARA_LIB_CYNARA_ASYNC_PATH}/sequence/SequenceContainer.cpp ${CYNARA_LIB_CYNARA_ASYNC_PATH}/sockets/SocketClientAsync.cpp ) diff --git a/src/client-async/callback/ResponseCallback.cpp b/src/client-async/callback/ResponseCallback.cpp new file mode 100644 index 0000000..e4577b3 --- /dev/null +++ b/src/client-async/callback/ResponseCallback.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/callback/ResponseCallback.cpp + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains definition of ResponseCallback class + */ + +#include "ResponseCallback.h" + +namespace Cynara { + +ResponseCallback::ResponseCallback(cynara_response_callback callback, void *userData) + : m_callback(callback), m_userData(userData) { +} + +void ResponseCallback::onAnswer(cynara_check_id checkId, int response) const { + if (!m_callback) + return; + m_callback(checkId, cynara_async_call_cause::CYNARA_CALL_CAUSE_ANSWER, response, m_userData); +} + +void ResponseCallback::onFinish(cynara_check_id checkId) const { + if (!m_callback) + return; + m_callback(checkId, cynara_async_call_cause::CYNARA_CALL_CAUSE_FINISH, 0, m_userData); +} + +void ResponseCallback::onDisconnected(cynara_check_id checkId) const { + if (!m_callback) + return; + m_callback(checkId, cynara_async_call_cause::CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE, 0, + m_userData); +} + +} // namespace Cynara diff --git a/src/client-async/callback/ResponseCallback.h b/src/client-async/callback/ResponseCallback.h new file mode 100644 index 0000000..47d526a --- /dev/null +++ b/src/client-async/callback/ResponseCallback.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/callback/ResponseCallback.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains declaration of ResponseCallback class + */ + +#ifndef SRC_CLIENT_ASYNC_CALLBACK_RESPONSECALLBACK_H_ +#define SRC_CLIENT_ASYNC_CALLBACK_RESPONSECALLBACK_H_ + +#include + +namespace Cynara { + +class ResponseCallback { +public: + ResponseCallback(cynara_response_callback callback, void *userData); + ResponseCallback(const ResponseCallback&) = default; + ~ResponseCallback() {}; + + void onAnswer(cynara_check_id checkId, int response) const; + // MOCKUP + void onFinish(cynara_check_id checkId) const; + void onDisconnected(cynara_check_id checkId) const; + +private: + cynara_response_callback m_callback; + void *m_userData; +}; + +} // namespace Cynara + +#endif /* SRC_CLIENT_ASYNC_CALLBACK_RESPONSECALLBACK_H_ */ diff --git a/src/client-async/check/CheckData.h b/src/client-async/check/CheckData.h new file mode 100644 index 0000000..1f8fe90 --- /dev/null +++ b/src/client-async/check/CheckData.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/check/CheckData.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains CheckData class for storing + * information about asynchronous check request. + */ + +#ifndef SRC_CLIENT_ASYNC_CHECK_CHECKDATA_H_ +#define SRC_CLIENT_ASYNC_CHECK_CHECKDATA_H_ + +#include +#include + +#include + +#include + +namespace Cynara { + +class CheckData +{ +public: + CheckData(const PolicyKey &key, const std::string &session, const ResponseCallback &callback) + : m_key(key), m_session(session), m_callback(callback) {} + ~CheckData() {} + + const PolicyKey &key(void) const { + return m_key; + } + + const std::string &session(void) const { + return m_session; + } + + const ResponseCallback &callback(void) const { + return m_callback; + } + +private: + PolicyKey m_key; + std::string m_session; + ResponseCallback m_callback; + // MOCKUP +}; + +} // namespace Cynara + +#endif // SRC_CLIENT_ASYNC_CHECK_CHECKDATA_H_ + diff --git a/src/client-async/logic/Logic.cpp b/src/client-async/logic/Logic.cpp index e1574ce..23cd7cc 100644 --- a/src/client-async/logic/Logic.cpp +++ b/src/client-async/logic/Logic.cpp @@ -26,10 +26,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include @@ -49,7 +52,9 @@ Logic::Logic(cynara_status_callback callback, void *userStatusData) } Logic::~Logic() { - onDisconnected(); + for (auto &kv : m_checks) + kv.second.callback().onFinish(kv.first); + m_statusCallback.onDisconnected(); } int Logic::checkCache(const std::string &client, const std::string &session, @@ -60,25 +65,41 @@ int Logic::checkCache(const std::string &client, const std::string &session, return m_cache->get(session, PolicyKey(client, user, privilege)); } -int Logic::createRequest(const std::string &client UNUSED, const std::string &session UNUSED, - const std::string &user UNUSED, const std::string &privilege UNUSED, - cynara_check_id &checkId UNUSED, cynara_response_callback callback UNUSED, - void *userResponseData UNUSED) { +int Logic::createRequest(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege, + cynara_check_id &checkId, cynara_response_callback callback, + void *userResponseData) { if (!ensureConnection()) return CYNARA_API_SERVICE_NOT_AVAILABLE; - // MOCKUP - return CYNARA_API_MAX_PENDING_REQUESTS; + ProtocolFrameSequenceNumber sequenceNumber; + if (!m_sequenceContainer.get(sequenceNumber)) + return CYNARA_API_MAX_PENDING_REQUESTS; + + PolicyKey key(client, user, privilege); + ResponseCallback responseCallback(callback, userResponseData); + m_checks.insert(CheckPair(sequenceNumber, CheckData(key, session, responseCallback))); + m_socketClient->appendRequest(std::make_shared(key, sequenceNumber)); + + m_statusCallback.onStatusChange(m_socketClient->getSockFd(), + cynara_async_status::CYNARA_STATUS_FOR_RW); + checkId = static_cast(sequenceNumber); + + return CYNARA_API_SUCCESS; } int Logic::process(void) { bool completed; - int ret = completeConnection(completed); - if (!completed) - return ret; - - // MOCKUP - return CYNARA_API_SUCCESS; + while (true) { + int ret = completeConnection(completed); + if (!completed) + return ret; + if (processOut() && processIn()) + return CYNARA_API_SUCCESS; + onDisconnected(); + if (!connect()) + return CYNARA_API_SERVICE_NOT_AVAILABLE; + } } int Logic::cancelRequest(cynara_check_id checkId UNUSED) { @@ -94,7 +115,67 @@ bool Logic::checkCacheValid(void) { } void Logic::prepareRequestsToSend(void) { + for (auto &kv : m_checks) { + // MOCKUP + m_socketClient->appendRequest(std::make_shared(kv.second.key(), kv.first)); + } +} + +bool Logic::processOut(void) { + switch (m_socketClient->sendToCynara()) { + case Socket::SendStatus::ALL_DATA_SENT: + m_statusCallback.onStatusChange(m_socketClient->getSockFd(), + cynara_async_status::CYNARA_STATUS_FOR_READ); + case Socket::SendStatus::PARTIAL_DATA_SENT: + return true; + default: + return false; + } +} + +void Logic::processCheckResponse(CheckResponsePtr checkResponse) { + LOGD("checkResponse: policyType = [%" PRIu16 "], metadata = <%s>", + checkResponse->m_resultRef.policyType(), + checkResponse->m_resultRef.metadata().c_str()); + + auto it = m_checks.find(checkResponse->sequenceNumber()); + if (it == m_checks.end()) { + LOGC("Critical error. Unknown response received: sequenceNumber = [%" PRIu16 "]", + checkResponse->sequenceNumber()); + throw UnexpectedErrorException("Unexpected response from cynara service"); + } + int result = m_cache->update(it->second.session(), it->second.key(), + checkResponse->m_resultRef); // MOCKUP + it->second.callback().onAnswer(static_cast(it->first), result); + m_sequenceContainer.release(it->first); + m_checks.erase(it); +} + +void Logic::processResponses(void) { + ResponsePtr response; + CheckResponsePtr checkResponse; + while (true) { + response = m_socketClient->getResponse(); + if (!response) + break; + + checkResponse = std::dynamic_pointer_cast(response); + if (checkResponse) { + processCheckResponse(checkResponse); + continue; + } + // MOCKUP + LOGC("Critical error. Casting Response to CheckResponse failed."); + throw UnexpectedErrorException("Unexpected response from cynara service"); + } +} + +bool Logic::processIn(void) { + if (!m_socketClient->receiveFromCynara()) + return false; + processResponses(); + return true; } cynara_async_status Logic::socketDataStatus(void) { @@ -106,6 +187,11 @@ bool Logic::ensureConnection(void) { if (m_socketClient->isConnected()) return true; onDisconnected(); + + return connect(); +} + +bool Logic::connect(void) { switch (m_socketClient->connect()) { case Socket::ConnectionStatus::CONNECTION_SUCCEEDED: prepareRequestsToSend(); @@ -117,6 +203,7 @@ bool Logic::ensureConnection(void) { cynara_async_status::CYNARA_STATUS_FOR_RW); return true; default: + onServiceNotAvailable(); return false; } } @@ -136,10 +223,19 @@ int Logic::completeConnection(bool &completed) { default: completed = false; onDisconnected(); + onServiceNotAvailable(); return CYNARA_API_SERVICE_NOT_AVAILABLE; } } +void Logic::onServiceNotAvailable(void) +{ + for (auto &kv : m_checks) + kv.second.callback().onDisconnected(kv.first); + m_checks.clear(); + m_sequenceContainer.clear(); +} + void Logic::onDisconnected(void) { m_cache->clear(); m_statusCallback.onDisconnected(); diff --git a/src/client-async/logic/Logic.h b/src/client-async/logic/Logic.h index 0475b08..53cfba9 100644 --- a/src/client-async/logic/Logic.h +++ b/src/client-async/logic/Logic.h @@ -25,10 +25,13 @@ #define SRC_CLIENT_ASYNC_LOGIC_LOGIC_H_ #include +#include #include #include +#include #include +#include #include namespace Cynara { @@ -48,15 +51,26 @@ public: virtual int cancelRequest(cynara_check_id checkId); private: + typedef std::map CheckMap; + typedef std::pair CheckPair; + StatusCallback m_statusCallback; PluginCachePtr m_cache; SocketClientAsyncPtr m_socketClient; + CheckMap m_checks; + SequenceContainer m_sequenceContainer; bool checkCacheValid(void); void prepareRequestsToSend(void); cynara_async_status socketDataStatus(void); + bool processOut(void); + void processCheckResponse(CheckResponsePtr checkResponse); + void processResponses(void); + bool processIn(void); bool ensureConnection(void); + bool connect(void); int completeConnection(bool &completed); + void onServiceNotAvailable(void); void onDisconnected(void); }; diff --git a/src/client-async/sequence/SequenceContainer.cpp b/src/client-async/sequence/SequenceContainer.cpp new file mode 100644 index 0000000..95b9318 --- /dev/null +++ b/src/client-async/sequence/SequenceContainer.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/sequence/SequenceContainer.cpp + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains definition of SequenceContainer class for + * storing check requests identifiers in libcynara-client-async + */ + +#include +#include +#include +#include + +#include "SequenceContainer.h" + +namespace Cynara { + +SequenceContainer::SequenceContainer() + : m_sequenceVector(((static_cast(UINT16_MAX) + 1) / CHAR_BIT) / sizeof(int), -1) { +} + +bool SequenceContainer::get(ProtocolFrameSequenceNumber &sequenceNumber) { + for (size_t index = 0; index < m_sequenceVector.size(); ++index) { + int pos = ffs(m_sequenceVector[index]); + if (pos != 0) { + sequenceNumber = static_cast(index * sizeof(int) * CHAR_BIT - 1 + pos); + m_sequenceVector[index] ^= 1 << (pos - 1); + return true; + } + } + return false; +} + +bool SequenceContainer::release(ProtocolFrameSequenceNumber sequenceNumber) { + size_t index = static_cast(sequenceNumber) / (CHAR_BIT * sizeof(int)); + int pos = static_cast(sequenceNumber) % (CHAR_BIT * sizeof(int)); + int i = m_sequenceVector[index] | 1 << pos; + if (i == m_sequenceVector[index]) + return false; + m_sequenceVector[index] = i; + return true; +} + +void SequenceContainer::clear(void) { + memset(m_sequenceVector.data(), -1, m_sequenceVector.size() * sizeof(int)); +} + +} // namespace Cynara diff --git a/src/client-async/sequence/SequenceContainer.h b/src/client-async/sequence/SequenceContainer.h new file mode 100644 index 0000000..c8748e6 --- /dev/null +++ b/src/client-async/sequence/SequenceContainer.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/sequence/SequenceContainer.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains declaration of SequenceContainer class for + * storing check requests identifiers in libcynara-client-async + */ + +#ifndef SRC_CLIENT_ASYNC_SEQUENCE_SEQUENCECONTAINER_H_ +#define SRC_CLIENT_ASYNC_SEQUENCE_SEQUENCECONTAINER_H_ + +#include + +#include + +namespace Cynara { + +class SequenceContainer { +public: + SequenceContainer(); + ~SequenceContainer() {} + + bool get(ProtocolFrameSequenceNumber &sequenceNumber); + bool release(ProtocolFrameSequenceNumber sequenceNumber); + void clear(void); + +private: + std::vector m_sequenceVector; +}; + +} // namespace Cynara + +#endif // SRC_CLIENT_ASYNC_SEQUENCE_SEQUENCECONTAINER_H_ -- 2.7.4