2 * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <sys/socket.h>
19 #include <sys/ioctl.h>
20 #include <sys/types.h>
29 #include "MsgException.h"
30 #include "MsgIpcSocket.h"
31 #include "MsgUtilFile.h"
33 /*==================================================================================================
34 IMPLEMENTATION OF MsgIpcClientSocket - Member Functions
35 ==================================================================================================*/
36 MsgIpcClientSocket::MsgIpcClientSocket() : sockfd(-1), remotefd(-1), maxfd(-1)
42 msg_error_t MsgIpcClientSocket::connect(const char* path)
46 if (!path || strlen(path) > strlen(MSG_SOCKET_PATH)) {
47 THROW(MsgException::IPC_ERROR, "path is null");
50 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
53 THROW(MsgException::IPC_ERROR, "socket not opened %s", g_strerror(errno));
56 struct sockaddr_un serverSA = {0, };
57 serverSA.sun_family = AF_UNIX;
59 memset(serverSA.sun_path, 0x00, sizeof(serverSA.sun_path));
60 strncpy(serverSA.sun_path, path, sizeof(serverSA.sun_path)-1);
62 int len = strlen(serverSA.sun_path) + sizeof(serverSA.sun_family);
64 if (::connect(sockfd, (struct sockaddr *)&serverSA, len) == CUSTOM_SOCKET_ERROR) {
65 MSG_DEBUG("errno=[%d]", errno);
67 THROW(MsgException::SECURITY_ERROR, "cannot connect server %s", g_strerror(errno));
69 THROW(MsgException::IPC_ERROR, "cannot connect server %s", g_strerror(errno));
72 /* add fd for select() */
75 if (!wait_for_reply()) {
76 THROW(MsgException::IPC_ERROR, "wait_for_reply() error");
79 /* read remote fd for reg func */
81 unique_ptr<char*, void(*)(char**)> wrap(&rfd, unique_ptr_deleter);
87 THROW(MsgException::IPC_ERROR, "rfd is NULL %s", g_strerror(errno));
90 memcpy(&remotefd, rfd, sizeof(rlen));
92 MSG_DEBUG("Connected: client fd [%d] <----> remote fd [%d]", sockfd, remotefd);
100 msg_error_t MsgIpcClientSocket::close()
103 MSG_DEBUG("Client socket is not opened or already closed");
107 /* it means that client is going to close the connection.*/
108 int cmd = CLOSE_CONNECTION_BY_USER;
109 int len = sizeof(cmd);
113 memcpy(cmdbuf, &cmd, len);
115 MSG_DEBUG("client socket [%d] will be closed", sockfd);
117 sockfd = CUSTOM_SOCKET_ERROR;
122 void MsgIpcClientSocket::addfd(int fd)
124 MSG_DEBUG("%d added", fd);
130 int MsgIpcClientSocket::writen(const char *buf, unsigned int len)
137 nwrite = ::write(sockfd, (const void*) buf, nleft);
139 MSG_FATAL("writen: sockfd [%d] error [%s]", sockfd, g_strerror(errno));
141 } else if (nwrite == 0) {
151 int MsgIpcClientSocket::write(const char* buf, unsigned int len)
154 MSG_FATAL("sockfd is not opened [%d]", sockfd);
155 return CUSTOM_SOCKET_ERROR;
158 if (!buf || len == 0) {
159 MSG_FATAL("buf[%p] and len[%d] MUST NOT NULL", buf, len);
160 return CUSTOM_SOCKET_ERROR;
163 /* send the data size first */
164 int n = writen((const char*)&len, sizeof(len));
165 if (n != sizeof(len)) {
166 MSG_FATAL("WARNING: write header_size[%d] not matched [%zu]", n, sizeof(len));
167 return CUSTOM_SOCKET_ERROR;
170 /* send the data in subsequence */
171 n = writen(buf, len);
172 if ((unsigned int)n != len) {
173 MSG_FATAL("WARNING: write data_size[%d] not matched [%d]", n, len);
174 return CUSTOM_SOCKET_ERROR;
180 int MsgIpcClientSocket::readn(char *buf, unsigned int len)
188 memset(t_buf, 0x00, len);
189 nread = ::read(sockfd, t_buf, nleft);
191 MSG_FATAL("WARNING read value %d: %s", nread, g_strerror(errno));
193 } else if (nread == 0) {
197 if (nleft >= (unsigned int)nread)
202 memcpy(buf, t_buf, nread);
209 bool MsgIpcClientSocket::wait_for_reply()
216 MSG_FATAL("Invalid file description : [%d]", sockfd);
221 FD_SET(sockfd, &fds);
223 tv.tv_sec = 5; /* should be tuned */
226 MSG_DEBUG("wait for response [%d]", sockfd);
227 err = select(sockfd + 1, &fds, NULL, NULL, &tv);
229 MSG_FATAL("select error[%d] fd[%d]", errno, sockfd);
231 } else if (err == 0) {
232 MSG_FATAL("select timeout fd[%d]", sockfd);
236 if (FD_ISSET(sockfd, &fds)) return true;
242 /* what if the buf is shorter than data? */
243 int MsgIpcClientSocket::read(char** buf, unsigned int* len)
246 MSG_FATAL("socket is not opened [%d]", sockfd);
247 return CUSTOM_SOCKET_ERROR;
251 MSG_FATAL("rbuf and rlen MUST NOT NULL");
252 return CUSTOM_SOCKET_ERROR;
256 char clen[sizeof(int)] = {0};
258 /* read the data size first */
259 int n = readn(clen, sizeof(int));
260 memcpy(len, clen, sizeof(int));
262 if (n == CLOSE_CONNECTION_BY_SIGNAL) { /* if msgfw gets down, it signals to all IPC clients */
263 MSG_FATAL("sockfd [%d] CLOSE_CONNECTION_BY_SIGNAL", sockfd);
265 } else if (n != sizeof(int)) {
266 MSG_FATAL("WARNING: read header_size[%d] not matched [%zu]", n, sizeof(int));
267 return CUSTOM_SOCKET_ERROR;
270 /* read the data in subsequence */
271 unsigned int ulen = (unsigned int)*len;
272 *buf = new char[ulen];
274 n = readn(*buf, ulen);
276 if ((unsigned int)n != ulen) {
277 MSG_FATAL("WARNING: read data_size [%d] not matched [%d]", n, ulen);
278 return CUSTOM_SOCKET_ERROR;
285 /*==================================================================================================
286 IMPLEMENTATION OF MsgIpcServerSocket - Member Functions
287 ==================================================================================================*/
288 MsgIpcServerSocket::MsgIpcServerSocket() : sockfd(-1), maxfd(-1)
293 void MsgIpcServerSocket::addfd(int fd)
295 MSG_DEBUG("%d added", fd);
298 std::map<int, int>::iterator it = mapFds.find(fd);
299 if (it != mapFds.end())
300 MSG_FATAL("Duplicate FD %d", fd);
308 msg_error_t MsgIpcServerSocket::open(const char* path)
312 if (!path || strlen(path) > strlen(MSG_SOCKET_PATH)) {
313 MSG_FATAL("path is null");
314 return MSG_ERR_INVALID_PARAMETER;
317 if (sockfd != CUSTOM_SOCKET_ERROR) {
318 MSG_FATAL("WARNING: server_socket already opened %d at %p", sockfd, &sockfd);
319 return MSG_ERR_UNKNOWN;
322 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
324 if (sockfd == CUSTOM_SOCKET_ERROR) {
325 MSG_FATAL("socket failed: %s", g_strerror(errno));
326 return MSG_ERR_UNKNOWN;
329 MSG_DEBUG("server_socket(%p) opened : %d", &sockfd, sockfd);
331 struct sockaddr_un local = {0, };
333 local.sun_family = AF_UNIX;
334 memset(local.sun_path, 0x00, sizeof(local.sun_path));
335 strncpy(local.sun_path, path, sizeof(local.sun_path)-1);
337 unlink(local.sun_path);
339 int len = strlen(local.sun_path) + sizeof(local.sun_family);
341 if (bind(sockfd, (struct sockaddr *)&local, len) == CUSTOM_SOCKET_ERROR) {
342 MSG_FATAL("bind: %s", g_strerror(errno));
343 return MSG_ERR_UNKNOWN;
347 * determine permission of socket file
349 * - S_IRWXU : for user, allow read and write and execute
350 * - S_IRWXG : for group, allow read and write and execute
351 * - S_IRWXO : for other, allow read and write and execute
353 * - S_IRUSR, S_IWUSR, S_IXUSR : for user, allow only read, write, execute respectively
354 * - S_IRGRP, S_IWGRP, S_IXGRP : for group, allow only read, write, execute respectively
355 * - S_IROTH, S_IWOTH, S_IXOTH : for other, allow only read, write, execute respectively
357 mode_t sock_mode = (S_IRWXU | S_IRWXG | S_IRWXO); /* has 777 permission */
359 if (chmod(path, sock_mode) == CUSTOM_SOCKET_ERROR) {
360 MSG_FATAL("chmod: %s", g_strerror(errno));
361 return MSG_ERR_UNKNOWN;
363 if (listen(sockfd, CUSTOM_SOCKET_BACKLOG) == CUSTOM_SOCKET_ERROR) {
364 MSG_FATAL("listen: %s", g_strerror(errno));
365 return MSG_ERR_UNKNOWN;
375 msg_error_t MsgIpcServerSocket::accept()
379 if (sockfd == CUSTOM_SOCKET_ERROR) {
380 MSG_FATAL("server_socket not init");
381 return MSG_ERR_UNKNOWN;
384 struct sockaddr_un remote;
386 int t = sizeof(remote);
387 int fd = ::accept(sockfd, (struct sockaddr *)&remote, (socklen_t*) &t);
389 MSG_FATAL("accept: %s", g_strerror(errno));
390 return MSG_ERR_UNKNOWN;
394 MSG_DEBUG("%d is added", fd);
396 /* write the registerd fd */
397 write(fd, (const char*) &fd, sizeof(fd));
404 void MsgIpcServerSocket::close(int fd)
408 if (sockfd == CUSTOM_SOCKET_ERROR) {
409 MSG_FATAL("server_socket not init");
413 MSG_DEBUG("%d to be removed", fd);
416 std::map<int, int>::iterator it = mapFds.find(fd);
417 if (it == mapFds.end())
418 MSG_FATAL("No FD %d", fd);
424 for (it = mapFds.begin() ; it != mapFds.end() ; it++)
425 newmax = (it->second > newmax)? it->second : newmax;
428 MSG_DEBUG("fd %d removal done", fd);
434 int MsgIpcServerSocket::readn(int fd, char *buf, unsigned int len)
441 nread = ::read(fd, (void*)buf, nleft);
443 MSG_FATAL("read: %s", g_strerror(errno));
445 } else if (nread == 0) {
449 if (nleft >= (unsigned int)nread)
459 int MsgIpcServerSocket::read(int fd, char** buf, int* len)
461 if (sockfd == CUSTOM_SOCKET_ERROR) {
462 MSG_FATAL("server_socket(%p) is not initd %d", &sockfd, sockfd);
463 return CUSTOM_SOCKET_ERROR;
467 MSG_FATAL("buf[%p] and len[%p] MUST NOT NULL", buf, len);
468 return CUSTOM_SOCKET_ERROR;
472 char clen[sizeof(int)] = {0};
474 /* read the data size first */
475 int n = readn(fd, clen, sizeof(int));
476 memcpy(len, clen, sizeof(int));
478 if (n == CLOSE_CONNECTION_BY_SIGNAL) {
479 MSG_FATAL("fd %d CLOSE_CONNECTION_BY_SIGNAL", fd);
481 } else if (n != sizeof(int)) {
482 MSG_FATAL("readn %d(%zu)", n, sizeof(int));
483 return CUSTOM_SOCKET_ERROR;
486 MSG_DEBUG("MsgLen %d", *len);
488 if (*len == CLOSE_CONNECTION_BY_USER)
491 /* read the data in subsequence */
492 if (*len > 0 && *len < MSG_MAX_IPC_SIZE) {
493 unsigned int ulen = (unsigned int)*len;
494 *buf = new char[ulen+1];
496 n = readn(fd, *buf, ulen);
498 if ((unsigned int)n != ulen) {
499 MSG_FATAL("WARNING: read data_size [%d] not matched [%d]", n, ulen);
500 return CUSTOM_SOCKET_ERROR;
507 void _get_max_buffer_size(int *max_buffer_size)
509 if (MsgAccessFile(MAX_BUFFER_PATH, R_OK) == false) {
510 *max_buffer_size = DEFAULT_MAX_BUFFER_SIZE;
514 FILE *pFile = MsgOpenFile(MAX_BUFFER_PATH, "rb");
516 *max_buffer_size = DEFAULT_MAX_BUFFER_SIZE;
520 if (fscanf(pFile, "%d", max_buffer_size) < 0) {
521 *max_buffer_size = DEFAULT_MAX_BUFFER_SIZE;
527 bool _doubling_buffer_size(int sock)
530 socklen_t rn = (socklen_t)sizeof(int);
531 static int max_buffer_size = -1;
533 int result = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bSize, &rn);
535 MSG_ERR("getsockopt: %s", g_strerror(errno));
539 MSG_DEBUG("send buffer size %d", bSize);
541 if (max_buffer_size < 0)
542 _get_max_buffer_size(&max_buffer_size);
544 MSG_DEBUG("current buffer size [%d] max buffer size [%d]", bSize, max_buffer_size);
546 if (bSize * 2 > max_buffer_size)
550 result = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bSize, rn);
552 MSG_ERR("setsockopt: %s", g_strerror(errno));
559 int MsgIpcServerSocket::writen(int fd, const char *buf, unsigned int len)
567 /* MSG_NOSIGNAL to prevent SIGPIPE Error */
568 /* MSG_DONTWAIT to avoid socket block */
569 nwrite = ::send(fd, (const void*) buf, nleft, MSG_NOSIGNAL|MSG_DONTWAIT);
572 MSG_FATAL("write: %s", g_strerror(errno));
573 if (errno == EINTR) {
575 } else if (errno == EAGAIN) {
576 if (_doubling_buffer_size(fd) == true)
580 } else if (nwrite == 0) { /* Nothing is send. */
592 int MsgIpcServerSocket::write(int fd, const char* buf, unsigned int len)
596 if (!buf || len <= 0) {
597 MSG_FATAL("buf [%p] and len [%d] MUST NOT NULL", buf, len);
598 return CUSTOM_SOCKET_ERROR;
601 MSG_DEBUG("for debug - fd : [%d], buf : [%p], len : [%d]", fd, buf, len);
603 /* send the data size first */
604 int n = writen(fd, (const char*)&len, sizeof(len));
606 if (n != sizeof(len)) {
607 MSG_FATAL("WARNING: write header_size[%d] not matched [%zu]", n, sizeof(len));
608 return CUSTOM_SOCKET_ERROR;
611 /* send the data in subsequence */
612 n = writen(fd, buf, len);
614 MSG_DEBUG("Writing %d bytes", n);
616 if ((unsigned int)n != len) {
617 MSG_FATAL("Written byte (%d) is not matched to input byte (%d)", n, len);
618 return CUSTOM_SOCKET_ERROR;