/*
- * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2000 - 2018 Samsung Electronics Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
#define _GNU_SOURCE
-#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdbool.h>
+#include <sys/types.h>
#include <sys/stat.h>
#include <sys/xattr.h>
#include <errno.h>
#define PATH_AMD_SOCK "/run/aul/daemons/.amd-sock"
#define REGULAR_UID_MIN 5000
+
+typedef struct app_pkt_header_s {
+ int cmd;
+ int len;
+ int opt;
+} app_pkt_header_t;
+
static int socket_timeout_initialized;
static struct timeval tv = { 5, 200 * 1000 }; /* 5.2 */
static int __connect_client_sock(int sockfd, const struct sockaddr *saptr,
socklen_t salen, int nsec);
+static int __recv_raw(int fd, unsigned char *data, size_t data_size)
+{
+ ssize_t recv_size = 0;
+ ssize_t r;
+ size_t size = data_size;
+ bool is_blocking;
+
+ if (fcntl(fd, F_GETFL, 0) & O_NONBLOCK)
+ is_blocking = false;
+ else
+ is_blocking = true;
+
+ while (size > 0) {
+ r = recv(fd, data, size, 0);
+ if (r == 0) {
+ _W("Socket was disconnected. fd(%d)", fd);
+ return -ECOMM;
+ } else if (r < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ if (is_blocking && errno == EAGAIN) {
+ _E("recv timeout. fd(%d)", fd);
+ return -EAGAIN;
+ }
+
+ continue;
+ }
+
+ _E("recv error. fd(%d), errno(%d)",
+ fd, errno);
+ return -ECOMM;
+ }
+
+ size -= r;
+ data += r;
+ recv_size += r;
+ }
+
+ if (recv_size != data_size) {
+ _E("Failed to receive messages. fd(%d)", fd);
+ return -ECOMM;
+ }
+
+ return 0;
+}
+
+static int __recv_pkt(int fd, app_pkt_t **out_pkt)
+{
+ app_pkt_header_t header = { 0, };
+ app_pkt_t *pkt;
+ int r;
+
+ *out_pkt = NULL;
+ r = __recv_raw(fd, (unsigned char *)&header, sizeof(header));
+ if (r < 0) {
+ _E("Failed to receive packet header");
+ return r;
+ }
+
+ if (header.len < 0 || header.len > MAX_PAYLOAD_SIZE) {
+ _E("Invalid protocol. length(%d)", header.len);
+ return -ECOMM;
+ }
+
+ pkt = calloc(1, sizeof(app_pkt_t) + header.len);
+ if (!pkt) {
+ _E("Out of memory");
+ return -ECOMM;
+ }
+ pkt->cmd = header.cmd;
+ pkt->len = header.len;
+ pkt->opt = header.opt;
+
+ r = __recv_raw(fd, (unsigned char *)pkt->data, pkt->len);
+ if (r < 0) {
+ free(pkt);
+ return r;
+ }
+
+ *out_pkt = pkt;
+
+ return 0;
+}
+
static void __set_timeval(double sec)
{
char buf[12];
{
int len;
int res;
- char buf[1024];
_D("fd(%d): cmd(%d)", fd, cmd);
if (opt & AUL_SOCK_ASYNC)
return fd;
-retry_recv:
- len = recv(fd, &res, sizeof(int), 0);
- if (len <= 0) {
- if (errno == EAGAIN) {
- _E("recv timeout : %s",
- strerror_r(errno, buf, sizeof(buf)));
- res = -EAGAIN;
- } else if (errno == EINTR) {
- _D("recv : %s", strerror_r(errno, buf, sizeof(buf)));
- goto retry_recv;
- } else {
- _E("recv error : %s", strerror_r(errno, buf, sizeof(buf)));
- res = -ECOMM;
- }
- }
+ len = __recv_raw(fd, (unsigned char *)&res, sizeof(int));
+ if (len < 0)
+ res = len;
close(fd);
API app_pkt_t *aul_sock_recv_pkt(int fd, int *clifd, struct ucred *cr)
{
- int len;
- int ret;
struct sockaddr_un aul_addr = { 0, };
- int sun_size;
- app_pkt_t *pkt = NULL;
+ int sun_size = sizeof(struct sockaddr_un);
int cl = sizeof(struct ucred);
- unsigned char buf[AUL_PKT_HEADER_SIZE];
- int cmd;
- int datalen;
- int opt;
-
- sun_size = sizeof(struct sockaddr_un);
+ app_pkt_t *pkt = NULL;
+ int client_fd;
+ int ret;
- *clifd = accept(fd, (struct sockaddr *)&aul_addr,
+ client_fd = accept(fd, (struct sockaddr *)&aul_addr,
(socklen_t *)&sun_size);
- if (*clifd == -1) {
+ if (client_fd == -1) {
if (errno != EINTR)
_E("accept error");
return NULL;
}
- if (getsockopt(*clifd, SOL_SOCKET, SO_PEERCRED, cr,
- (socklen_t *) &cl) < 0) {
+ ret = getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED,
+ cr, (socklen_t *)&cl);
+ if (ret < 0) {
_E("peer information error");
- close(*clifd);
+ close(client_fd);
return NULL;
}
- aul_sock_set_sock_option(*clifd, 1);
-
- retry_recv:
- /* receive header(cmd, datalen) */
- len = recv(*clifd, buf, sizeof(buf), 0);
- if (len <= 0)
- if (errno == EINTR)
- goto retry_recv;
-
- if (len < AUL_PKT_HEADER_SIZE) {
- _E("recv error");
- close(*clifd);
- return NULL;
- }
- memcpy(&cmd, buf, sizeof(int));
- memcpy(&datalen, buf + sizeof(int), sizeof(int));
- memcpy(&opt, buf + sizeof(int) + sizeof(int), sizeof(int));
+ aul_sock_set_sock_option(client_fd, 1);
- if (datalen < 0 || datalen > MAX_PAYLOAD_SIZE) {
- close(*clifd);
+ ret = __recv_pkt(client_fd, &pkt);
+ if (ret < 0) {
+ close(client_fd);
return NULL;
}
- /* allocate for a null byte */
- pkt = (app_pkt_t *)calloc(1, sizeof(app_pkt_t) + datalen);
- if (pkt == NULL) {
- close(*clifd);
- return NULL;
- }
- pkt->cmd = cmd;
- pkt->len = datalen;
- pkt->opt = opt;
-
- len = 0;
- while (len != pkt->len) {
- ret = recv(*clifd, pkt->data + len, pkt->len - len, 0);
- if (ret <= 0) {
- _E("recv error %d %d", len, pkt->len);
- free(pkt);
- close(*clifd);
- return NULL;
- }
- len += ret;
- _D("recv len %d %d", len, pkt->len);
- }
+ *clifd = client_fd;
return pkt;
}
API int aul_sock_recv_reply_pkt(int fd, app_pkt_t **ret_pkt)
{
- int len;
- int cmd;
int ret;
- int recv_opt;
- app_pkt_t *pkt = NULL;
- unsigned char buf[AUL_PKT_HEADER_SIZE];
- char err_buf[1024];
-
-retry_recv:
- /* receive header(cmd, datalen) */
- len = recv(fd, buf, sizeof(buf), 0);
- if (len <= 0)
- if (errno == EINTR)
- goto retry_recv;
-
- if (len < AUL_PKT_HEADER_SIZE) {
- _E("recv error");
- close(fd);
- if (len == sizeof(int)) {
- memcpy(&ret, buf, sizeof(int));
- return ret;
- }
- *ret_pkt = NULL;
- return -ECOMM;
- }
- memcpy(&cmd, buf, sizeof(int));
- memcpy(&len, buf + sizeof(int), sizeof(int));
- memcpy(&recv_opt, buf + sizeof(int) + sizeof(int), sizeof(int));
-
- if (len < 0 || len > MAX_PAYLOAD_SIZE) {
- close(fd);
- *ret_pkt = NULL;
- return -ECOMM;
- }
-
- /* allocate for a null byte */
- pkt = (app_pkt_t *)calloc(1, sizeof(app_pkt_t) + len);
- if (pkt == NULL) {
- close(fd);
- *ret_pkt = NULL;
- return -ECOMM;
- }
- pkt->cmd = cmd;
- pkt->len = len;
- pkt->opt = recv_opt;
-
- len = 0;
- while (len != pkt->len) {
- ret = recv(fd, pkt->data + len, pkt->len - len, 0);
- if (ret <= 0) {
- if (errno == EINTR) {
- continue;
- } else {
- _E("recv error %s", strerror_r(errno,
- err_buf, sizeof(err_buf)));
- free(pkt);
- close(fd);
- *ret_pkt = NULL;
- return -ECOMM;
- }
- }
- len += ret;
- _D("recv len %d %d", len, pkt->len);
- }
+ ret = __recv_pkt(fd, ret_pkt);
close(fd);
- *ret_pkt = pkt;
- return 0;
+ return ret;
}
static int __get_descriptors(struct cmsghdr *cmsg, struct msghdr *msg, int *fds, int maxdesc)
return fd;
}
-static int __recv_raw_with_fd(int fd, unsigned int size,
- unsigned char *data, unsigned int *datalen)
-{
- int ret;
- unsigned int len = size;
- int retry = 2;
-
- *datalen = 0;
- while (len > 0 && retry) {
- ret = recv(fd, data, len, 0);
- if (ret <= 0) {
- if (errno == EINTR || errno == EAGAIN) {
- retry--;
- continue;
- }
-
- _E("recv error - fd: %d, errno: %d", fd, errno);
- return -ECOMM;
- }
-
- len -= ret;
- data += ret;
- *datalen += ret;
- _D("recv len - %d:%d", size, *datalen);
- if (*datalen == size)
- retry = 0;
- }
-
- return 0;
-}
-
-
int aul_sock_recv_pkt_with_cb(int fd,
void (*callback)(app_pkt_t *pkt, void *data),
void *user_data)
{
- int i;
- int count = 0;
- unsigned int recv_size;
- int ret = 0;
app_pkt_t **pkt;
- unsigned char buf[AUL_PKT_HEADER_SIZE];
- int cmd;
- int len;
- int opt;
+ int count = 0;
size_t size;
+ int ret;
+ int i;
- if (fd < 0) {
+ if (fd < 0 || fd > sysconf(_SC_OPEN_MAX)) {
_E("Invalid parameter");
return -1;
}
return -1;
}
- ret = __recv_raw_with_fd(fd, sizeof(int),
- (unsigned char *)(intptr_t)&count, &recv_size);
+ ret = __recv_raw(fd, (unsigned char *)&count, sizeof(int));
if (ret < 0) {
_E("recv error - %d", ret);
close(fd);
- return -ECOMM;
- } else if (count <= 0 || count > MAX_RUNNING_INSTANCE ||
- recv_size != sizeof(int)) {
- _E("error - count: %d, recv_size: %d",
- count, recv_size);
+ return ret;
+ } else if (count <= 0 || count > MAX_RUNNING_INSTANCE) {
+ _E("error - count: %d", count);
close(fd);
- return count;
+ return -ECOMM;
}
size = sizeof(app_pkt_t *) * count;
}
for (i = 0; i < count; ++i) {
- ret = __recv_raw_with_fd(fd, sizeof(buf), buf,
- &recv_size);
- if (ret < 0) {
- _E("recv error - %d", ret);
- break;
- } else if (recv_size != sizeof(buf)) {
- _E("recv error - recv_size: %d", recv_size);
- ret = -ECOMM;
- break;
- }
- memcpy(&cmd, buf, sizeof(int));
- memcpy(&len, buf + sizeof(int), sizeof(int));
- memcpy(&opt, buf + sizeof(int) + sizeof(int), sizeof(int));
-
- if (len < 0 || len > MAX_PAYLOAD_SIZE) {
- ret = -ECOMM;
- break;
- }
-
- pkt[i] = (app_pkt_t *)calloc(1, sizeof(app_pkt_t) + len);
- if (pkt[i] == NULL) {
- _E("out of memory");
- ret = -1;
- break;
- }
- pkt[i]->cmd = cmd;
- pkt[i]->len = len;
- pkt[i]->opt = opt;
-
- ret = __recv_raw_with_fd(fd, pkt[i]->len, pkt[i]->data,
- &recv_size);
+ ret = __recv_pkt(fd, &pkt[i]);
if (ret < 0) {
- _E("recv error - %d", ret);
- free(pkt[i]);
- pkt[i] = NULL;
- break;
- } else if (recv_size != pkt[i]->len) {
- _E("error - recv_size: %d", recv_size);
- free(pkt[i]);
- pkt[i] = NULL;
+ _E("Failed to receive packet");
break;
}
-
- memset(buf, 0, sizeof(buf));
}
for (i = 0; i < count; ++i) {
callback(pkt[i], user_data);
free(pkt[i]);
}
+
free(pkt);
close(fd);
{
int len;
int res;
- char buf[1024];
-
-retry_recv:
- len = recv(fd, &res, sizeof(int), 0);
- if (len <= 0) {
- if (errno == EAGAIN) {
- _E("recv timeout: %s, fd: %d ",
- strerror_r(errno, buf, sizeof(buf)),
- fd);
- res = -EAGAIN;
- } else if (errno == EINTR) {
- _D("recv: %s, fd: %d",
- strerror_r(errno, buf, sizeof(buf)),
- fd);
- goto retry_recv;
- } else {
- _E("recv error: %s, fd: %d",
- strerror_r(errno, buf, sizeof(buf)),
- fd);
- res = -ECOMM;
- }
+
+ len = __recv_raw(fd, (unsigned char *)&res, sizeof(int));
+ if (len < 0) {
+ _E("Failed to receive the result. fd(%d)", fd);
+ res = -ECOMM;
}
return res;