Replace some functions with thread safe version.
[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
41 #include <client-common.h>
42
43 IMPLEMENT_SAFE_SINGLETON(CKM::Log::LogSystem);
44
45 namespace {
46
47 const int POLL_TIMEOUT = 8000;
48
49 void centKeyClientEnableLogSystem(void) {
50     CKM::Singleton<CKM::Log::LogSystem>::Instance().SetTag("CKM_CLIENT");
51 }
52
53 int waitForSocket(int sock, int event, int timeout) {
54     int retval;
55     pollfd desc[1];
56     desc[0].fd = sock;
57     desc[0].events = event;
58
59     while((-1 == (retval = poll(desc, 1, timeout))) && (errno == EINTR)) {
60         timeout >>= 1;
61         errno = 0;
62     }
63
64     if (0 == retval) {
65         LogDebug("Poll timeout");
66     } else if (-1 == retval) {
67         int err = errno;
68         LogError("Error in poll: " << CKM::GetErrnoString(err));
69     }
70     return retval;
71 }
72
73 } // namespace anonymous
74
75 namespace CKM {
76
77
78 int connectSocket(int& sock, char const * const interface) {
79     sockaddr_un clientAddr;
80     int flags;
81
82     if (sock != -1) // guard
83         close(sock);
84
85     sock = socket(AF_UNIX, SOCK_STREAM, 0);
86     if (sock < 0) {
87         int err = errno;
88         LogError("Error creating socket: " << GetErrnoString(err));
89         return CKM_API_ERROR_SOCKET;
90     }
91
92     if ((flags = fcntl(sock, F_GETFL, 0)) < 0 ||
93         fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
94     {
95         int err = errno;
96         LogError("Error in fcntl: " << GetErrnoString(err));
97         return CKM_API_ERROR_SOCKET;
98     }
99
100     memset(&clientAddr, 0, sizeof(clientAddr));
101
102     clientAddr.sun_family = AF_UNIX;
103
104     if (strlen(interface) >= sizeof(clientAddr.sun_path)) {
105         LogError("Error: interface name " << interface << "is too long. Max len is:" <<
106                  sizeof(clientAddr.sun_path));
107         return CKM_API_ERROR_SOCKET;
108     }
109
110     strcpy(clientAddr.sun_path, interface);
111
112     LogDebug("ClientAddr.sun_path = " << interface);
113
114     int retval = TEMP_FAILURE_RETRY(
115         connect(sock, (struct sockaddr*)&clientAddr, SUN_LEN(&clientAddr)));
116     if ((retval == -1) && (errno == EINPROGRESS)) {
117         if (0 >= waitForSocket(sock, POLLOUT, POLL_TIMEOUT)) {
118             LogError("Error in waitForSocket.");
119             return CKM_API_ERROR_SOCKET;
120         }
121         int error = 0;
122         socklen_t len = sizeof(error);
123         retval = getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len);
124
125         if (-1 == retval) {
126             int err = errno;
127             LogError("Error in getsockopt: " << GetErrnoString(err));
128             return CKM_API_ERROR_SOCKET;
129         }
130
131         if (error == EACCES) {
132             LogError("Access denied");
133             return CKM_API_ERROR_ACCESS_DENIED;
134         }
135
136         if (error != 0) {
137             LogError("Error in connect: " << GetErrnoString(error));
138             return CKM_API_ERROR_SOCKET;
139         }
140
141         return CKM_API_SUCCESS;
142     }
143
144     if (-1 == retval) {
145         int err = errno;
146         LogError("Error connecting socket: " << GetErrnoString(err));
147         if (err == EACCES)
148             return CKM_API_ERROR_ACCESS_DENIED;
149         return CKM_API_ERROR_SOCKET;
150     }
151
152     return CKM_API_SUCCESS;
153 }
154
155 int sendToServer(char const * const interface, const RawBuffer &send, MessageBuffer &recv) {
156     int ret;
157     SockRAII sock;
158     ssize_t done = 0;
159     char buffer[2048];
160
161     if (CKM_API_SUCCESS != (ret = sock.Connect(interface))) {
162         LogError("Error in SockRAII");
163         return ret;
164     }
165
166     while ((send.size() - done) > 0) {
167         if (0 >= waitForSocket(sock.Get(), POLLOUT, POLL_TIMEOUT)) {
168             LogError("Error in poll(POLLOUT)");
169             return CKM_API_ERROR_SOCKET;
170         }
171         ssize_t temp = TEMP_FAILURE_RETRY(write(sock.Get(), &send[done], send.size() - done));
172         if (-1 == temp) {
173             int err = errno;
174             LogError("Error in write: " << GetErrnoString(err));
175             return CKM_API_ERROR_SOCKET;
176         }
177         done += temp;
178     }
179
180     do {
181         if (0 >= waitForSocket(sock.Get(), POLLIN, POLL_TIMEOUT)) {
182             LogError("Error in poll(POLLIN)");
183             return CKM_API_ERROR_SOCKET;
184         }
185         ssize_t temp = TEMP_FAILURE_RETRY(read(sock.Get(), buffer, 2048));
186         if (-1 == temp) {
187             int err = errno;
188             LogError("Error in read: " << GetErrnoString(err));
189             return CKM_API_ERROR_SOCKET;
190         }
191
192         if (0 == temp) {
193             LogError("Read return 0/Connection closed by server(?)");
194             return CKM_API_ERROR_SOCKET;
195         }
196
197         RawBuffer raw(buffer, buffer+temp);
198         recv.Push(raw);
199     } while(!recv.Ready());
200     return CKM_API_SUCCESS;
201 }
202
203 int try_catch(const std::function<int()>& func)
204 {
205     try {
206         return func();
207     } catch (MessageBuffer::Exception::Base &e) {
208         LogError("CKM::MessageBuffer::Exception " << e.DumpToString());
209     } catch (std::exception &e) {
210         LogError("STD exception " << e.what());
211     } catch (...) {
212         LogError("Unknown exception occured");
213     }
214     return CKM_API_ERROR_UNKNOWN;
215 }
216
217 void try_catch_async(const std::function<void()>& func, const std::function<void(int)>& error)
218 {
219     try {
220         func();
221     } catch (const MessageBuffer::Exception::Base& e) {
222         LogError("CKM::MessageBuffer::Exception " << e.DumpToString());
223         error(CKM_API_ERROR_BAD_REQUEST);
224     } catch (const std::exception& e) {
225         LogError("STD exception " << e.what());
226         error(CKM_API_ERROR_UNKNOWN);
227     } catch (...) {
228         LogError("Unknown exception occured");
229         error(CKM_API_ERROR_UNKNOWN);
230     }
231 }
232
233 } // namespace CKM
234
235 static void init_lib(void) __attribute__ ((constructor));
236 static void init_lib(void)
237 {
238     centKeyClientEnableLogSystem();
239 }
240
241 static void fini_lib(void) __attribute__ ((destructor));
242 static void fini_lib(void)
243 {
244
245 }
246