39a4379c28ff15ea0d574a6fd5aa45c4c05c6297
[platform/core/security/key-manager.git] / src / manager / client-async / service.cpp
1 /*
2  *  Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  */
16 /*
17  * @file       service.cpp
18  * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
19  * @version    1.0
20  */
21
22 #include <service.h>
23
24 #include <dpl/errno_string.h>
25 #include <dpl/log/log.h>
26
27 #include <storage-receiver.h>
28 #include <ocsp-receiver.h>
29 #include <encryption-receiver.h>
30 #include <protocols.h>
31
32 namespace CKM {
33
34 namespace {
35 const size_t RECV_BUFFER_SIZE = 2048;
36 }
37
38 Service::Service(IDescriptorSet& descriptors, const std::string& interface) :
39     m_interface(interface),
40     m_descriptors(descriptors)
41 {
42 }
43
44 void Service::addRequest(AsyncRequest&& req)
45 {
46     if(!m_socket) {
47         m_socket.reset(new SockRAII());
48         int ret;
49         if (CKM_API_SUCCESS != (ret = m_socket->connect(m_interface.c_str()))) {
50             LogError("Socket connection failed: " << ret);
51             m_socket.reset();
52             req.observer->ReceivedError(ret);
53             return;
54         }
55     }
56
57     if (m_sendQueue.empty())
58         watch(POLLOUT);
59
60     m_sendQueue.push(std::move(req));
61 }
62
63 void Service::serviceError(int error)
64 {
65     if (m_socket)
66     {
67         // stop listening on socket
68         m_descriptors.remove(m_socket->get(), false);
69         // close the socket
70         m_socket.reset();
71     }
72
73     // notify observers waiting for response
74     for(const auto& it: m_responseMap) {
75         it.second.observer->ReceivedError(error);
76     }
77     m_responseMap.clear();
78
79     // notify observers waiting for send
80     while(!m_sendQueue.empty()) {
81         m_sendQueue.front().observer->ReceivedError(error);
82         m_sendQueue.pop();
83     }
84
85     // clear response buffer
86     m_responseBuffer.reset();
87 }
88
89 void Service::socketReady(int sock, short revents)
90 {
91     if (sock != m_socket->get()) {
92         LogError("Unexpected socket: " << sock << "!=" << m_socket->get());
93         serviceError(CKM_API_ERROR_SOCKET);
94         return;
95     }
96
97     try {
98         if (revents & POLLOUT)
99             sendData();
100         else if (revents & POLLIN)
101             receiveData();
102         else {
103             LogError("Unexpected event: " << revents << "!=" << POLLOUT);
104             serviceError(CKM_API_ERROR_SOCKET);
105         }
106     } catch (const IReceiver::BadResponse&) {
107         serviceError(CKM_API_ERROR_BAD_RESPONSE);
108     } catch (std::exception &e) {
109         LogError("STD exception " << e.what());
110         serviceError(CKM_API_ERROR_UNKNOWN);
111     } catch (...) {
112         LogError("Unknown exception occurred");
113         serviceError(CKM_API_ERROR_UNKNOWN);
114     }
115 }
116
117 void Service::sendData()
118 {
119     // nothing to send? -> stop watching POLLOUT
120     if (m_sendQueue.empty()) {
121         watch(POLLIN);
122         return;
123     }
124
125     while (!m_sendQueue.empty()) {
126         AsyncRequest& req = m_sendQueue.front();
127
128         ssize_t temp = TEMP_FAILURE_RETRY(write(m_socket->get(),
129                                                 &req.buffer[req.written],
130                                                 req.buffer.size() - req.written));
131         if (-1 == temp) {
132             int err = errno;
133             // can't write? -> go to sleep
134             if (EAGAIN == err || EWOULDBLOCK == err)
135                 return;
136
137             LogError("Error in write: " << GetErrnoString(err));
138             serviceError(CKM_API_ERROR_SEND_FAILED);
139             return;
140         }
141
142         req.written += temp;
143
144         // finished? -> move request to response map
145         if(req.written == req.buffer.size()) {
146             AsyncRequest finished = std::move(m_sendQueue.front());
147             m_sendQueue.pop();
148
149             // update poll flags if necessary
150             if(m_sendQueue.empty() || m_responseMap.empty())
151                 watch((m_sendQueue.empty()? 0 : POLLOUT) | POLLIN);
152
153             m_responseMap.insert(std::make_pair(finished.id,finished));
154         }
155     }
156 }
157
158 void Service::receiveData()
159 {
160     char buffer[RECV_BUFFER_SIZE];
161
162     ssize_t temp = TEMP_FAILURE_RETRY(read(m_socket->get(), buffer, RECV_BUFFER_SIZE));
163     if (-1 == temp) {
164         int err = errno;
165         LogError("Error in read: " << GetErrnoString(err));
166         serviceError(CKM_API_ERROR_RECV_FAILED);
167         return;
168     }
169
170     if (0 == temp) {
171         LogError("Read return 0/Connection closed by server(?)");
172         serviceError(CKM_API_ERROR_RECV_FAILED);
173         return;
174     }
175
176     if (!m_responseBuffer)
177         m_responseBuffer.reset(new MessageBuffer());
178
179     RawBuffer raw(buffer, buffer+temp);
180     m_responseBuffer->Push(raw);
181
182     // parse while you can
183     while(m_responseBuffer->Ready())
184     {
185         std::unique_ptr<IReceiver> receiver;
186         if (m_interface == SERVICE_SOCKET_CKM_STORAGE)
187             receiver.reset(new StorageReceiver(*m_responseBuffer, m_responseMap));
188         else if (m_interface == SERVICE_SOCKET_OCSP)
189             receiver.reset(new OcspReceiver(*m_responseBuffer, m_responseMap));
190         else if (m_interface == SERVICE_SOCKET_ENCRYPTION)
191             receiver.reset(new EncryptionReceiver(*m_responseBuffer, m_responseMap));
192         else {
193             LogError("Unknown service " << m_interface);
194             serviceError(CKM_API_ERROR_RECV_FAILED);
195             return;
196         }
197         receiver->processResponse();
198
199         if (m_responseMap.empty())
200             watch(m_sendQueue.empty()?0:POLLOUT);
201     }
202 }
203
204 void Service::watch(short events)
205 {
206     if (0 == events)
207         m_descriptors.remove(m_socket->get(), false);
208     else
209         m_descriptors.add(m_socket->get(),
210                           events,
211                           [this](int sock, short revents){ socketReady(sock, revents); });
212 }
213
214 } // namespace CKM