Removed compiler warning - comparison between signed and unsigned integers
[platform/core/system/sensord.git] / src / shared / csocket.cpp
1 /*
2  * libsensord-share
3  *
4  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
20 #include <csocket.h>
21 #include <attr/xattr.h>
22 #include <sys/stat.h>
23
24
25 csocket::csocket()
26 : m_sock_fd(-1)
27 , m_sock_type(SOCK_STREAM)
28 , m_send_flags(MSG_NOSIGNAL)
29 , m_recv_flags(MSG_NOSIGNAL)
30 {
31         memset(&m_addr, 0, sizeof(m_addr));
32 }
33
34
35 csocket::csocket(int sock_fd)
36 : m_send_flags(MSG_NOSIGNAL)
37 , m_recv_flags(MSG_NOSIGNAL)
38 {
39         m_sock_fd = sock_fd;
40         set_sock_type();
41         memset(&m_addr, 0, sizeof(m_addr));
42 }
43
44
45 csocket::csocket(const csocket &sock)
46 {
47         if (this == &sock)
48                 return;
49
50         m_sock_fd = sock.m_sock_fd;
51         m_sock_type = sock.m_sock_type;
52         m_send_flags = sock.m_send_flags;
53         m_recv_flags = sock.m_recv_flags;
54
55         memcpy(&m_addr, &sock.m_addr, sizeof(sockaddr_un));
56 }
57
58 csocket::~csocket() { }
59
60 bool csocket::create(int sock_type)
61 {
62         m_sock_fd = socket(AF_UNIX, sock_type, 0);
63
64         if (!is_valid()) {
65                 ERR("Failed to create socket for %s, errno : %d , errstr : %s ",
66                         get_client_name(), errno, strerror(errno));
67                 return false;
68         }
69
70         m_sock_type = sock_type;
71
72         return true;
73 }
74
75 bool csocket::bind (const char *sock_path)
76 {
77         int length;
78         mode_t socket_mode;
79
80         if (!is_valid()) {
81                 ERR("%s's socket is invalid", get_client_name());
82                 return false;
83         }
84
85         if((fsetxattr(m_sock_fd, "security.SMACK64IPOUT", "@", 2, 0)) < 0) {
86                 if(errno != EOPNOTSUPP) {
87                         close();
88                         ERR("security.SMACK64IPOUT error = [%d][%s]\n", errno, strerror(errno) );
89                         return false;
90                 }
91         }
92
93         if((fsetxattr(m_sock_fd, "security.SMACK64IPIN", "*", 2, 0)) < 0) {
94                 if(errno != EOPNOTSUPP) {
95                         close();
96                         ERR("security.SMACK64IPIN error  = [%d][%s]\n", errno, strerror(errno) );
97                         return false;
98                 }
99         }
100
101         if (!access(sock_path, F_OK)) {
102                 unlink(sock_path);
103         }
104
105         m_addr.sun_family = AF_UNIX;
106         strcpy(m_addr.sun_path, sock_path);
107
108         length = strlen(m_addr.sun_path) + sizeof(m_addr.sun_family);
109
110         if (::bind(m_sock_fd, (struct sockaddr *)&m_addr, length) < 0) {
111                 ERR("Binding failed for socket(%d), errno : %d , errstr : %s", m_sock_fd, errno, strerror(errno));
112                 close();
113                 return false;
114         }
115
116         socket_mode = ( S_IRWXU | S_IRWXG | S_IRWXO );
117         if (chmod(sock_path, socket_mode) < 0) {
118                 ERR("chmod failed for socket(%d), errno : %d , errstr : %s", m_sock_fd, errno, strerror(errno));
119                 close();
120                 return false;
121         }
122
123         return true;
124 }
125
126 bool csocket::listen(const int max_connections)
127 {
128         if (!is_valid()) {
129                 ERR("Socket(%d) is invalid", m_sock_fd);
130                 return false;
131         }
132
133         if (::listen(m_sock_fd, max_connections) < 0) {
134                 ERR("Listening failed for socket(%d), errno : %d , errstr : %s", m_sock_fd, errno, strerror(errno));
135                 close();
136                 return false;
137         }
138
139         return true;
140 }
141
142 bool csocket::accept(csocket& client_socket) const
143 {
144         int addr_length = sizeof(m_addr);
145         int err = 0;
146
147         do {
148                 client_socket.m_sock_fd = ::accept(m_sock_fd, (sockaddr *)&m_addr, (socklen_t *)&addr_length);
149                 if (!client_socket.is_valid())
150                         err = errno;
151         } while (err == EINTR);
152
153         if (!client_socket.is_valid()) {
154                 ERR("Accept failed for socket(%d), errno : %d , errstr : %s", m_sock_fd, errno, strerror(errno));
155                 return false;
156         }
157
158         return true;
159 }
160
161 ssize_t csocket::send_for_seqpacket(void const* buffer, size_t size) const
162 {
163         ssize_t err, len;
164
165         do {
166                 len = ::send(m_sock_fd, buffer, size, m_send_flags);
167                 err = len < 0 ? errno : 0;
168         } while (err == EINTR);
169
170         if (err) {
171                 ERR("send(%d, 0x%x, %d, 0x%x) = %d cause = %s(%d)",
172                         m_sock_fd, buffer, size, m_send_flags, len, strerror(errno), errno);
173         }
174
175         return err == 0 ? len : -err;
176 }
177
178 ssize_t csocket::recv_for_seqpacket(void* buffer, size_t size) const
179 {
180     ssize_t err, len;
181
182         do {
183         len = ::recv(m_sock_fd, buffer, size, m_recv_flags);
184
185                 if (len > 0) {
186                         err = 0;
187                 } else if (len == 0) {
188                         ERR("recv(%d, 0x%p , %d) = %d, because the peer performed shutdown!",
189                                 m_sock_fd, buffer, size, len);
190                         err = 1;
191                 } else {
192                         err = errno;
193                 }
194     } while (err == EINTR);
195
196         if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
197                 DBG("recv(%d, 0x%x, %d, 0x%x) = %d cause = %s(%d)",
198                         m_sock_fd, buffer, size, m_recv_flags, len, strerror(errno), errno);
199                 return 0;
200         }
201
202         if (err) {
203                 ERR("recv(%d, 0x%x, %d, 0x%x) = %d cause = %s(%d)",
204                         m_sock_fd, buffer, size, m_recv_flags, len, strerror(errno), errno);
205         }
206
207     return err == 0 ? len : -err;
208 }
209
210
211 ssize_t csocket::send_for_stream(void const* buffer, size_t size) const
212 {
213         ssize_t len;
214         ssize_t err = 0;
215         size_t total_sent_size = 0;
216
217         do {
218                 len = ::send(m_sock_fd, buffer + total_sent_size, size - total_sent_size, m_send_flags);
219
220                 if (len >= 0) {
221                         total_sent_size += len;
222                         err = 0;
223                 } else {
224                         ERR("send(%d, 0x%p + %d, %d - %d) = %d, error: %s(%d) for %s",
225                                 m_sock_fd, buffer, total_sent_size, size, total_sent_size,
226                                 len, strerror(errno), errno, get_client_name());
227
228                         if (errno != EINTR) {
229                                 err = errno;
230                                 break;
231                         }
232                 }
233         } while (total_sent_size < size);
234
235         return err == 0 ? total_sent_size : -err;
236 }
237
238 ssize_t csocket::recv_for_stream(void* buffer, size_t size) const
239 {
240         ssize_t len;
241         ssize_t err = 0;
242         size_t total_recv_size = 0;
243
244         do {
245                 len = ::recv(m_sock_fd, buffer + total_recv_size, size - total_recv_size, m_recv_flags);
246
247                 if (len > 0) {
248                         total_recv_size += len;
249                 } else if (len == 0) {
250                         ERR("recv(%d, 0x%p + %d, %d - %d) = %d, because the peer of %s performed shutdown!",
251                                 m_sock_fd, buffer, total_recv_size, size, total_recv_size, len, get_client_name());
252                         err = 1;
253                         break;
254                 } else {
255                         ERR("recv(%d, 0x%p + %d, %d - %d) = %d, error: %s(%d) for %s",
256                                 m_sock_fd, buffer, total_recv_size, size, total_recv_size,
257                                 len, strerror(errno), errno, get_client_name());
258
259                         if (errno != EINTR) {
260                                 err = errno;
261                                 break;
262                         }
263                 }
264         } while (total_recv_size < size);
265
266         return err == 0 ? total_recv_size : -err;
267 }
268
269
270 ssize_t csocket::send(void const* buffer, size_t size) const
271 {
272         if (m_sock_type == SOCK_STREAM)
273                 return send_for_stream(buffer, size);
274
275         return send_for_seqpacket(buffer, size);
276 }
277
278 ssize_t csocket::recv(void* buffer, size_t size) const
279 {
280         if (m_sock_type == SOCK_STREAM)
281                 return recv_for_stream(buffer, size);
282
283         return recv_for_seqpacket(buffer, size);
284 }
285
286 bool csocket::connect(const char *sock_path)
287 {
288         const int TIMEOUT = 5;
289         fd_set write_fds;
290         struct timeval tv;
291         int addr_len;
292         bool prev_blocking_mode;
293
294         if (!is_valid()) {
295                 ERR("%s's socket is invalid", get_client_name());
296                 return false;
297         }
298
299         prev_blocking_mode = is_blocking_mode();
300
301         set_blocking_mode(false);
302
303         m_addr.sun_family = AF_UNIX;
304         strcpy(m_addr.sun_path, sock_path);
305         addr_len = strlen(m_addr.sun_path) + sizeof(m_addr.sun_family);
306
307         if (::connect(m_sock_fd,(sockaddr *) &m_addr, addr_len) < 0) {
308                 ERR("connect error: %s sock_fd: %d\n for %s", strerror(errno), m_sock_fd, get_client_name());
309                 return false;
310         }
311
312         FD_ZERO(&write_fds);
313         FD_SET(m_sock_fd, &write_fds);
314         tv.tv_sec = TIMEOUT;
315         tv.tv_usec = 0;
316
317         int ret;
318
319         ret = select(m_sock_fd + 1, NULL, &write_fds, NULL, &tv);
320
321         if (ret == -1) {
322                 ERR("select error: %s sock_fd: %d\n for %s", strerror(errno), m_sock_fd, get_client_name());
323                 close();
324                 return false;
325         } else if (!ret) {
326                 ERR("select timeout: %d seconds elapsed for %s", tv.tv_sec, get_client_name());
327                 close();
328                 return true;
329         }
330
331         if (!FD_ISSET(m_sock_fd, &write_fds)) {
332                 ERR("select failed for %s, nothing to write, m_sock_fd : %d", get_client_name(), m_sock_fd);
333                 close();
334                 return false;
335         }
336
337         int so_error;
338         socklen_t len = sizeof(so_error);
339
340         if (getsockopt(m_sock_fd, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) {
341                 ERR("getsockopt failed for %s, m_sock_fd : %d, errno : %d , errstr : %s",
342                         get_client_name(), m_sock_fd, errno, strerror(errno));
343                 close();
344                 return false;
345         }
346
347         if (so_error) {
348                 ERR("SO_ERROR occurred for %s, m_sock_fd : %d, so_error : %d",
349                         get_client_name(), m_sock_fd, so_error);
350                 close();
351                 return false;
352         }
353
354         if (prev_blocking_mode)
355                 set_blocking_mode(true);
356
357         return true;
358 }
359
360 bool csocket::set_blocking_mode(bool blocking)
361 {
362         int flags;
363
364         flags = fcntl(m_sock_fd, F_GETFL);
365
366         if (flags == -1) {
367                 ERR("fcntl(F_GETFL) failed for %s, m_sock_fd: %d, errno : %d , errstr : %s", get_client_name(), m_sock_fd, errno, strerror(errno));
368                 return false;
369         }
370
371         flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
372
373         flags = fcntl(m_sock_fd, F_SETFL, flags);
374
375         if (flags == -1) {
376                 ERR("fcntl(F_SETFL) failed for %s, m_sock_fd: %d, errno : %d , errstr : %s", get_client_name(), m_sock_fd, errno, strerror(errno));
377                 return false;
378         }
379
380         return true;
381 }
382
383
384 bool csocket::set_sock_type(void)
385 {
386         socklen_t opt_len;
387         int sock_type;
388
389         opt_len = sizeof(sock_type);
390
391         if (getsockopt(m_sock_fd, SOL_SOCKET, SO_TYPE, &sock_type, &opt_len) < 0) {
392            ERR("getsockopt(SOL_SOCKET, SO_TYPE) failed for %s, m_sock_fd: %d, errno : %d , errstr : %s", get_client_name(), m_sock_fd, errno, strerror(errno));
393            return false;
394         }
395
396         m_sock_type = sock_type;
397         return true;
398 }
399
400 bool csocket::set_connection_mode(void)
401 {
402         struct timeval tv;
403         const int TIMEOUT = 5;
404
405         set_blocking_mode(true);
406
407         tv.tv_sec = TIMEOUT;
408         tv.tv_usec = 0;
409
410         if(setsockopt(m_sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
411                 ERR("Set SO_RCVTIMEO failed for %s, m_sock_fd : %d, errno : %d , errstr : %s",
412                         get_client_name(), m_sock_fd, errno, strerror(errno));
413                 close();
414                 return false;
415         }
416
417         m_send_flags = MSG_NOSIGNAL;
418         m_recv_flags = MSG_NOSIGNAL;
419
420         return true;
421 }
422
423 bool csocket::set_transfer_mode(void)
424 {
425         set_blocking_mode(false);
426
427
428         m_send_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
429         m_recv_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
430
431         return true;
432 }
433
434 bool csocket::is_blocking_mode(void)
435 {
436         int flags;
437
438         flags = fcntl(m_sock_fd, F_GETFL);
439
440         if (flags == -1) {
441                 ERR("fcntl(F_GETFL) failed for %s, m_sock_fd: %d, errno : %d , errstr : %s", get_client_name(), m_sock_fd, errno, strerror(errno));
442                 return false;
443         }
444
445         return !(flags & O_NONBLOCK);
446 }
447
448
449 bool csocket::is_valid(void) const
450 {
451         return (m_sock_fd >= 0);
452 }
453
454 int csocket::get_socket_fd(void) const
455 {
456         return m_sock_fd;
457 }
458
459 bool csocket::close(void)
460 {
461         if (m_sock_fd >= 0) {
462                 if (::close(m_sock_fd) < 0) {
463                         ERR("Socket(%d) close failed, errno : %d , errstr : %s", m_sock_fd, errno, strerror(errno));
464                         return false;
465                 }
466                 m_sock_fd = -1;
467         }
468
469         return true;
470 }