Add new apis to watch that remote port is registered and unregistered
[platform/core/appfw/message-port.git] / src / message-port.c
index dacd5ae..6868a5e 100755 (executable)
@@ -1,25 +1,25 @@
-
 /*
- Message Port
- Copyright (c) 2015 Samsung Electronics Co., Ltd.
-
- Licensed under the Apache License, Version 2.0 (the License);
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
Message Port
Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
Licensed under the Apache License, Version 2.0 (the License);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
+ *
    http://www.apache.org/licenses/LICENSE-2.0
+ *
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+ */
 
 /**
  * @file       message-port.cpp
  * @brief      This is the implementation file for the MessagePort.
  */
+#define _GNU_SOURCE
 
 #include <sys/socket.h>
 #include <stdlib.h>
 #define DBUS_RELEASE_NAME_REPLY_NON_EXISTENT    2 /* *< The given name does not exist on the bus */
 #define DBUS_RELEASE_NAME_REPLY_NOT_OWNER       3 /* *< Service is not an owner of the given name */
 #define HEADER_LEN 8
-#define MAX_RETRY_CNT 2
+#define MAX_RETRY_CNT 10
+#define SOCK_PAIR_SENDER 0
+#define SOCK_PAIR_RECEIVER 1
+
 
 #define retvm_if(expr, val, fmt, arg...) do { \
        if (expr) { \
 } while (0)
 
 static bool _initialized = false;
-static GDBusConnection *__gdbus_conn = NULL;
+static GDBusConnection *__gdbus_conn;
 static char *__app_id;
