Modify the setting value of POLL_TIMEOUT
[platform/core/security/key-manager.git] / src / manager / client / client-common.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        client-common.cpp
18  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
19  * @author      Zofia Abramowska (z.abramowska@samsung.com)
20  * @version     1.0
21  * @brief       This file is implementation of client-common functions.
22  */
23
24 #include <fcntl.h>
25 #include <poll.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <unistd.h>
30
31 #include <dpl/errno_string.h>
32 #include <dpl/log/log.h>
33 #include <dpl/serialization.h>
34 #include <dpl/singleton.h>
35 #include <dpl/singleton_safe_impl.h>
36
37 #include <message-buffer.h>
38
39 #include <ckm/ckm-error.h>
40 #include <ckmc/ckmc-type.h>
41 #include <protocols.h>
42 #include <client-common.h>
43
44 IMPLEMENT_SAFE_SINGLETON(CKM::Log::LogSystem);
45
46 namespace {
47
48 const int POLL_TIMEOUT = 600000;
49
50 void centKeyClientEnableLogSystem(void) {
51     CKM::Singleton<CKM::Log::LogSystem>::Instance().SetTag("CKM_CLIENT");
52 }
53
54 } // namespace anonymous
55
56 namespace CKM {
57
58 SockRAII::SockRAII() : m_sock(-1) {}
59
60 SockRAII::~SockRAII()
61 {
62     Disconnect();
63 }
64
65 int SockRAII::Connect(char const * const interface)
66 {
67     int sock = -1;
68     try
69     {
70         if(!interface) {
71             LogError("No valid interface address given.");
72             throw CKM_API_ERROR_INPUT_PARAM;
73         }
74
75         sock = socket(AF_UNIX, SOCK_STREAM, 0);
76         if(sock < 0) {
77             LogError("Error creating socket: " << CKM::GetErrnoString(errno));
78             throw CKM_API_ERROR_SOCKET;
79         }
80
81         // configure non-blocking mode
82         int flags;
83         if((flags = fcntl(sock, F_GETFL, 0)) < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
84         {
85             LogError("Error in fcntl: " << CKM::GetErrnoString(errno));
86             throw CKM_API_ERROR_SOCKET;
87         }
88
89         sockaddr_un clientAddr;
90         memset(&clientAddr, 0, sizeof(clientAddr));
91         clientAddr.sun_family = AF_UNIX;
92         if(strlen(interface) >= sizeof(clientAddr.sun_path))
93         {
94             LogError("Error: interface name " << interface << "is too long. Max len is:" << sizeof(clientAddr.sun_path));
95             throw CKM_API_ERROR_INPUT_PARAM;
96         }
97
98         strcpy(clientAddr.sun_path, interface);
99         LogDebug("ClientAddr.sun_path = " << interface);
100
101         int retval = TEMP_FAILURE_RETRY(::connect(sock, (struct sockaddr*)&clientAddr, SUN_LEN(&clientAddr)));
102         if(-1 == retval)
103         {
104             switch(errno)
105             {
106                 case EACCES:
107                     LogError("Access denied");
108                     throw CKM_API_ERROR_ACCESS_DENIED;
109                     break;
110
111                 case EINPROGRESS:
112                 {
113                     if( 0 >= WaitForSocket(POLLOUT, POLL_TIMEOUT))
114                     {
115                         LogError("Error in WaitForSocket.");
116                         throw CKM_API_ERROR_SOCKET;
117                     }
118
119                     int error = 0;
120                     size_t len = sizeof(error);
121                     retval = getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len);
122                     if(-1 == retval)
123                     {
124                         LogError("Error in getsockopt: " << CKM::GetErrnoString(error));
125                         throw CKM_API_ERROR_SOCKET;
126                     }
127
128                     if(error == EACCES)
129                     {
130                         LogError("Access denied");
131                         throw CKM_API_ERROR_ACCESS_DENIED;
132                     }
133
134                     if(error != 0)
135                     {
136                         LogError("Error in connect: " << CKM::GetErrnoString(error));
137                         throw CKM_API_ERROR_SOCKET;
138                     }
139
140                     break;
141                 }
142
143                 default:
144                     LogError("Error connecting socket: " << CKM::GetErrnoString(errno));
145                     throw CKM_API_ERROR_SOCKET;
146                     break;
147             }
148         }
149     }
150     catch(int & error_code) {
151         if(sock > 0)
152             close(sock);
153         return error_code;
154     }
155
156     m_sock = sock;
157     return CKM_API_SUCCESS;
158 }
159
160 bool SockRAII::isConnected() const {
161     return (m_sock != -1);
162 }
163
164 void SockRAII::Disconnect() {
165     if( isConnected() )
166         close(m_sock);
167     m_sock = -1;
168 }
169
170 int SockRAII::WaitForSocket(int event, int timeout)
171 {
172     int retval;
173     pollfd desc[1];
174     desc[0].fd = m_sock;
175     desc[0].events = event;
176
177     while((-1 == (retval = poll(desc, 1, timeout))) && (errno == EINTR)) {
178         timeout >>= 1;
179         errno = 0;
180     }
181
182     if (0 == retval) {
183         LogDebug("Poll timeout");
184     } else if(-1 == retval) {
185         LogError("Error in poll: " << CKM::GetErrnoString(errno));
186     }
187     return retval;
188 }
189
190 int SockRAII::Get() const {
191     return m_sock;
192 }
193
194 } // namespace anonymous
195
196 namespace CKM {
197
198 AliasSupport::AliasSupport(const Alias &alias)
199 {
200     std::size_t separator_pos = alias.rfind(CKM::LABEL_NAME_SEPARATOR);
201     if(separator_pos == Alias::npos)
202     {
203         m_label.clear();
204         m_name = alias;
205     } else {
206         m_label = alias.substr(0, separator_pos);
207         m_name = alias.substr(separator_pos + strlen(CKM::LABEL_NAME_SEPARATOR));
208     }
209 }
210
211 Alias AliasSupport::merge(const Label &label, const Name &name)
212 {
213     if(label.empty())
214         return name;
215
216     std::stringstream output;
217     output << label << std::string(CKM::LABEL_NAME_SEPARATOR) << name;
218     return output.str();
219 }
220
221 const Name & AliasSupport::getName() const {
222     return m_name;
223 }
224
225 const Label & AliasSupport::getLabel() const {
226     return m_label;
227 }
228
229 bool AliasSupport::isLabelEmpty() const {
230     return m_label.empty();
231 }
232
233 ServiceConnection::ServiceConnection(char const * const service_interface) {
234     if(service_interface)
235         m_service_interface = std::string(service_interface);
236 }
237
238 int ServiceConnection::processRequest( const CKM::RawBuffer &send_buf,
239                                        CKM::MessageBuffer &recv_buf) {
240     int ec;
241     if(CKM_API_SUCCESS != (ec = send(send_buf)))
242         return ec;
243
244     return receive(recv_buf);
245 }
246
247 int ServiceConnection::Connect()
248 {
249     // cleanup
250     if( isConnected() )
251         Disconnect();
252
253     return SockRAII::Connect(m_service_interface.c_str());
254 }
255
256 int ServiceConnection::send(const CKM::RawBuffer &send_buf)
257 {
258     if( ! isConnected() )
259     {
260         int ec;
261         if(CKM_API_SUCCESS != (ec = ServiceConnection::Connect()))
262         {
263             LogError("send failed, connect fail code: " << ec);
264             return ec;
265         }
266     }
267
268     int ec = CKM_API_SUCCESS;
269     ssize_t done = 0;
270     while((send_buf.size() - done) > 0)
271     {
272         if( 0 >= WaitForSocket(POLLOUT, POLL_TIMEOUT)) {
273             LogError("Error in WaitForSocket.");
274             ec = CKM_API_ERROR_SOCKET;
275             break;
276         }
277
278         ssize_t temp = TEMP_FAILURE_RETRY(write(Get(), &send_buf[done], send_buf.size() - done));
279         if(-1 == temp) {
280             LogError("Error in write: " << CKM::GetErrnoString(errno));
281             ec = CKM_API_ERROR_SOCKET;
282             break;
283         }
284
285         done += temp;
286     }
287
288     if(ec != CKM_API_SUCCESS)
289         Disconnect();
290
291     return ec;
292 }
293
294 int ServiceConnection::receive(CKM::MessageBuffer &recv_buf)
295 {
296     if( ! isConnected() )
297     {
298         LogError("Not connected!");
299         return CKM_API_ERROR_SOCKET;
300     }
301
302     int ec = CKM_API_SUCCESS;
303     const size_t c_recv_buf_len = 2048;
304     char buffer[c_recv_buf_len];
305     do
306     {
307         if( 0 >= WaitForSocket(POLLIN, POLL_TIMEOUT)) {
308             LogError("Error in WaitForSocket.");
309             ec = CKM_API_ERROR_SOCKET;
310             break;
311         }
312
313         ssize_t temp = TEMP_FAILURE_RETRY(read(Get(), buffer, sizeof(buffer)));
314         if(-1 == temp) {
315             LogError("Error in read: " << CKM::GetErrnoString(errno));
316             ec = CKM_API_ERROR_SOCKET;
317             break;
318         }
319
320         if (0 == temp) {
321             LogError("Read return 0/Connection closed by server(?)");
322             ec = CKM_API_ERROR_SOCKET;
323             break;
324         }
325
326         CKM::RawBuffer raw(buffer, buffer+temp);
327         recv_buf.Push(raw);
328     }
329     while(!recv_buf.Ready());
330
331     if(ec != CKM_API_SUCCESS)
332         Disconnect();
333
334     return ec;
335 }
336
337 ServiceConnection::~ServiceConnection()
338 {
339 }
340
341 int try_catch(const std::function<int()>& func)
342 {
343     int retval = CKM_API_ERROR_UNKNOWN;
344     try {
345         return func();
346     } catch (MessageBuffer::Exception::Base &e) {
347         LogError("CKM::MessageBuffer::Exception " << e.DumpToString());
348     } catch (std::exception &e) {
349         LogError("STD exception " << e.what());
350     } catch (...) {
351         LogError("Unknown exception occured");
352     }
353     return retval;
354 }
355
356 void try_catch_async(const std::function<void()>& func, const std::function<void(int)>& error)
357 {
358     try {
359         func();
360     } catch (const MessageBuffer::Exception::Base& e) {
361         LogError("CKM::MessageBuffer::Exception " << e.DumpToString());
362         error(CKM_API_ERROR_BAD_REQUEST);
363     } catch (const std::exception& e) {
364         LogError("STD exception " << e.what());
365         error(CKM_API_ERROR_UNKNOWN);
366     } catch (...) {
367         LogError("Unknown exception occured");
368         error(CKM_API_ERROR_UNKNOWN);
369     }
370 }
371
372 } // namespace CKM
373
374 static void init_lib(void) __attribute__ ((constructor));
375 static void init_lib(void)
376 {
377     centKeyClientEnableLogSystem();
378 }
379
380 static void fini_lib(void) __attribute__ ((destructor));
381 static void fini_lib(void)
382 {
383
384 }
385