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