Add fd passing feature for data-control 01/48901/9
authorhyunho kang <hhstark.kang@samsung.com>
Tue, 27 Oct 2015 08:13:53 +0000 (17:13 +0900)
committerhyunho kang <hhstark.kang@samsung.com>
Tue, 27 Oct 2015 10:30:29 +0000 (19:30 +0900)
Change-Id: I9106541404b4f0c439b89b31f8e6f0efe3258d33
Signed-off-by: hyunho kang <hhstark.kang@samsung.com>
am_daemon/amd_main.c
am_daemon/amd_request.c
am_daemon/amd_request.h
include/app_sock.h
include/aul.h
src/app_sock.c
src/launch.c

index a19142a..e7846a6 100644 (file)
@@ -276,7 +276,7 @@ static int __init()
                return -1;
        }
 
-       _requset_init();
+       _request_init();
        app_group_init();
 
        if (vconf_notify_key_changed(VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS,
index efb8761..1c41f57 100644 (file)
@@ -55,6 +55,9 @@
 #define PRIVILEGE_APPMANAGER_KILL "http://tizen.org/privilege/appmanager.kill"
 #define PRIVILEGE_APPMANAGER_KILL_BGAPP "http://tizen.org/privilege/appmanager.kill.bgapp"
 
+#define MAX_NR_OF_DESCRIPTORS 2
+static GHashTable *__socket_pair_hash = NULL;
+
 typedef int (*app_cmd_dispatch_func)(int clifd, const app_pkt_t *pkt, struct ucred *cr);
 
 static cynara *r_cynara = NULL;
@@ -62,6 +65,58 @@ static cynara *r_cynara = NULL;
 static int __send_result_to_client(int fd, int res);
 static gboolean __request_handler(gpointer data);
 
+static int __send_message(int sock, const struct iovec *vec, int vec_size, const int *desc, int nr_desc)
+{
+       struct msghdr msg = {0};
+       int sndret;
+
+       if (vec == NULL || vec_size < 1)
+               return -EINVAL;
+       if (nr_desc < 0 || nr_desc > MAX_NR_OF_DESCRIPTORS)
+               return -EINVAL;
+       if (desc == NULL)
+               nr_desc = 0;
+
+       msg.msg_iov = (struct iovec *)vec;
+       msg.msg_iovlen = vec_size;
+
+       /* sending ancillary data */
+       if (nr_desc > 0) {
+               int desclen = 0;
+               struct cmsghdr *cmsg = NULL;
+               char buff[CMSG_SPACE(sizeof(int) * MAX_NR_OF_DESCRIPTORS)] = {0};
+
+               msg.msg_control = buff;
+               msg.msg_controllen = sizeof(buff);
+               cmsg = CMSG_FIRSTHDR(&msg);
+               if (cmsg == NULL)
+                       return -EINVAL;
+
+               /* packing files descriptors */
+               if (nr_desc > 0) {
+                       cmsg->cmsg_level = SOL_SOCKET;
+                       cmsg->cmsg_type = SCM_RIGHTS;
+                       desclen = cmsg->cmsg_len = CMSG_LEN(sizeof(int) * nr_desc);
+                       memcpy((int *)CMSG_DATA(cmsg), desc, sizeof(int) * nr_desc);
+                       cmsg = CMSG_NXTHDR(&msg, cmsg);
+
+                       _D("packing file descriptors done");
+               }
+
+               /* finished packing updating the corect length */
+               msg.msg_controllen = desclen;
+       } else {
+               msg.msg_control = NULL;
+               msg.msg_controllen = 0;
+       }
+
+       sndret = sendmsg(sock, &msg, 0);
+
+       _D("sendmsg ret : %d", sndret);
+       if(sndret < 0) return -errno;
+       else return sndret;
+}
+
 static int __send_result_data(int fd, int cmd, unsigned char *kb_data, int datalen)
 {
        int len;
@@ -260,6 +315,114 @@ static void __handle_agent_dead_signal(struct ucred *pcr)
        __agent_dead_handler(pcr->uid);
 }
 
+static int __dispatch_get_socket_pair(int clifd, const app_pkt_t *pkt, struct ucred *cr)
+{
+
+       char *caller;
+       char *callee;
+       char *socket_pair_key;
+       int socket_pair_key_len;
+       int *handles;
+       struct iovec vec[3];
+       int msglen;
+       char buffer[1024];
+       struct sockaddr_un saddr;
+       char *datacontrol_type;
+       bundle *kb;
+
+       kb = bundle_decode(pkt->data, pkt->len);
+       caller = (char *)bundle_get_val(kb, AUL_K_CALLER_APPID);
+       callee = (char *)bundle_get_val(kb, AUL_K_CALLEE_APPID);
+       datacontrol_type = (char *)bundle_get_val(kb, "DATA_CONTOL_TYPE");
+
+       socket_pair_key_len = strlen(caller) + strlen(callee) + 2;
+
+       socket_pair_key = (char *)calloc(socket_pair_key_len, sizeof(char));
+
+       if (socket_pair_key == NULL) {
+               _E("calloc fail");
+               goto err_out;
+       }
+
+       snprintf(socket_pair_key, socket_pair_key_len, "%s_%s", caller, callee);
+       _E("socket pair key : %s", socket_pair_key);
+
+       handles = g_hash_table_lookup(__socket_pair_hash, socket_pair_key);
+
+       if (handles == NULL) {
+
+               handles = (int *)calloc(2, sizeof(int));
+               if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) {
+                       _E("error create socket pair");
+                       __send_result_to_client(clifd, -1);
+                       goto err_out;
+               }
+
+               if(handles[0] == -1) {
+                       _E("error socket open");
+                       __send_result_to_client(clifd, -1);
+                       goto err_out;
+               }
+               g_hash_table_insert(__socket_pair_hash, strdup(socket_pair_key),
+                               handles);
+
+               _E("New socket pair insert done.");
+       }
+
+
+       memset(&saddr, 0, sizeof(saddr));
+       saddr.sun_family = AF_UNIX;
+
+       SECURE_LOGD("amd send fd : [%d, %d]", handles[0], handles[1]);
+       vec[0].iov_base = buffer;
+       vec[0].iov_len = strlen(buffer) + 1;
+
+       if (datacontrol_type != NULL) {
+               _E("datacontrol_type : %s", datacontrol_type);
+               if (strcmp(datacontrol_type, "consumer") == 0) {
+
+                       msglen = __send_message(clifd, vec, 1, &handles[0], 1);
+                       if(msglen < 0) {
+                               _E("Error[%d]: while sending message\n", -msglen);
+                               __send_result_to_client(clifd, -1);
+                               goto err_out;
+                       }
+                       close(handles[0]);
+                       handles[0] = -1;
+                       if (handles[1] == -1) {
+                               _E("remove from hash : %s", socket_pair_key);
+                               g_hash_table_remove(__socket_pair_hash, socket_pair_key);
+                       }
+
+               }
+               else {
+                       msglen = __send_message(clifd, vec, 1, &handles[1], 1);
+                       if(msglen < 0) {
+                               _E("Error[%d]: while sending message\n", -msglen);
+                               __send_result_to_client(clifd, -1);
+                               goto err_out;
+                       }
+                       close(handles[1]);
+                       handles[1] = -1;
+                       if (handles[0] == -1) {
+                               _E("remove from hash : %s", socket_pair_key);
+                               g_hash_table_remove(__socket_pair_hash, socket_pair_key);
+                       }
+               }
+       }
+       SECURE_LOGD("send_message msglen : [%d]\n", msglen);
+
+       return 0;
+
+err_out:
+       if (handles)
+               free(handles);
+       if (socket_pair_key)
+               free(socket_pair_key);
+
+       return -1;
+}
+
 static int __dispatch_app_group_add(int clifd, const app_pkt_t *pkt, struct ucred *cr)
 {
        bundle *b;
@@ -767,6 +930,7 @@ end:
 }
 
 static app_cmd_dispatch_func dispatch_table[APP_CMD_MAX] = {
+       [APP_GET_SOCKET_PAIR] =  __dispatch_get_socket_pair,
        [APP_START] =  __dispatch_app_start,
        [APP_OPEN] = __dispatch_app_start,
        [APP_RESUME] = __dispatch_app_start,
@@ -884,13 +1048,15 @@ static GSourceFuncs funcs = {
        .finalize = NULL
 };
 
-int _requset_init(void)
+int _request_init(void)
 {
        int fd;
        int r;
        GPollFD *gpollfd;
        GSource *src;
 
+       __socket_pair_hash = g_hash_table_new_full(g_str_hash,  g_str_equal, NULL, g_free);
+
        fd = __create_sock_activation();
        if (fd == -1) {
                _D("Create server socket without socket activation");
index 812fa03..db963fe 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef __AUL_AMD_REQUEST_H_
 #define __AUL_AMD_REQUEST_H_
 
-int _requset_init(void);
+int _request_init(void);
 
 #endif
 
index 342efb6..b9c5411 100644 (file)
@@ -66,6 +66,7 @@ enum app_cmd {
        APP_GROUP_RESUME,
        APP_GROUP_GET_LEADER_PID,
        APP_GET_STATUS,
+       APP_GET_SOCKET_PAIR,
 
        /* for special purpose */
        AMD_RELOAD_APPINFO,
@@ -105,6 +106,7 @@ int __app_send_raw_with_noreply(int pid, int cmd, unsigned char *kb_data, int da
 int __app_send_raw_with_noreply_for_uid(int pid, uid_t uid, int cmd, unsigned char *kb_data, int datalen);
 int __app_send_raw_with_delay_reply(int pid, int cmd, unsigned char *kb_data, int datalen);
 int __app_send_raw_with_delay_reply_for_uid(int pid, uid_t uid, int cmd, unsigned char *kb_data, int datalen);
+int __app_send_raw_with_fd_reply(int pid, uid_t uid, int cmd, unsigned char *kb_data, int datalen, int *ret_fd);
 int __app_agent_send_raw(int uid, int cmd, unsigned char *kb_data, int datalen);
 int __app_agent_send_raw_with_noreply(int uid, int cmd, unsigned char *kb_data, int datalen);
 app_pkt_t *__app_recv_raw(int fd, int *clifd, struct ucred *cr);
index 42f9941..6e27d9b 100644 (file)
@@ -1697,6 +1697,7 @@ int aul_app_group_get_leader_pid(int pid);
 int aul_app_group_clear_top(void);
 int aul_app_group_is_top(void);
 
+int aul_request_data_control_socket_pair(bundle *b, int *fd);
 
 /** @} */
 
index cf661b1..8d2d4f4 100644 (file)
@@ -33,6 +33,8 @@
 #include "app_sock.h"
 #include "simple_util.h"
 
+#define MAX_NR_OF_DESCRIPTORS 2
+
 static int __connect_client_sock(int sockfd, const struct sockaddr *saptr, socklen_t salen,
                   int nsec);
 
@@ -416,6 +418,195 @@ retry_recv:
 }
 
 
+static int __get_descriptors(struct cmsghdr *cmsg, struct msghdr *msg, int *fds, int maxdesc)
+{
+       int retnr = 0;
+       if (cmsg == NULL || msg == NULL)
+               return 0;
+       if (cmsg->cmsg_type != SCM_RIGHTS)
+               return 0;
+
+       if (msg->msg_controllen > 0) {
+               int nrdesc;
+               int payload = cmsg->cmsg_len - sizeof(*cmsg);
+               int *recvdesc = (int *)CMSG_DATA(cmsg);
+               int i;
+
+               nrdesc = payload / sizeof(int);
+               retnr = nrdesc < maxdesc ? nrdesc : maxdesc;
+               for (i = 0; i < nrdesc; ++i) {
+                       if (maxdesc-- > 0)
+                               *fds++ = *recvdesc++;
+                       else
+                               close(*recvdesc++);
+               }
+       }
+       return retnr;
+}
+
+static int __recv_message(int sock, struct iovec *vec, int vec_max_size, int *vec_size,
+               int *fds, int *nr_fds)
+{
+
+       char buff[CMSG_SPACE(sizeof(int) * MAX_NR_OF_DESCRIPTORS) + CMSG_SPACE(50)] = {0};
+       struct msghdr msg = {0};
+       struct cmsghdr *cmsg = NULL;
+       int ret;
+
+       if (vec == NULL || vec_max_size < 1 || vec_size == NULL)
+               return -EINVAL;
+
+       msg.msg_iov = vec;
+       msg.msg_iovlen = vec_max_size;
+       msg.msg_control = buff;
+       msg.msg_controllen = sizeof(buff);
+
+       ret = recvmsg(sock, &msg, 0);
+       if (ret < 0)
+               return -errno;
+       *vec_size = msg.msg_iovlen;
+
+       /* get the ANCILLARY data */
+       cmsg = CMSG_FIRSTHDR(&msg);
+       if (cmsg == NULL) {
+               if(nr_fds != NULL)
+                       *nr_fds = 0;
+       } else {
+               int iter = 0;
+               int fdnum = 0;
+
+               for (; cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg), iter ++) {
+                       switch(cmsg->cmsg_type) {
+                               case SCM_RIGHTS:
+                                       if (fds != NULL)
+                                               fdnum = __get_descriptors(cmsg, &msg, fds, MAX_NR_OF_DESCRIPTORS);
+                                       if (nr_fds != NULL)
+                                               *nr_fds = fdnum;
+                                       break;
+                       }
+               }
+       }
+       return ret;
+}
+
+int __app_send_raw_with_fd_reply(int pid, uid_t uid, int cmd, unsigned char *kb_data, int datalen, int *ret_fd)
+{
+       int fd;
+       int len;
+       int ret;
+       int res = 0;
+       app_pkt_t *pkt = NULL;
+
+       if (kb_data == NULL || datalen > AUL_SOCK_MAXBUFF - 8) {
+               _E("keybundle error\n");
+               return -EINVAL;
+       }
+
+       _D("pid(%d) : cmd(%d)", pid, cmd);
+
+       fd = __create_client_sock(pid, uid);
+       if (fd < 0) {
+               _E("cannot create a client socket: %d", fd);
+               return -ECOMM;
+       }
+
+       pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
+       if (NULL == pkt) {
+               _E("Malloc Failed!");
+               return -ENOMEM;
+       }
+       memset(pkt, 0, AUL_SOCK_MAXBUFF);
+
+       pkt->cmd = cmd;
+       pkt->len = datalen;
+       memcpy(pkt->data, kb_data, datalen);
+
+       if ((len = send(fd, pkt, datalen + 8, 0)) != datalen + 8) {
+               _E("sendto() failed - %d %d (errno %d)", len, datalen + 8, errno);
+               if(len > 0) {
+                       while (len != datalen + 8) {
+                               ret = send(fd, &pkt->data[len - 8], datalen + 8 - len, 0);
+                               if (ret < 0) {
+                                       _E("second send() failed - %d %d (errno: %d)", ret, datalen + 8, errno);
+                                       if (errno == EPIPE) {
+                                               _E("pid:%d, fd:%d\n", pid, fd);
+                                       }
+                                       close(fd);
+                                       if (pkt) {
+                                               free(pkt);
+                                               pkt = NULL;
+                                       }
+                                       return -ECOMM;
+                               }
+                               len += ret;
+                               _D("send() len - %d %d", len, datalen + 8);
+                       }
+               } else {
+                       if (errno == EPIPE) {
+                               _E("pid:%d, fd:%d\n", pid, fd);
+                       }
+                       close(fd);
+                       if (pkt) {
+                               free(pkt);
+                               pkt = NULL;
+                       }
+
+                       _E("send() failed: %d %s", errno, strerror(errno));
+                       return -ECOMM;
+               }
+       }
+       if (pkt) {
+               free(pkt);
+               pkt = NULL;
+       }
+
+retry_recv:
+
+       if(cmd == APP_GET_SOCKET_PAIR) {
+
+               char recv_buff[1024];
+               struct iovec vec[3];
+               int ret = 0;
+               int vec_len = 0;
+               int fds_len = 0;
+               int fds[1] = {0};
+
+               vec[0].iov_base = recv_buff;
+               vec[0].iov_len = 1024;
+               ret = __recv_message(fd, vec, 1, &vec_len, fds, &fds_len);
+               if (ret < 0) {
+                       _E("Error[%d]. while receiving message\n", -ret);
+                       if (fds_len > 0)
+                               close(fds[0]);
+                       return -ECOMM;
+               } else
+                       recv_buff[ret] = '\0';
+
+               if(fds_len > 0){
+                       _E("fds : %d", fds[0]);
+                       ret_fd[0] = fds[0];
+               }
+
+       } else {
+               len = recv(fd, &res, sizeof(int), 0);
+               if (len == -1) {
+                       if (errno == EAGAIN) {
+                               _E("recv timeout : cmd(%d) %s", cmd, strerror(errno));
+                               res = -EAGAIN;
+                       } else if (errno == EINTR) {
+                               _E("recv : %s", strerror(errno));
+                               goto retry_recv;
+                       } else {
+                               _E("recv error : %s", strerror(errno));
+                               res = -ECOMM;
+                       }
+               }
+       }
+       close(fd);
+
+       return res;
+}
+
 int __app_agent_send_raw(int uid, int cmd, unsigned char *kb_data, int datalen)
 {
        int fd;
index 0ff4b79..e3dc7d7 100644 (file)
@@ -151,6 +151,56 @@ static int __get_aul_error(int res)
        return ret;
 }
 
+static int __app_send_cmd_with_fd(int pid, int uid, int cmd, bundle *kb, int *ret_fd)
+{
+       int datalen;
+       bundle_raw *kb_data = NULL;
+       int res = AUL_R_OK;
+
+       res = bundle_encode(kb, &kb_data, &datalen);
+       if (res != BUNDLE_ERROR_NONE) {
+               return AUL_R_EINVAL;
+       }
+       if ((res = __app_send_raw_with_fd_reply(pid, uid, cmd, kb_data, datalen, ret_fd)) < 0) {
+               switch (res) {
+                       case -EINVAL:
+                               res = AUL_R_EINVAL;
+                               break;
+                       case -ECOMM:
+                               res = AUL_R_ECOMM;
+                               break;
+                       case -EAGAIN:
+                               res = AUL_R_ETIMEOUT;
+                               break;
+                       case -ELOCALLAUNCH_ID:
+                               res = AUL_R_LOCAL;
+                               break;
+                       case -EILLEGALACCESS:
+                               res = AUL_R_EILLACC;
+                               break;
+                       case -ETERMINATING:
+                               res = AUL_R_ETERMINATING;
+                               break;
+                       case -ENOLAUNCHPAD:
+                               res = AUL_R_ENOLAUNCHPAD;
+                               break;
+#ifdef _APPFW_FEATURE_APP_CONTROL_LITE
+                       case -EUGLOCAL_LAUNCH:
+                               res = AUL_R_UG_LOCAL;
+                               break;
+#endif
+                       case -EREJECTED:
+                               res = AUL_R_EREJECTED;
+                               break;
+                       default:
+                               res = AUL_R_ERROR;
+               }
+       }
+       free(kb_data);
+
+       return res;
+}
+
 /**
  * @brief      encode kb and send it to 'pid'
  * @param[in]  pid             receiver's pid
@@ -278,6 +328,50 @@ static int __app_resume_local()
        return 0;
 }
 
+int app_request_to_launchpad_with_fd(int cmd, const char *appid, bundle *kb, int *fd, int uid)
+{
+       int must_free = 0;
+       int ret = 0;
+
+       SECURE_LOGD("launch request : %s", appid);
+       if (kb == NULL) {
+               kb = bundle_create();
+               must_free = 1;
+       } else
+               __clear_internal_key(kb);
+
+       ret = __app_send_cmd_with_fd(AUL_UTIL_PID, uid, cmd, kb, fd);
+
+       _D("launch request result : %d", ret);
+       if (ret == AUL_R_LOCAL) {
+               _E("app_request_to_launchpad : Same Process Send Local");
+               bundle *b;
+
+               switch (cmd) {
+                       case APP_START:
+                       case APP_START_RES:
+                               b = bundle_dup(kb);
+                               ret = __app_launch_local(b);
+                               break;
+                       case APP_OPEN:
+                       case APP_RESUME:
+                       case APP_RESUME_BY_PID:
+                               ret = __app_resume_local();
+                               break;
+                       default:
+                               _E("no support packet");
+               }
+
+       }
+
+       /*   cleanup */
+       if (must_free)
+               bundle_free(kb);
+
+       return ret;
+}
+
+
 /**
  * @brief      start caller with kb
  * @return     callee's pid
@@ -524,6 +618,10 @@ SLPAPI void aul_finalize()
        return;
 }
 
+SLPAPI int aul_request_data_control_socket_pair(bundle *kb, int *fd)
+{
+       return app_request_to_launchpad_with_fd(APP_GET_SOCKET_PAIR, NULL, kb, fd, getuid());
+}
 
 SLPAPI int aul_launch_app(const char *appid, bundle *kb)
 {