-static GHashTable *__local_port_info = NULL;
-static GHashTable *__remote_port_info = NULL;;
-static GHashTable *__sender_appid_hash = NULL;;
-static GHashTable *__trusted_app_list_hash = NULL;
+static GHashTable *__local_port_info;
+static GHashTable *__remote_app_info;
+static GHashTable *__sender_appid_hash;
+static GHashTable *__trusted_app_list_hash;
+static GHashTable *__callback_info_hash;
+static GHashTable *__registered_callback_info_hash;
 static const int MAX_MESSAGE_SIZE = 16 * 1024;
 
 enum __certificate_info_type {
@@ -125,22 +130,35 @@ typedef struct port_list_info {
        char *port_name;
        char *encoded_bus_name;
        bool is_trusted;
-       int sock_pair[2];
+       int send_sock_fd;
        int watcher_id;
        bool exist;
+       GIOChannel *gio_read;
+       int g_src_id;
 } port_list_info_s;
 
-static void __callback_info_free(message_port_callback_info_s *callback_info)
+typedef struct registered_callback_info {
+       char *remote_app_id;
+       char *remote_port;
+       bool is_trusted;
+       int watcher_id;
+       void *user_data;
+       messageport_registration_event_cb registered_cb;
+       messageport_registration_event_cb unregistered_cb;
+} registered_callback_info_s;
+
+static void __callback_info_free(gpointer data)
 {
+       message_port_callback_info_s *callback_info = (message_port_callback_info_s *)data;
        GError *error = NULL;
        if (callback_info == NULL)
                return;
 
        if (callback_info->remote_app_id)
-               free(callback_info->remote_app_id);
+               FREE_AND_NULL(callback_info->remote_app_id);
 
        if (callback_info->gio_read != NULL) {
-               g_io_channel_shutdown(callback_info->gio_read, FALSE, &error);
+               g_io_channel_shutdown(callback_info->gio_read, TRUE, &error);
                if (error) {
                        _LOGE("g_io_channel_shutdown error : %s", error->message);
                        g_error_free(error);
@@ -154,9 +172,50 @@ static void __callback_info_free(message_port_callback_info_s *callback_info)
                callback_info->g_src_id = 0;
        }
 
+       FREE_AND_NULL(callback_info);
+}
+
+static void __callback_info_free_by_info(message_port_callback_info_s *callback_info)
+{
+       GList *callback_info_list = g_hash_table_lookup(__callback_info_hash, GUINT_TO_POINTER(callback_info->local_id));
+       GList *find_list;
+
+       if (callback_info_list == NULL)
+               return;
+
+       find_list = g_list_find(callback_info_list, callback_info);
+       if (find_list == NULL)
+               return;
+
+       callback_info_list = g_list_remove_link(callback_info_list, find_list);
+       __callback_info_free(callback_info);
+       g_list_free(find_list);
+}
+
+static void __registered_callback_info_free(gpointer data)
+{
+       registered_callback_info_s *callback_info = (registered_callback_info_s *)data;
+       if (callback_info == NULL)
+               return;
+
+       if (callback_info->remote_app_id)
+               free(callback_info->remote_app_id);
+
+       if (callback_info->remote_port)
+               free(callback_info->remote_port);
+
        free(callback_info);
 }
 
+
+static void __hash_destroy_callback_info(gpointer data)
+{
+
+       GList *callback_list = (GList *)data;
+       if (callback_list != NULL)
+               g_list_free_full(callback_list, __callback_info_free);
+}
+
 static char *__get_encoded_name(const char *remote_app_id, const char *port_name, bool is_trusted)
 {
 
@@ -243,6 +302,8 @@ static bool __is_preloaded(const char *local_appid, const char *remote_appid)
                pkgmgrinfo_appinfo_destroy_appinfo(handle);
                return false;
        }
+       pkgmgrinfo_appinfo_destroy_appinfo(handle);
+
        ret = pkgmgrinfo_appinfo_get_usr_appinfo(remote_appid, getuid(), &handle);
        if (ret != PMINFO_R_OK) {
                _LOGE("Failed to get the appinfo. %d", ret);
@@ -296,8 +357,19 @@ static void on_name_vanished(GDBusConnection *connection,
 {
        _LOGI("name vanished : %s", name);
        port_list_info_s *pli = (port_list_info_s *)user_data;
-       g_bus_unwatch_name(pli->watcher_id);
+       if (pli == NULL) {
+               LOGE("NULL port info");
+               return;
+       }
+
+       _LOGI("watcher_id :%d", pli->watcher_id);
+       if (pli->watcher_id > 0)
+               g_bus_unwatch_name(pli->watcher_id);
+       else
+               _LOGE("Invalid watcher_id %d", pli->watcher_id);
        pli->exist = false;
+       pli->watcher_id = 0;
+
 }
 
 static int __get_local_port_info(int id, message_port_local_port_info_s **info)
@@ -326,16 +398,12 @@ static port_list_info_s *__set_remote_port_info(const char *remote_app_id, const
                goto out;
        }
        port_info->is_trusted = is_trusted;
-
        port_info->encoded_bus_name = __get_encoded_name(remote_app_id, remote_port, is_trusted);
        if (port_info->encoded_bus_name == NULL) {
                ret_val = MESSAGEPORT_ERROR_OUT_OF_MEMORY;
                goto out;
        }
-
-       port_info->sock_pair[0] = 0;
-       port_info->sock_pair[1] = 0;
-
+       port_info->send_sock_fd = 0;
 out:
        if (ret_val != MESSAGEPORT_ERROR_NONE) {
                if (port_info) {
@@ -350,7 +418,6 @@ out:
 
 static message_port_remote_app_info_s *__set_remote_app_info(const char *remote_app_id, const char *remote_port, bool is_trusted)
 {
-       port_list_info_s *port_info = NULL;
        message_port_remote_app_info_s *remote_app_info = NULL;
        int ret_val = MESSAGEPORT_ERROR_NONE;
 
@@ -366,14 +433,6 @@ static message_port_remote_app_info_s *__set_remote_app_info(const char *remote_
                goto out;
        }
 
-       port_info = __set_remote_port_info(remote_app_id, remote_port, is_trusted);
-       if (port_info == NULL) {
-               ret_val = MESSAGEPORT_ERROR_OUT_OF_MEMORY;
-               goto out;
-       }
-
-       remote_app_info->port_list = g_list_append(remote_app_info->port_list, port_info);
-
 out:
        if (ret_val != MESSAGEPORT_ERROR_NONE) {
                if (remote_app_info) {
@@ -385,6 +444,62 @@ out:
        return remote_app_info;
 }
 
+static void __clear_disconnect_socket(port_list_info_s *port_info)
+{
+       GError *error = NULL;
+
+       if (port_info == NULL)
+               return;
+       _LOGI("__clear_disconnect_socket : fd [%d]", port_info->send_sock_fd);
+
+       if (port_info->gio_read != NULL) {
+               g_io_channel_shutdown(port_info->gio_read, TRUE, &error);
+               if (error) {
+                       _LOGE("g_io_channel_shutdown error : %s", error->message);
+                       g_error_free(error);
+               }
+               g_io_channel_unref(port_info->gio_read);
+               port_info->gio_read = NULL;
+       }
+
+       if (port_info->g_src_id != 0) {
+               g_source_remove(port_info->g_src_id);
+               port_info->g_src_id = 0;
+       }
+       port_info->send_sock_fd = 0;
+}
+
+static gboolean __socket_disconnect_handler(GIOChannel *gio,
+               GIOCondition cond,
+               gpointer data)
+{
+       /* It's sender socket's gio channel so, only EOF can be received */
+       port_list_info_s *port_info = (port_list_info_s *)data;
+       _LOGI("__socket_disconnect_handler %d", cond);
+       __clear_disconnect_socket(port_info);
+       return FALSE;
+}
+
+static void __watch_remote_port_info(port_list_info_s *port_info)
+{
+       if (port_info == NULL)
+               return;
+
+       if (port_info->watcher_id < 1) {
+               port_info->watcher_id = g_bus_watch_name_on_connection(
+                               __gdbus_conn,
+                               port_info->encoded_bus_name,
+                               G_BUS_NAME_WATCHER_FLAGS_NONE,
+                               on_name_appeared,
+                               on_name_vanished,
+                               port_info,
+                               NULL);
+       } else {
+               LOGI("Already watched port info");
+               return;
+       }
+}
+
 static int __get_remote_port_info(const char *remote_app_id, const char *remote_port, bool is_trusted,
                message_port_remote_app_info_s **mri, port_list_info_s **pli)
 {
@@ -393,7 +508,7 @@ static int __get_remote_port_info(const char *remote_app_id, const char *remote_
        GList *cb_list = NULL;
        int ret_val = MESSAGEPORT_ERROR_NONE;
 
-       remote_app_info = (message_port_remote_app_info_s *)g_hash_table_lookup(__remote_port_info, remote_app_id);
+       remote_app_info = (message_port_remote_app_info_s *)g_hash_table_lookup(__remote_app_info, remote_app_id);
 
        if (remote_app_info == NULL) {
                remote_app_info = __set_remote_app_info(remote_app_id, remote_port, is_trusted);
@@ -402,8 +517,7 @@ static int __get_remote_port_info(const char *remote_app_id, const char *remote_
                        ret_val = MESSAGEPORT_ERROR_OUT_OF_MEMORY;
                        goto out;
                }
-               g_hash_table_insert(__remote_port_info, remote_app_info->remote_app_id, remote_app_info);
-
+               g_hash_table_insert(__remote_app_info, remote_app_info->remote_app_id, remote_app_info);
        }
        *mri = remote_app_info;
 
@@ -415,18 +529,15 @@ static int __get_remote_port_info(const char *remote_app_id, const char *remote_
                free(port_info.port_name);
        if (cb_list == NULL) {
                port_list_info_s *tmp = __set_remote_port_info(remote_app_id, remote_port, is_trusted);
-
                if (tmp == NULL) {
                        ret_val = MESSAGEPORT_ERROR_OUT_OF_MEMORY;
                        goto out;
                }
                remote_app_info->port_list = g_list_append(remote_app_info->port_list, tmp);
                *pli = tmp;
-               g_hash_table_insert(__remote_port_info, (*pli)->encoded_bus_name, *pli);
        } else {
                *pli = (port_list_info_s *)cb_list->data;
        }
-
 out:
 
        return ret_val;
@@ -438,7 +549,6 @@ static bool __is_local_port_registed(const char *local_port, bool trusted, int *
        gpointer key, value;
 
        g_hash_table_iter_init(&iter, __local_port_info);
-
        while (g_hash_table_iter_next(&iter, &key, &value)) {
                message_port_local_port_info_s *mi = (message_port_local_port_info_s *)value;
 
@@ -546,6 +656,7 @@ static int __read_socket(int fd,
        unsigned int left = nbytes;
        ssize_t nb;
        int retry_cnt = 0;
+       const struct timespec TRY_SLEEP_TIME = { 0, 500 * 1000 * 1000 };
 
        *bytes_read = 0;
        while (left && (retry_cnt < MAX_RETRY_CNT)) {
@@ -554,9 +665,11 @@ static int __read_socket(int fd,
                        LOGE("__read_socket: ...read EOF, socket closed %d: nb %d\n", fd, nb);
                        return MESSAGEPORT_ERROR_IO_ERROR;
                } else if (nb == -1) {
-                       if (errno == EINTR) {
-                               LOGE("__read_socket: EINTR error continue ...");
+                       /*  wrt(nodejs) could change socket to none-blocking socket :-( */
+                       if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
+                               LOGE("__read_socket: %d errno, sleep and retry ...", errno);
                                retry_cnt++;
+                               nanosleep(&TRY_SLEEP_TIME, 0);
                                continue;
                        }
                        LOGE("__read_socket: ...error fd %d: errno %d\n", fd, errno);
@@ -578,7 +691,7 @@ static int __read_string_from_socket(int fd, char **buffer, int *string_len)
                LOGE("read socket fail");
                return MESSAGEPORT_ERROR_IO_ERROR;
        }
-       if (*string_len > 0) {
+       if (*string_len > 0 && *string_len < MAX_MESSAGE_SIZE) {
                *buffer = (char *)calloc(*string_len, sizeof(char));
                if (*buffer == NULL) {
                        LOGE("Out of memory.");
@@ -588,6 +701,9 @@ static int __read_string_from_socket(int fd, char **buffer, int *string_len)
                        LOGE("read socket fail");
                        return MESSAGEPORT_ERROR_IO_ERROR;
                }
+       } else {
+               LOGE("Invalid string len %d", *string_len);
+               return MESSAGEPORT_ERROR_IO_ERROR;
        }
        return MESSAGEPORT_ERROR_NONE;
 }
@@ -607,7 +723,6 @@ message_port_pkt_s *__message_port_recv_raw(int fd)
                LOGE("read socket fail: port_name");
                free(pkt->remote_port_name);
                free(pkt);
-               close(fd);
                return NULL;
        }
 
@@ -615,7 +730,6 @@ message_port_pkt_s *__message_port_recv_raw(int fd)
                LOGE("read socket fail: is_bidirection");
                free(pkt->remote_port_name);
                free(pkt);
-               close(fd);
                return NULL;
        }
 
@@ -623,15 +737,15 @@ message_port_pkt_s *__message_port_recv_raw(int fd)
                LOGE("read socket fail: is_trusted");
                free(pkt->remote_port_name);
                free(pkt);
-               close(fd);
                return NULL;
        }
 
        if (__read_string_from_socket(fd, (char **)&pkt->data, &pkt->data_len) != MESSAGEPORT_ERROR_NONE) {
                LOGE("read socket fail: data");
+               if (pkt->data)
+                       free(pkt->data);
                free(pkt->remote_port_name);
                free(pkt);
-               close(fd);
                return NULL;
        }
 
@@ -651,7 +765,7 @@ static gboolean __socket_request_handler(GIOChannel *gio,
        mi = (message_port_callback_info_s *)data;
        if (mi == NULL) {
 
-               g_io_channel_shutdown(gio, FALSE, &error);
+               g_io_channel_shutdown(gio, TRUE, &error);
                if (error) {
                        _LOGE("g_io_channel_shutdown error : %s", error->message);
                        g_error_free(error);
@@ -663,30 +777,30 @@ static gboolean __socket_request_handler(GIOChannel *gio,
        if (cond == G_IO_HUP) {
 
                _LOGI("socket G_IO_HUP");
-               __callback_info_free(mi);
+               __callback_info_free_by_info(mi);
                return FALSE;
 
        } else {
 
                if ((fd = g_io_channel_unix_get_fd(gio)) < 0) {
                        _LOGE("fail to get fd from io channel");
-                       __callback_info_free(mi);
+                       __callback_info_free_by_info(mi);
                        return FALSE;
                }
 
                if ((pkt = __message_port_recv_raw(fd)) == NULL) {
                        _LOGE("recv error on SOCKET");
-                       __callback_info_free(mi);
+                       __callback_info_free_by_info(mi);
                        return FALSE;
                }
 
                kb = bundle_decode(pkt->data, pkt->data_len);
-
                if (pkt->is_bidirection)
                        mi->callback(mi->local_id, mi->remote_app_id, pkt->remote_port_name, pkt->is_trusted, kb, NULL);
                else
                        mi->callback(mi->local_id, mi->remote_app_id, NULL, pkt->is_trusted, kb, NULL);
 
+               bundle_free(kb);
                if (pkt) {
                        if (pkt->remote_port_name)
                                free(pkt->remote_port_name);
@@ -713,10 +827,19 @@ static bool send_message(GVariant *parameters, GDBusMethodInvocation *invocation
        bundle *data = NULL;
        bundle_raw *raw = NULL;
        message_port_local_port_info_s *mi;
-       message_port_callback_info_s *callback_info;
        int local_reg_id = 0;
+       message_port_callback_info_s *callback_info;
+       message_port_callback_info_s *head_callback_info;
+       GList *callback_info_list = NULL;
+
+       char buf[1024];
+       GDBusMessage *msg;
+       GUnixFDList *fd_list;
+       int fd_len;
+       int *returned_fds = NULL;
+       int fd;
 
-       g_variant_get(parameters, "(ssbbssbus)", &local_appid, &local_port, &local_trusted, &bi_dir,
+       g_variant_get(parameters, "(&s&sbb&s&sbu&s)", &local_appid, &local_port, &local_trusted, &bi_dir,
                        &remote_appid, &remote_port, &remote_trusted, &len, &raw);
 
        if (!remote_port) {
@@ -754,7 +877,6 @@ static bool send_message(GVariant *parameters, GDBusMethodInvocation *invocation
        if (remote_trusted) {
                if (g_hash_table_lookup(__trusted_app_list_hash, (gpointer)local_appid) == NULL) {
                        if (!__is_preloaded(local_appid, remote_appid)) {
-                               /* Check the certificate */
                                int ret = __check_certificate(local_appid, remote_appid);
                                if (ret == MESSAGEPORT_ERROR_NONE)
                                        g_hash_table_insert(__trusted_app_list_hash, local_appid, "TRUE");
@@ -775,40 +897,60 @@ static bool send_message(GVariant *parameters, GDBusMethodInvocation *invocation
        callback_info->remote_app_id = strdup(local_appid);
        callback_info->callback = mi->callback;
 
-       GError *error = NULL;
-       GDBusMessage *msg = g_dbus_method_invocation_get_message(invocation);
+       msg = g_dbus_method_invocation_get_message(invocation);
+       fd_list = g_dbus_message_get_unix_fd_list(msg);
 
-       GUnixFDList *fd_list = g_dbus_message_get_unix_fd_list(msg);
-       int fd = g_unix_fd_list_get(fd_list, 0, &error);
-       if (error) {
-               LOGE("g_unix_fd_list_get fail : %s", error->message);
-               g_error_free(error);
-       }
+       /* When application send message to self fd_list is NULL */
+       if (fd_list != NULL) {
+               returned_fds = g_unix_fd_list_steal_fds(fd_list, &fd_len);
+               if (returned_fds == NULL) {
+                       _LOGE("fail to get fds");
+                       __callback_info_free(callback_info);
+                       return false;
+               }
+               fd = returned_fds[0];
 
-       LOGI("g_unix_fd_list_get fd: [%d]", fd);
+               LOGI("g_unix_fd_list_get %d fd: [%d]", fd_len, fd);
+               if (fd > 0) {
 
-       if (fd > 0) {
+                       callback_info->gio_read = g_io_channel_unix_new(fd);
+                       if (!callback_info->gio_read) {
+                               _LOGE("Error is %s\n", strerror_r(errno, buf, sizeof(buf)));
+                               __callback_info_free(callback_info);
+                               return false;
+                       }
 
-               callback_info->gio_read = g_io_channel_unix_new(fd);
-               if (!callback_info->gio_read) {
-                       _LOGE("Error is %s\n", strerror(errno));
-                       __callback_info_free(callback_info);
-                       return -1;
-               }
+                       callback_info->g_src_id = g_io_add_watch(callback_info->gio_read, G_IO_IN | G_IO_HUP,
+                                       __socket_request_handler, (gpointer)callback_info);
+                       if (callback_info->g_src_id == 0) {
+                               _LOGE("fail to add watch on socket");
+                               __callback_info_free(callback_info);
+                               return false;
+                       }
 
-               callback_info->g_src_id = g_io_add_watch(callback_info->gio_read, G_IO_IN | G_IO_HUP,
-                               __socket_request_handler, (gpointer)callback_info);
-               if (callback_info->g_src_id == 0) {
-                       _LOGE("fail to add watch on socket");
-                       __callback_info_free(callback_info);
-                       return -1;
+                       callback_info_list = g_hash_table_lookup(__callback_info_hash, GUINT_TO_POINTER(mi->local_id));
+                       if (callback_info_list == NULL) {
+                               head_callback_info = (message_port_callback_info_s *)calloc(1, sizeof(message_port_callback_info_s));
+                               if (head_callback_info == NULL) {
+                                       _LOGE("fail to alloc head_callback_info");
+                                       __callback_info_free(callback_info);
+                                       return false;
+                               }
+                               head_callback_info->local_id = 0;
+                               head_callback_info->remote_app_id = NULL;
+                               head_callback_info->callback = NULL;
+                               head_callback_info->gio_read = NULL;
+                               head_callback_info->g_src_id = 0;
+                               callback_info_list = g_list_append(callback_info_list, head_callback_info);
+                               callback_info_list = g_list_append(callback_info_list, callback_info);
+                               g_hash_table_insert(__callback_info_hash, GUINT_TO_POINTER(mi->local_id), callback_info_list);
+                       } else {
+                               callback_info_list = g_list_append(callback_info_list, callback_info);
+                       }
                }
-
        }
 
        data = bundle_decode(raw, len);
-       bundle_free_encoded_rawdata(&raw);
-
        if (!data) {
                _LOGE("Invalid argument : message");
                goto out;
@@ -819,8 +961,10 @@ static bool send_message(GVariant *parameters, GDBusMethodInvocation *invocation
                mi->callback(mi->local_id, local_appid, local_port, local_trusted, data, NULL);
        else
                mi->callback(mi->local_id, local_appid, NULL, false, data, NULL);
-
+       bundle_free(data);
 out:
+       if (returned_fds)
+               free(returned_fds);
 
        return true;
 }
@@ -845,7 +989,6 @@ static int __check_remote_port(const char *remote_app_id, const char *remote_por
        if (ret_val != MESSAGEPORT_ERROR_NONE)
                return ret_val;
 
-
        /* self check */
        if (strcmp(remote_app_id, __app_id) == 0) {
 
@@ -885,7 +1028,7 @@ static int __check_remote_port(const char *remote_app_id, const char *remote_por
                g_variant_get(result, "(b)", &name_exist);
 
                if (!name_exist) {
-                       LOGE("Name not exist %s", bus_name);
+                       _LOGI("Name not exist %s", bus_name);
                        *exist = false;
                        ret_val = MESSAGEPORT_ERROR_NONE;
                } else {
@@ -901,22 +1044,11 @@ static int __check_remote_port(const char *remote_app_id, const char *remote_por
                                        remote_app_info->certificate_info = CERTIFICATE_MATCH;
                                }
                        }
-
-                       port_info->watcher_id = g_bus_watch_name_on_connection(
-                                       __gdbus_conn,
-                                       port_info->encoded_bus_name,
-                                       G_BUS_NAME_WATCHER_FLAGS_NONE,
-                                       on_name_appeared,
-                                       on_name_vanished,
-                                       port_info,
-                                       NULL);
-
                        port_info->exist = true;
                        *exist = true;
                        ret_val = MESSAGEPORT_ERROR_NONE;
-                       _LOGI("Exist port: %s", bus_name);
+                       __watch_remote_port_info(port_info);
                }
-
        }
 out:
        if (result)
@@ -925,24 +1057,70 @@ out:
        return ret_val;
 }
 
+static void __on_sender_name_appeared(GDBusConnection *connection,
+               const gchar     *name,
+               const gchar     *name_owner,
+               gpointer         user_data)
+{
+       _LOGI("sender name appeared : %s", name);
+}
+
+static void __on_sender_name_vanished(GDBusConnection *connection,
+               const gchar     *name,
+               gpointer         user_data)
+{
+       gboolean remove_result = FALSE;
+       int *watcher_id = (int *)user_data;
+       remove_result = g_hash_table_remove(__sender_appid_hash, (gpointer)name);
+       if (!remove_result)
+               _LOGE("Fail to remove sender appid from hash : %s", name);
+
+       if (watcher_id) {
+               if (*watcher_id > 0)
+                       g_bus_unwatch_name(*watcher_id);
+               else
+                       LOGE("Invalid watcher_id %d", *watcher_id);
+               free(watcher_id);
+       } else {
+               LOGE("watcher_id is NULL");
+       }
+}
+
 static bool __check_sender_validation(GVariant *parameters, const char *sender, GDBusConnection *conn)
 {
        int ret = 0;
        char buffer[MAX_PACKAGE_STR_SIZE] = {0, };
        char *local_appid = NULL;
        int pid = __get_sender_pid(conn, sender);
+       int *watcher_id = (int *)calloc(1, sizeof(int));
 
        ret = aul_app_get_appid_bypid(pid, buffer, sizeof(buffer));
-       retvm_if(ret != AUL_R_OK, false, "Failed to get the sender ID: (%s) (%d)", sender, pid);
+       if (ret != AUL_R_OK) {
+               _LOGE("Failed to get the sender ID: (%s) (%d)", sender, pid);
+               free(watcher_id);
+               return false;
+       }
 
-       g_variant_get_child(parameters, 0, "s", &local_appid);
-       retvm_if(!local_appid, false, "remote_appid is NULL (%s) (%d)", sender, pid);
+       g_variant_get_child(parameters, 0, "&s", &local_appid);
+       if (local_appid == NULL) {
+               _LOGE("appid is NULL : (%s) (%d)", sender, pid);
+               free(watcher_id);
+               return false;
+       }
 
        if (strncmp(buffer, local_appid, MAX_PACKAGE_STR_SIZE) == 0) {
-               g_hash_table_insert(__sender_appid_hash, strdup(sender), GINT_TO_POINTER(pid));
-               g_free(local_appid);
+               _LOGI("insert sender !!!!! %s", sender);
+               g_hash_table_insert(__sender_appid_hash, (gpointer)strdup(sender), GINT_TO_POINTER(pid));
+               *watcher_id = g_bus_watch_name_on_connection(
+                                       __gdbus_conn,
+                                       sender,
+                                       G_BUS_NAME_WATCHER_FLAGS_NONE,
+                                       __on_sender_name_appeared,
+                                       __on_sender_name_vanished,
+                                       watcher_id,
+                                       NULL);
        } else {
-               g_free(local_appid);
+               free(watcher_id);
                return false;
        }
        return true;
@@ -954,16 +1132,16 @@ static void __dbus_method_call_handler(GDBusConnection *conn,
                                GVariant *parameters, GDBusMethodInvocation *invocation,
                                gpointer user_data)
 {
-       _LOGI("method_name: %s", method_name);
+       _LOGI("method_name: %s, sender: %s", method_name, sender);
        gpointer sender_pid = g_hash_table_lookup(__sender_appid_hash, sender);
        if (sender_pid == NULL) {
                if (!__check_sender_validation(parameters, sender, conn))
-                       return;
+                       goto out;
        }
-
        if (g_strcmp0(method_name, "send_message") == 0)
                send_message(parameters, invocation);
-
+out:
+       g_dbus_method_invocation_return_value(invocation, NULL);
 }
 
 static const GDBusInterfaceVTable interface_vtable = {
@@ -996,7 +1174,6 @@ out:
 
 }
 
-
 int __register_dbus_interface(const char *port_name, bool is_trusted)
 {
 
@@ -1064,6 +1241,7 @@ int __register_dbus_interface(const char *port_name, bool is_trusted)
                        &error);
        if (error) {
                _LOGE("RequestName fail : %s", error->message);
+               g_error_free(error);
                goto out;
        }
        if (result == NULL) {
@@ -1111,7 +1289,7 @@ out:
        return registration_id;
 }
 
-
+/* LCOV_EXCL_START */
 void __list_free_port_list(gpointer data)
 {
        port_list_info_s *n = (port_list_info_s *)data;
@@ -1120,24 +1298,34 @@ void __list_free_port_list(gpointer data)
        FREE_AND_NULL(n->port_name);
        FREE_AND_NULL(n);
 }
+/* LCOV_EXCL_STOP */
 
+/* LCOV_EXCL_START */
 static void __hash_destory_local_value(gpointer data)
 {
        message_port_local_port_info_s *mli = (message_port_local_port_info_s *)data;
-       if (mli->port_name)
-               free(mli->port_name);
+       if (mli) {
+               if (mli->port_name)
+                       free(mli->port_name);
+               free(mli);
+       }
 }
+/* LCOV_EXCL_STOP */
+
+/* LCOV_EXCL_START */
 static void __hash_destory_remote_value(gpointer data)
 {
        message_port_remote_app_info_s *mri = (message_port_remote_app_info_s *)data;
-
        if (mri) {
                FREE_AND_NULL(mri->sender_id);
                FREE_AND_NULL(mri->remote_app_id);
                if (mri->port_list)
                        g_list_free_full(mri->port_list, __list_free_port_list);
+
+               free(mri);
        }
 }
+/* LCOV_EXCL_STOP */
 
 static bool __initialize(void)
 {
@@ -1163,13 +1351,13 @@ static bool __initialize(void)
                retvm_if(!__local_port_info, false, "fail to create __local_port_info");
        }
 
-       if (__remote_port_info == NULL) {
-               __remote_port_info = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, __hash_destory_remote_value);
-               retvm_if(!__remote_port_info, false, "fail to create __remote_port_info");
+       if (__remote_app_info == NULL) {
+               __remote_app_info = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, __hash_destory_remote_value);
+               retvm_if(!__remote_app_info, false, "fail to create __remote_app_info");
        }
 
        if (__sender_appid_hash == NULL) {
-               __sender_appid_hash = g_hash_table_new(g_str_hash, g_str_equal);
+               __sender_appid_hash = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
                retvm_if(!__sender_appid_hash, false, "fail to create __sender_appid_hash");
        }
 
@@ -1178,6 +1366,11 @@ static bool __initialize(void)
                retvm_if(!__trusted_app_list_hash, false, "fail to create __trusted_app_list_hash");
        }
 
+       if (__callback_info_hash == NULL) {
+               __callback_info_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, __hash_destroy_callback_info);
+               retvm_if(!__trusted_app_list_hash, false, "fail to create __trusted_app_list_hash");
+       }
+
        if (!__dbus_init())
                return false;
        _initialized = true;
@@ -1236,40 +1429,44 @@ int __message_port_send_async(int sockfd, bundle *kb, const char *local_port,
        unsigned int nb;
        bundle_raw *kb_data = NULL;
 
+       bundle_encode(kb, &kb_data, &data_len);
+       if (kb_data == NULL) {
+               _LOGE("bundle encode fail");
+               ret = MESSAGEPORT_ERROR_IO_ERROR;
+               goto out;
+       }
+
+       if (data_len > MAX_MESSAGE_SIZE) {
+               _LOGE("bigger than max size\n");
+               ret = MESSAGEPORT_ERROR_MAX_EXCEEDED;
+               goto out;
+       }
+
        if (local_port != NULL)
                local_port_len = strlen(local_port) + 1;
 
        if (__write_string_to_socket(sockfd, local_port, local_port_len) != MESSAGEPORT_ERROR_NONE) {
                _LOGE("write local_port fail");
-               return MESSAGEPORT_ERROR_IO_ERROR;
+               ret = MESSAGEPORT_ERROR_IO_ERROR;
+               goto out;
        }
 
        if (__write_socket(sockfd, (char *)&is_bidirection, sizeof(is_bidirection), &nb) != MESSAGEPORT_ERROR_NONE) {
                _LOGE("write is_bidirection fail");
-               return MESSAGEPORT_ERROR_IO_ERROR;
+               ret = MESSAGEPORT_ERROR_IO_ERROR;
+               goto out;
        }
 
        if (__write_socket(sockfd, (char *)&local_trusted, sizeof(local_trusted), &nb) != MESSAGEPORT_ERROR_NONE) {
                _LOGE("write local_trusted fail");
-               return MESSAGEPORT_ERROR_IO_ERROR;
-       }
-
-       bundle_encode(kb, &kb_data, &data_len);
-       if (kb_data == NULL) {
-               _LOGE("bundle encode fail");
                ret = MESSAGEPORT_ERROR_IO_ERROR;
                goto out;
        }
 
-       if (data_len > MAX_MESSAGE_SIZE) {
-               _LOGE("bigger than max size\n");
-               ret = MESSAGEPORT_ERROR_MAX_EXCEEDED;
-               goto out;
-       }
-
        if (__write_string_to_socket(sockfd, (void *)kb_data, data_len) != MESSAGEPORT_ERROR_NONE) {
                _LOGE("write kb_data fail");
                ret = MESSAGEPORT_ERROR_IO_ERROR;
+               goto out;
        }
 out:
        if (kb_data)
@@ -1284,7 +1481,6 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
 
        int ret = MESSAGEPORT_ERROR_NONE;
        GUnixFDList *fd_list = NULL;
-       GError *error = NULL;
 
        int len = 0;
        bundle_raw *raw = NULL;
@@ -1296,6 +1492,8 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
        GDBusMessage *msg = NULL;
        GError *err = NULL;
        GVariant *body = NULL;
+       int sock_pair[2] = {0,};
+       char buf[1024];
 
        ret = __get_remote_port_info(remote_appid, remote_port, trusted_message, &remote_app_info, &port_info);
        if (ret != MESSAGEPORT_ERROR_NONE)
@@ -1313,8 +1511,8 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
                }
        }
 
-       if (port_info->sock_pair[0] > 0) {
-               ret = __message_port_send_async(port_info->sock_pair[0], message,
+       if (port_info->send_sock_fd > 0) {
+               ret = __message_port_send_async(port_info->send_sock_fd, message,
                                (local_port) ? local_port : "", local_trusted, bi_dir);
        } else {
 
@@ -1329,33 +1527,49 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
                if (MAX_MESSAGE_SIZE < len) {
                        _LOGE("The size of message (%d) has exceeded the maximum limit.", len);
                        ret = MESSAGEPORT_ERROR_MAX_EXCEEDED;
+                       goto out;
                }
 
                body = g_variant_new("(ssbbssbus)", __app_id, (local_port) ? local_port : "", local_trusted, bi_dir,
                                remote_appid, remote_port, trusted_message, len, raw);
-
-
                if (strcmp(remote_appid, __app_id) != 0) { /* self send */
 
                        /*  if message-port fail to get socket pair, communicate using GDBus */
-                       if (aul_request_message_port_socket_pair(port_info->sock_pair) != AUL_R_OK) {
+                       if (aul_request_message_port_socket_pair(sock_pair) != AUL_R_OK) {
                                _LOGE("error create socket pair");
                        } else {
 
-                               _LOGI("sock pair : %d, %d", port_info->sock_pair[0], port_info->sock_pair[1]);
-
+                               _LOGI("sock pair : %d, %d",
+                                               sock_pair[SOCK_PAIR_SENDER], sock_pair[SOCK_PAIR_RECEIVER]);
                                fd_list = g_unix_fd_list_new();
-                               g_unix_fd_list_append(fd_list, port_info->sock_pair[1], &err);
-                               g_unix_fd_list_append(fd_list, port_info->sock_pair[0], &err);
-
+                               g_unix_fd_list_append(fd_list, sock_pair[SOCK_PAIR_RECEIVER], &err);
                                if (err != NULL) {
-                                       _LOGE("g_unix_fd_list_append [%s]", error->message);
+                                       _LOGE("g_unix_fd_list_append [%s]", err->message);
                                        ret = MESSAGEPORT_ERROR_IO_ERROR;
                                        g_error_free(err);
                                        goto out;
                                }
-                       }
 
+                               port_info->send_sock_fd = sock_pair[SOCK_PAIR_SENDER];
+                               close(sock_pair[SOCK_PAIR_RECEIVER]);
+                               sock_pair[SOCK_PAIR_RECEIVER] = 0;
+
+                               port_info->gio_read = g_io_channel_unix_new(port_info->send_sock_fd);
+                               if (!port_info->gio_read) {
+                                       _LOGE("Error is %s\n", strerror_r(errno, buf, sizeof(buf)));
+                                       ret = MESSAGEPORT_ERROR_IO_ERROR;
+                                       goto out;
+                               }
+
+                               port_info->g_src_id = g_io_add_watch(port_info->gio_read, G_IO_IN | G_IO_HUP,
+                                               __socket_disconnect_handler, (gpointer)port_info);
+                               if (port_info->g_src_id == 0) {
+                                       _LOGE("fail to add watch on socket");
+                                       ret = MESSAGEPORT_ERROR_IO_ERROR;
+                                       goto out;
+                               }
+
+                       }
                }
 
                msg = g_dbus_message_new_method_call(bus_name, MESSAGEPORT_OBJECT_PATH, interface_name, "send_message");
@@ -1367,7 +1581,6 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
 
                g_dbus_message_set_unix_fd_list(msg, fd_list);
                g_dbus_message_set_body(msg, body);
-               g_dbus_message_set_flags(msg, G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED);
                g_dbus_connection_send_message(__gdbus_conn, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &err);
                if (err != NULL) {
                        _LOGE("No reply. error = %s", err->message);
@@ -1375,7 +1588,7 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
                        ret = MESSAGEPORT_ERROR_IO_ERROR;
                        goto out;
                }
-
+               __watch_remote_port_info(port_info);
 
        }
 
@@ -1387,6 +1600,13 @@ out:
        if (fd_list)
                g_object_unref(fd_list);
 
+       if (ret != MESSAGEPORT_ERROR_NONE) {
+               __clear_disconnect_socket(port_info);
+               if (sock_pair[SOCK_PAIR_SENDER])
+                       close(sock_pair[SOCK_PAIR_SENDER]);
+               if (sock_pair[SOCK_PAIR_RECEIVER])
+                       close(sock_pair[SOCK_PAIR_RECEIVER]);
+       }
 
        return ret;
 }
@@ -1403,6 +1623,92 @@ int __message_send_bidirectional_message(int id, const char *remote_app_id, cons
                        local_info->port_name, trusted_message, local_info->is_trusted, true, message);
 }
 
+static void __name_registered(GDBusConnection *connection,
+               const gchar *name,
+               const gchar *name_owner,
+               gpointer user_data)
+{
+
+       registered_callback_info_s *info = (registered_callback_info_s *)user_data;
+       if (info == NULL) {
+               LOGE("NULL registered_callback_info");
+               return;
+       }
+
+       _LOGI("watcher_id : %d, appeared name : %s , name_owner : %s\n", info->watcher_id, name, name_owner);
+       if (info->registered_cb)
+               info->registered_cb(info->remote_app_id, info->remote_port, info->is_trusted, info->user_data);
+}
+
+static void __name_unregistered(GDBusConnection *connection,
+               const gchar *name,
+               gpointer user_data)
+{
+
+       registered_callback_info_s *info = (registered_callback_info_s *)user_data;
+       if (info == NULL) {
+               LOGE("NULL registered_callback_info");
+               return;
+       }
+
+       _LOGI("watcher_id : %d, vanished name : %s\n", info->watcher_id, name);
+       if (info->unregistered_cb)
+               info->unregistered_cb(info->remote_app_id, info->remote_port, info->is_trusted, info->user_data);
+}
+
+int __messageport_watch_remote_port(int *watcher_id, const char *remote_app_id, const char *remote_port, bool trusted_remote_port, messageport_registration_event_cb registered_cb, messageport_registration_event_cb unregistered_cb, void *user_data)
+{
+       int ret_val = MESSAGEPORT_ERROR_NONE;
+       message_port_remote_app_info_s *remote_app_info = NULL;
+       port_list_info_s *port_info = NULL;
+
+       _LOGI("remote_app_id, app_id :[%s : %s] ", remote_app_id, __app_id);
+
+       ret_val = __get_remote_port_info(remote_app_id, remote_port, trusted_remote_port, &remote_app_info, &port_info);
+       if (ret_val != MESSAGEPORT_ERROR_NONE)
+               return ret_val;
+
+       if (__registered_callback_info_hash == NULL)
+               __registered_callback_info_hash = g_hash_table_new_full(g_direct_hash,  g_direct_equal, NULL, __registered_callback_info_free);
+
+       registered_callback_info_s *registered_cb_info = (registered_callback_info_s *)calloc(1, sizeof(registered_callback_info_s));
+       registered_cb_info->registered_cb = registered_cb;
+       registered_cb_info->unregistered_cb = unregistered_cb;
+       registered_cb_info->user_data = user_data;
+       registered_cb_info->remote_app_id = strdup(remote_app_info->remote_app_id);
+       if (registered_cb_info->remote_app_id == NULL) {
+               free(registered_cb_info);
+               return MESSAGEPORT_ERROR_OUT_OF_MEMORY;
+       }
+       registered_cb_info->remote_port = strdup(port_info->port_name);
+       if (registered_cb_info->remote_port == NULL) {
+               free(registered_cb_info->remote_app_id);
+               free(registered_cb_info);
+               return MESSAGEPORT_ERROR_OUT_OF_MEMORY;
+       }
+
+       registered_cb_info->watcher_id = g_bus_watch_name_on_connection(
+                       __gdbus_conn,
+                       port_info->encoded_bus_name,
+                       G_BUS_NAME_WATCHER_FLAGS_NONE,
+                       __name_registered,
+                       __name_unregistered,
+                       registered_cb_info,
+                       NULL);
+       if (registered_cb_info->watcher_id == 0) {
+               free(registered_cb_info->remote_app_id);
+               free(registered_cb_info->remote_port);
+               free(registered_cb_info);
+               return MESSAGEPORT_ERROR_IO_ERROR;
+       }
+
+       g_hash_table_insert(__registered_callback_info_hash,
+                       GINT_TO_POINTER(registered_cb_info->watcher_id), registered_cb_info);
+
+       *watcher_id = registered_cb_info->watcher_id;
+       return MESSAGEPORT_ERROR_NONE;
+}
+
 int messageport_unregister_local_port(int local_port_id, bool trusted_port)
 {
 
@@ -1422,6 +1728,8 @@ int messageport_unregister_local_port(int local_port_id, bool trusted_port)
        if (mi->is_trusted != trusted_port)
                return MESSAGEPORT_ERROR_INVALID_PARAMETER;
 
+       g_hash_table_remove(__callback_info_hash, GUINT_TO_POINTER(local_port_id));
+
        bus_name = __get_encoded_name(__app_id, mi->port_name, mi->is_trusted);
        if (bus_name == NULL)
                return MESSAGEPORT_ERROR_OUT_OF_MEMORY;
@@ -1565,32 +1873,42 @@ int messageport_send_bidirectional_trusted_message(int id, const char *remote_ap
        return __message_send_bidirectional_message(id, remote_app_id, remote_port, true, message);
 }
 
-int messageport_get_local_port_name(int id, char **name)
+int messageport_add_registered_cb(const char *remote_app_id, const char *remote_port, bool is_trusted, messageport_registration_event_cb registered_cb, void *user_data, int *watcher_id)
 {
-       message_port_local_port_info_s *local_info;
-       int ret = __get_local_port_info(id, &local_info);
+       if (!_initialized) {
+               if (!__initialize())
+                       return MESSAGEPORT_ERROR_IO_ERROR;
+       }
+       return __messageport_watch_remote_port(watcher_id, remote_app_id, remote_port, is_trusted, registered_cb, NULL, user_data);
+}
 
-       if (ret != MESSAGEPORT_ERROR_NONE)
-               return ret;
+int messageport_add_unregistered_cb(const char *remote_app_id, const char *remote_port, bool is_trusted, messageport_registration_event_cb unregistered_cb, void *user_data, int *watcher_id)
+{
+       if (!_initialized) {
+               if (!__initialize())
+                       return MESSAGEPORT_ERROR_IO_ERROR;
+       }
+       return __messageport_watch_remote_port(watcher_id, remote_app_id, remote_port, is_trusted, NULL, unregistered_cb, user_data);
+}
 
-       *name = strdup(local_info->port_name);
 
-       if (*name == NULL)
-               return MESSAGEPORT_ERROR_OUT_OF_MEMORY;
+int messageport_remove_registration_event_cb(int watcher_id)
+{
+       registered_callback_info_s *registered_cb_info = NULL;
+       gboolean remove_result = FALSE;
 
-       return MESSAGEPORT_ERROR_NONE;
-}
+       if (watcher_id < 1)
+               return MESSAGEPORT_ERROR_INVALID_PARAMETER;
 
-int messageport_check_trusted_local_port(int id, bool *trusted)
-{
-       message_port_local_port_info_s *local_info;
-       int ret = __get_local_port_info(id, &local_info);
+       registered_cb_info = g_hash_table_lookup(__registered_callback_info_hash, GINT_TO_POINTER(watcher_id));
+       if (registered_cb_info == NULL)
+               return MESSAGEPORT_ERROR_INVALID_PARAMETER;
 
-       if (ret != MESSAGEPORT_ERROR_NONE)
-               return ret;
+       remove_result = g_hash_table_remove(__registered_callback_info_hash, GINT_TO_POINTER(watcher_id));
+       if (!remove_result)
+               return MESSAGEPORT_ERROR_IO_ERROR;
 
-       *trusted = local_info->is_trusted;
+       g_bus_unwatch_name(watcher_id);
 
-       return MESSAGEPORT_ERROR_NONE;;
+       return MESSAGEPORT_ERROR_NONE;
 }
-