diff options
author | Krzysztof Jackiewicz <k.jackiewicz@samsung.com> | 2014-09-16 10:05:35 +0200 |
---|---|---|
committer | Bartlomiej Grzelewski <b.grzelewski@samsung.com> | 2014-10-16 17:10:41 +0200 |
commit | 69a47332bd800b434abf29685d72eb8c051d9a08 (patch) | |
tree | 827336c47e0574ec19e49780a0eaacbd1ef871f9 | |
parent | 806b399774793aa8a62469c021ca8e0421e1c7d0 (diff) | |
download | key-manager-69a47332bd800b434abf29685d72eb8c051d9a08.tar.gz key-manager-69a47332bd800b434abf29685d72eb8c051d9a08.tar.bz2 key-manager-69a47332bd800b434abf29685d72eb8c051d9a08.zip |
Implement service communication
Add service class for communication with server services. Implement response
parser for single request.
Change-Id: Idf68c5abcb1e8270937b7b2f6f4e87fb6d696653
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/manager/client-async/connection-thread.cpp | 20 | ||||
-rw-r--r-- | src/manager/client-async/connection-thread.h | 4 | ||||
-rw-r--r-- | src/manager/client-async/receiver.cpp | 85 | ||||
-rw-r--r-- | src/manager/client-async/receiver.h | 51 | ||||
-rw-r--r-- | src/manager/client-async/service.cpp | 197 | ||||
-rw-r--r-- | src/manager/client-async/service.h | 60 |
7 files changed, 417 insertions, 2 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5063236a..cc3dff92 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -84,6 +84,8 @@ SET(KEY_MANAGER_CLIENT_SOURCES ${KEY_MANAGER_CLIENT_ASYNC_SRC_PATH}/client-manager-async-impl.cpp ${KEY_MANAGER_CLIENT_ASYNC_SRC_PATH}/connection-thread.cpp ${KEY_MANAGER_CLIENT_ASYNC_SRC_PATH}/async-request.cpp + ${KEY_MANAGER_CLIENT_ASYNC_SRC_PATH}/service.cpp + ${KEY_MANAGER_CLIENT_ASYNC_SRC_PATH}/receiver.cpp ${KEY_MANAGER_CLIENT_CAPI_SRC_PATH}/ckmc-type.cpp ${KEY_MANAGER_CLIENT_CAPI_SRC_PATH}/ckmc-error.cpp ${KEY_MANAGER_CLIENT_CAPI_SRC_PATH}/ckmc-manager.cpp diff --git a/src/manager/client-async/connection-thread.cpp b/src/manager/client-async/connection-thread.cpp index d6ea9bed..50d025fd 100644 --- a/src/manager/client-async/connection-thread.cpp +++ b/src/manager/client-async/connection-thread.cpp @@ -93,6 +93,11 @@ void ConnectionThread::threadLoop() LogError("Unknown exception occured"); } + // cleanup services + for(auto& it: m_services) + it.second.serviceError(CKM_API_ERROR_UNKNOWN); + m_services.clear(); + // close all descriptors (including pipe) m_descriptors.purge(); @@ -120,6 +125,17 @@ void ConnectionThread::readPipe(int pipe, short revents) } } +Service& ConnectionThread::getService(const std::string& interface) +{ + auto it = m_services.find(interface); + if (it != m_services.end()) + return it->second; + + // create new service, insert it and return + return m_services.insert( + std::make_pair(interface,Service(m_descriptors, interface))).first->second; +} + void ConnectionThread::newRequest(int pipe, short revents) { readPipe(pipe, revents); @@ -138,8 +154,8 @@ void ConnectionThread::newRequest(int pipe, short revents) lock.unlock(); - // TODO handle request here - req.observer->ReceivedError(CKM_API_ERROR_UNKNOWN); + Service& srv = getService(req.interface); + srv.addRequest(std::move(req)); } } /* namespace CKM */ diff --git a/src/manager/client-async/connection-thread.h b/src/manager/client-async/connection-thread.h index 864000de..690828bb 100644 --- a/src/manager/client-async/connection-thread.h +++ b/src/manager/client-async/connection-thread.h @@ -29,6 +29,7 @@ #include <client-common.h> #include <async-request.h> #include <descriptor-set.h> +#include <service.h> namespace CKM { @@ -56,6 +57,8 @@ private: // reads notification pipe void readPipe(int pipe, short revents); + Service& getService(const std::string& interface); + // Helper class that creates a pipe before thread is started class Pipe { public: @@ -81,6 +84,7 @@ private: std::thread m_thread; // child thread vars + std::map<std::string, Service> m_services; DescriptorSet m_descriptors; }; diff --git a/src/manager/client-async/receiver.cpp b/src/manager/client-async/receiver.cpp new file mode 100644 index 00000000..57db0bc5 --- /dev/null +++ b/src/manager/client-async/receiver.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2000 - 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 receiver.cpp + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + */ + +#include <receiver.h> +#include <protocols.h> +#include <dpl/log/log.h> + +namespace CKM { + +Receiver::Receiver(MessageBuffer& buffer, AsyncRequest::Map& requests) : + m_buffer(buffer), + m_requests(requests), + m_observer(NULL) +{ +} + +void Receiver::parseResponse() +{ + int command; + int id; + Deserialization::Deserialize(m_buffer, command); + Deserialization::Deserialize(m_buffer, id); + + auto it = m_requests.find(id); + if (it == m_requests.end()) { + LogError("Request with id " << id << " not found!"); + ThrowMsg(BadResponse, "Request with id " << id << " not found!"); + } + + // let it throw + AsyncRequest req = std::move(m_requests.at(id)); + m_requests.erase(id); + + m_observer = req.observer; + + switch (static_cast<LogicCommand>(command)) { + case LogicCommand::SAVE: + parseSaveCommand(); + break; + // TODO other cases + default: + LogError("Unknown command id: " << command); + ThrowMsg(BadResponse, "Unknown command id: " << command); + break; + } +} + +void Receiver::parseSaveCommand() +{ + int retCode; + int dataType; + + Deserialization::Deserialize(m_buffer, retCode); + Deserialization::Deserialize(m_buffer, dataType); + + DBDataType dt = static_cast<DBDataType>(dataType); + if (dt >= DBDataType::DB_KEY_FIRST && dt <= DBDataType::DB_KEY_LAST) { + if (retCode == CKM_API_SUCCESS) + m_observer->ReceivedSaveKey(); + else + m_observer->ReceivedError(retCode); + } else { + // TODO + } +} + +} /* namespace CKM */ diff --git a/src/manager/client-async/receiver.h b/src/manager/client-async/receiver.h new file mode 100644 index 00000000..4655791b --- /dev/null +++ b/src/manager/client-async/receiver.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2000 - 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 receiver.h + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + */ + +#pragma once + +#include <message-buffer.h> +#include <noncopyable.h> +#include <ckm/ckm-manager.h> +#include <async-request.h> + +namespace CKM { + +class Receiver +{ +public: + DECLARE_EXCEPTION_TYPE(CKM::Exception, BadResponse); + + Receiver(MessageBuffer& buffer, AsyncRequest::Map& reqMap); + virtual ~Receiver() {} + + NONCOPYABLE(Receiver); + + void parseResponse(); + +private: + void parseSaveCommand(); + + MessageBuffer& m_buffer; + AsyncRequest::Map& m_requests; + ManagerAsync::ObserverPtr m_observer; +}; + +} /* namespace CKM */ diff --git a/src/manager/client-async/service.cpp b/src/manager/client-async/service.cpp new file mode 100644 index 00000000..b2e8e8d1 --- /dev/null +++ b/src/manager/client-async/service.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2000 - 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 service.cpp + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + */ + +#include <service.h> +#include <dpl/log/log.h> +#include <receiver.h> + +namespace CKM { + +namespace { +const size_t RECV_BUFFER_SIZE = 2048; +} + +Service::Service(IDescriptorSet& descriptors, const std::string& interface) : + m_interface(interface), + m_descriptors(descriptors) +{ +} + +void Service::addRequest(AsyncRequest&& req) +{ + if(!m_socket) { + m_socket.reset(new SockRAII()); + int ret; + if (CKM_API_SUCCESS != (ret = m_socket->Connect(m_interface.c_str()))) { + LogError("Socket connection failed: " << ret); + m_socket.reset(); + req.observer->ReceivedError(ret); + return; + } + } + + if (m_sendQueue.empty()) + watch(POLLOUT); + + m_sendQueue.push(std::move(req)); +} + +void Service::serviceError(int error) +{ + if (m_socket) + { + // stop listening on socket + m_descriptors.remove(m_socket->Get(), false); + // close the socket + m_socket.reset(); + } + + // notify observers waiting for response + for(const auto& it: m_responseMap) { + it.second.observer->ReceivedError(error); + } + m_responseMap.clear(); + + // notify observers waiting for send + while(!m_sendQueue.empty()) { + m_sendQueue.front().observer->ReceivedError(error); + m_sendQueue.pop(); + } + + // clear response buffer + m_responseBuffer.reset(); +} + +void Service::socketReady(int sock, short revents) +{ + if (sock != m_socket->Get()) { + LogError("Unexpected socket: " << sock << "!=" << m_socket->Get()); + serviceError(CKM_API_ERROR_SOCKET); + return; + } + + try { + if (revents & POLLOUT) + sendData(); + else if (revents & POLLIN) + receiveData(); + else { + LogError("Unexpected event: " << revents << "!=" << POLLOUT); + serviceError(CKM_API_ERROR_SOCKET); + } + } catch (const Receiver::BadResponse&) { + serviceError(CKM_API_ERROR_BAD_RESPONSE); + } catch (std::exception &e) { + LogError("STD exception " << e.what()); + serviceError(CKM_API_ERROR_UNKNOWN); + } catch (...) { + LogError("Unknown exception occurred"); + serviceError(CKM_API_ERROR_UNKNOWN); + } +} + +void Service::sendData() +{ + // nothing to send? -> stop watching POLLOUT + if (m_sendQueue.empty()) { + watch(POLLIN); + return; + } + + while (!m_sendQueue.empty()) { + AsyncRequest& req = m_sendQueue.front(); + + ssize_t temp = TEMP_FAILURE_RETRY(write(m_socket->Get(), + &req.buffer[req.written], + req.buffer.size() - req.written)); + if (-1 == temp) { + int err = errno; + // can't write? -> go to sleep + if (EAGAIN == err || EWOULDBLOCK == err) + return; + + LogError("Error in write: " << strerror(err)); + serviceError(CKM_API_ERROR_SEND_FAILED); + return; + } + + req.written += temp; + + // finished? -> move request to response map + if(req.written == req.buffer.size()) { + AsyncRequest finished = std::move(m_sendQueue.front()); + m_sendQueue.pop(); + + // update poll flags if necessary + if(m_sendQueue.empty() || m_responseMap.empty()) + watch((m_sendQueue.empty()? 0 : POLLOUT) | POLLIN); + + m_responseMap.insert(std::make_pair(finished.id,finished)); + } + } +} + +void Service::receiveData() +{ + char buffer[RECV_BUFFER_SIZE]; + + ssize_t temp = TEMP_FAILURE_RETRY(read(m_socket->Get(), buffer, RECV_BUFFER_SIZE)); + if (-1 == temp) { + int err = errno; + LogError("Error in read: " << strerror(err)); + serviceError(CKM_API_ERROR_RECV_FAILED); + return; + } + + if (0 == temp) { + LogError("Read return 0/Connection closed by server(?)"); + serviceError(CKM_API_ERROR_RECV_FAILED); + return; + } + + if (!m_responseBuffer) + m_responseBuffer.reset(new MessageBuffer()); + + RawBuffer raw(buffer, buffer+temp); + m_responseBuffer->Push(raw); + + // parse while you can + while(m_responseBuffer->Ready()) + { + Receiver recv(*m_responseBuffer, m_responseMap); + recv.parseResponse(); + + if (m_responseMap.empty()) + watch(m_sendQueue.empty()?0:POLLOUT); + } +} + +void Service::watch(short events) +{ + if (0 == events) + m_descriptors.remove(m_socket->Get(), false); + else + m_descriptors.add(m_socket->Get(), + events, + [this](int sock, short revents){ socketReady(sock, revents); }); +} + +} // namespace CKM diff --git a/src/manager/client-async/service.h b/src/manager/client-async/service.h new file mode 100644 index 00000000..0de979f8 --- /dev/null +++ b/src/manager/client-async/service.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2000 - 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 service.h + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + */ + +#pragma once + +#include <string> +#include <memory> +#include <descriptor-set.h> +#include <async-request.h> +#include <noncopyable.h> +#include <client-common.h> + +namespace CKM { + +class Service { +public: + Service(IDescriptorSet& descriptors, const std::string& interface); + + Service(Service&&) = default; + Service& operator=(Service&&) = default; + + void addRequest(AsyncRequest&& req); + + void serviceError(int error); + +private: + void socketReady(int sock, short revents); + + void sendData(); + void receiveData(); + + void watch(short events); + + std::string m_interface; + std::unique_ptr<SockRAII> m_socket; + IDescriptorSet& m_descriptors; + AsyncRequest::Queue m_sendQueue; + AsyncRequest::Map m_responseMap; + std::unique_ptr<MessageBuffer> m_responseBuffer; +}; + +} // namespace CKM |