Extract communication functions to common library
[platform/core/security/security-manager.git] / src / common / connection.cpp
1 /*
2  *  Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Rafal Krypa <r.krypa@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18 /*
19  * @file        connection.cpp
20  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
21  * @author      Lukasz Kostyra (l.kostyra@samsung.com)
22  * @version     1.0
23  * @brief       This file is implementation of common connection functions.
24  */
25
26 #include "connection.h"
27 #include <fcntl.h>
28 #include <poll.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <sys/smack.h>
33 #include <sys/xattr.h>
34 #include <linux/xattr.h>
35 #include <unistd.h>
36
37 #include <dpl/log/log.h>
38 #include <dpl/serialization.h>
39
40 #include <message-buffer.h>
41
42 #include <protocols.h>
43
44 namespace {
45
46 const int POLL_TIMEOUT = -1;
47
48 int waitForSocket(int sock, int event, int timeout) {
49     int retval;
50     pollfd desc[1];
51     desc[0].fd = sock;
52     desc[0].events = event;
53
54     while((-1 == (retval = poll(desc, 1, timeout))) && (errno == EINTR)) {
55         timeout >>= 1;
56         errno = 0;
57     }
58
59     if (0 == retval) {
60         LogDebug("Poll timeout");
61     } else if (-1 == retval) {
62         int err = errno;
63         LogError("Error in poll: " << strerror(err));
64     }
65     return retval;
66 }
67
68 class SockRAII {
69 public:
70     SockRAII()
71       : m_sock(-1)
72     {}
73
74     virtual ~SockRAII() {
75         if (m_sock > -1)
76             close(m_sock);
77     }
78
79     int Connect(char const * const interface) {
80         sockaddr_un clientAddr;
81         int flags;
82
83         if (m_sock != -1) // guard
84             close(m_sock);
85
86         m_sock = socket(AF_UNIX, SOCK_STREAM, 0);
87         if (m_sock < 0) {
88             int err = errno;
89             LogError("Error creating socket: " << strerror(err));
90             return SECURITY_MANAGER_API_ERROR_SOCKET;
91         }
92
93         if ((flags = fcntl(m_sock, F_GETFL, 0)) < 0 ||
94             fcntl(m_sock, F_SETFL, flags | O_NONBLOCK) < 0)
95         {
96             int err = errno;
97             LogError("Error in fcntl: " << strerror(err));
98             return SECURITY_MANAGER_API_ERROR_SOCKET;
99         }
100
101         memset(&clientAddr, 0, sizeof(clientAddr));
102
103         clientAddr.sun_family = AF_UNIX;
104
105         if (strlen(interface) >= sizeof(clientAddr.sun_path)) {
106             LogError("Error: interface name " << interface << "is too long. Max len is:" << sizeof(clientAddr.sun_path));
107             return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE;
108         }
109
110         strcpy(clientAddr.sun_path, interface);
111
112         LogDebug("ClientAddr.sun_path = " << interface);
113
114         int retval = TEMP_FAILURE_RETRY(connect(m_sock, (struct sockaddr*)&clientAddr, SUN_LEN(&clientAddr)));
115         if ((retval == -1) && (errno == EINPROGRESS)) {
116             if (0 >= waitForSocket(m_sock, POLLIN, POLL_TIMEOUT)) {
117                 LogError("Error in waitForSocket.");
118                 return SECURITY_MANAGER_API_ERROR_SOCKET;
119             }
120             int error = 0;
121             socklen_t len = sizeof(error);
122             retval = getsockopt(m_sock, SOL_SOCKET, SO_ERROR, &error, &len);
123
124             if (-1 == retval) {
125                 int err = errno;
126                 LogError("Error in getsockopt: " << strerror(err));
127                 return SECURITY_MANAGER_API_ERROR_SOCKET;
128             }
129
130             if (error == EACCES) {
131                 LogError("Access denied");
132                 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
133             }
134
135             if (error != 0) {
136                 LogError("Error in connect: " << strerror(error));
137                 return SECURITY_MANAGER_API_ERROR_SOCKET;
138             }
139
140             return SECURITY_MANAGER_API_SUCCESS;
141         }
142
143         if (-1 == retval) {
144             int err = errno;
145             LogError("Error connecting socket: " << strerror(err));
146             if (err == EACCES)
147                 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
148             if (err == ENOTSOCK)
149                 return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE;
150             return SECURITY_MANAGER_API_ERROR_SOCKET;
151         }
152
153         return SECURITY_MANAGER_API_SUCCESS;
154     }
155
156     int Get() {
157         return m_sock;
158     }
159
160 private:
161     int m_sock;
162 };
163
164 } // namespace anonymous
165
166 namespace SecurityManager {
167
168 int sendToServer(char const * const interface, const RawBuffer &send, MessageBuffer &recv) {
169     int ret;
170     SockRAII sock;
171     ssize_t done = 0;
172     char buffer[2048];
173
174     if (SECURITY_MANAGER_API_SUCCESS != (ret = sock.Connect(interface))) {
175         LogError("Error in SockRAII");
176         return ret;
177     }
178
179     while ((send.size() - done) > 0) {
180         if (0 >= waitForSocket(sock.Get(), POLLOUT, POLL_TIMEOUT)) {
181             LogError("Error in poll(POLLOUT)");
182             return SECURITY_MANAGER_API_ERROR_SOCKET;
183         }
184         ssize_t temp = TEMP_FAILURE_RETRY(write(sock.Get(), &send[done], send.size() - done));
185         if (-1 == temp) {
186             int err = errno;
187             LogError("Error in write: " << strerror(err));
188             return SECURITY_MANAGER_API_ERROR_SOCKET;
189         }
190         done += temp;
191     }
192
193     do {
194         if (0 >= waitForSocket(sock.Get(), POLLIN, POLL_TIMEOUT)) {
195             LogError("Error in poll(POLLIN)");
196             return SECURITY_MANAGER_API_ERROR_SOCKET;
197         }
198         ssize_t temp = TEMP_FAILURE_RETRY(read(sock.Get(), buffer, 2048));
199         if (-1 == temp) {
200             int err = errno;
201             LogError("Error in read: " << strerror(err));
202             return SECURITY_MANAGER_API_ERROR_SOCKET;
203         }
204
205         if (0 == temp) {
206             LogError("Read return 0/Connection closed by server(?)");
207             return SECURITY_MANAGER_API_ERROR_SOCKET;
208         }
209
210         RawBuffer raw(buffer, buffer+temp);
211         recv.Push(raw);
212     } while(!recv.Ready());
213     return SECURITY_MANAGER_API_SUCCESS;
214 }
215
216 int sendToServerAncData(char const * const interface, const RawBuffer &send, struct msghdr &hdr) {
217     int ret;
218     SockRAII sock;
219     ssize_t done = 0;
220
221     if (SECURITY_MANAGER_API_SUCCESS != (ret = sock.Connect(interface))) {
222         LogError("Error in SockRAII");
223         return ret;
224     }
225
226     while ((send.size() - done) > 0) {
227         if (0 >= waitForSocket(sock.Get(), POLLOUT, POLL_TIMEOUT)) {
228             LogError("Error in poll(POLLOUT)");
229             return SECURITY_MANAGER_API_ERROR_SOCKET;
230         }
231         ssize_t temp = TEMP_FAILURE_RETRY(write(sock.Get(), &send[done], send.size() - done));
232         if (-1 == temp) {
233             int err = errno;
234             LogError("Error in write: " << strerror(err));
235             return SECURITY_MANAGER_API_ERROR_SOCKET;
236         }
237         done += temp;
238     }
239
240     if (0 >= waitForSocket(sock.Get(), POLLIN, POLL_TIMEOUT)) {
241         LogError("Error in poll(POLLIN)");
242         return SECURITY_MANAGER_API_ERROR_SOCKET;
243     }
244
245     ssize_t temp = TEMP_FAILURE_RETRY(recvmsg(sock.Get(), &hdr, MSG_CMSG_CLOEXEC));
246
247     if (temp < 0) {
248         int err = errno;
249         LogError("Error in recvmsg(): " << strerror(err) << " errno: " << err);
250         return SECURITY_MANAGER_API_ERROR_SOCKET;
251     }
252
253     if (0 == temp) {
254         LogError("Read return 0/Connection closed by server(?)");
255         return SECURITY_MANAGER_API_ERROR_SOCKET;
256     }
257
258     return SECURITY_MANAGER_API_SUCCESS;
259 }
260
261 } // namespace SecurityManager