5eb87565581758f63e735b41ae1781fc95614c11
[platform/core/security/key-manager.git] / src / manager / client-async / service.cpp
1 /*
2  *  Copyright (c) 2000 - 2014 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 #include <dpl/log/log.h>
24 #include <storage-receiver.h>
25 #include <ocsp-receiver.h>
26 #include <protocols.h>
27
28 namespace CKM {
29
30 namespace {
31 const size_t RECV_BUFFER_SIZE = 2048;
32 }
33
34 Service::Service(IDescriptorSet& descriptors, const std::string& interface) :
35     m_interface(interface),
36     m_descriptors(descriptors)
37 {
38 }
39
40 void Service::addRequest(AsyncRequest&& req)
41 {
42     if(!m_socket) {
43         m_socket.reset(new SockRAII());
44         int ret;
45         if (CKM_API_SUCCESS != (ret = m_socket->Connect(m_interface.c_str()))) {
46             LogError("Socket connection failed: " << ret);
47             m_socket.reset();
48             req.observer->ReceivedError(ret);
49             return;
50         }
51     }
52
53     if (m_sendQueue.empty())
54         watch(POLLOUT);
55
56     m_sendQueue.push(std::move(req));
57 }
58
59 void Service::serviceError(int error)
60 {
61     if (m_socket)
62     {
63         // stop listening on socket
64         m_descriptors.remove(m_socket->Get(), false);
65         // close the socket
66         m_socket.reset();
67     }
68
69     // notify observers waiting for response
70     for(const auto& it: m_responseMap) {
71         it.second.observer->ReceivedError(error);
72     }
73     m_responseMap.clear();
74
75     // notify observers waiting for send
76     while(!m_sendQueue.empty()) {
77         m_sendQueue.front().observer->ReceivedError(error);
78         m_sendQueue.pop();
79     }
80
81     // clear response buffer
82     m_responseBuffer.reset();
83 }
84
85 void Service::socketReady(int sock, short revents)
86 {
87     if (sock != m_socket->Get()) {
88         LogError("Unexpected socket: " << sock << "!=" << m_socket->Get());
89         serviceError(CKM_API_ERROR_SOCKET);
90         return;
91     }
92
93     try {
94         if (revents & POLLOUT)
95             sendData();
96         else if (revents & POLLIN)
97             receiveData();
98         else {
99             LogError("Unexpected event: " << revents << "!=" << POLLOUT);
100             serviceError(CKM_API_ERROR_SOCKET);
101         }
102     } catch (const IReceiver::BadResponse&) {
103         serviceError(CKM_API_ERROR_BAD_RESPONSE);
104     } catch (std::exception &e) {
105         LogError("STD exception " << e.what());
106         serviceError(CKM_API_ERROR_UNKNOWN);
107     } catch (...) {
108         LogError("Unknown exception occurred");
109         serviceError(CKM_API_ERROR_UNKNOWN);
110     }
111 }
112
113 void Service::sendData()
114 {
115     // nothing to send? -> stop watching POLLOUT
116     if (m_sendQueue.empty()) {
117         watch(POLLIN);
118         return;
119     }
120
121     while (!m_sendQueue.empty()) {
122         AsyncRequest& req = m_sendQueue.front();
123
124         ssize_t temp = TEMP_FAILURE_RETRY(write(m_socket->Get(),
125                                                 &req.buffer[req.written],
126                                                 req.buffer.size() - req.written));
127         if (-1 == temp) {
128             int err = errno;
129             // can't write? -> go to sleep
130             if (EAGAIN == err || EWOULDBLOCK == err)
131                 return;
132
133             LogError("Error in write: " << strerror(err));
134             serviceError(CKM_API_ERROR_SEND_FAILED);
135             return;
136         }
137
138         req.written += temp;
139
140         // finished? -> move request to response map
141         if(req.written == req.buffer.size()) {
142             AsyncRequest finished = std::move(m_sendQueue.front());
143             m_sendQueue.pop();
144
145             // update poll flags if necessary
146             if(m_sendQueue.empty() || m_responseMap.empty())
147                 watch((m_sendQueue.empty()? 0 : POLLOUT) | POLLIN);
148
149             m_responseMap.insert(std::make_pair(finished.id,finished));
150         }
151     }
152 }
153
154 void Service::receiveData()
155 {
156     char buffer[RECV_BUFFER_SIZE];
157
158     ssize_t temp = TEMP_FAILURE_RETRY(read(m_socket->Get(), buffer, RECV_BUFFER_SIZE));
159     if (-1 == temp) {
160         int err = errno;
161         LogError("Error in read: " << strerror(err));
162         serviceError(CKM_API_ERROR_RECV_FAILED);
163         return;
164     }
165
166     if (0 == temp) {
167         LogError("Read return 0/Connection closed by server(?)");
168         serviceError(CKM_API_ERROR_RECV_FAILED);
169         return;
170     }
171
172     if (!m_responseBuffer)
173         m_responseBuffer.reset(new MessageBuffer());
174
175     RawBuffer raw(buffer, buffer+temp);
176     m_responseBuffer->Push(raw);
177
178     // parse while you can
179     while(m_responseBuffer->Ready())
180     {
181         std::unique_ptr<IReceiver> receiver;
182         if (m_interface == SERVICE_SOCKET_CKM_STORAGE)
183             receiver.reset(new StorageReceiver(*m_responseBuffer, m_responseMap));
184         else if (m_interface == SERVICE_SOCKET_OCSP)
185             receiver.reset(new OcspReceiver(*m_responseBuffer, m_responseMap));
186         else {
187             LogError("Unknown service " << m_interface);
188             serviceError(CKM_API_ERROR_RECV_FAILED);
189             return;
190         }
191         receiver->parseResponse();
192
193         if (m_responseMap.empty())
194             watch(m_sendQueue.empty()?0:POLLOUT);
195     }
196 }
197
198 void Service::watch(short events)
199 {
200     if (0 == events)
201         m_descriptors.remove(m_socket->Get(), false);
202     else
203         m_descriptors.add(m_socket->Get(),
204                           events,
205                           [this](int sock, short revents){ socketReady(sock, revents); });
206 }
207
208 } // namespace CKM