diff options
author | Sung-jae Park <nicesj.park@samsung.com> | 2014-11-23 10:37:40 +0900 |
---|---|---|
committer | Sung-jae Park <nicesj.park@samsung.com> | 2014-11-23 10:57:13 +0900 |
commit | 11203dee088ed592d4c04e18a68f5ee72551aa4a (patch) | |
tree | 313ab48f67812e5af23cb132dc864711185d64ae | |
parent | c5f0c7269cdc75f01586b6a2a5802565a8386d7d (diff) | |
download | com-core-11203dee088ed592d4c04e18a68f5ee72551aa4a.tar.gz com-core-11203dee088ed592d4c04e18a68f5ee72551aa4a.tar.bz2 com-core-11203dee088ed592d4c04e18a68f5ee72551aa4a.zip |
Add new method for sending/receving file descriptors
between local processes.
[model] Redwood,Kiran,B3(Wearable)
[binary_type] AP
[customer] Docomo/Orange/ATT/Open
[issue#] N/A
[problem]
[cause]
[solution]
[team] HomeTF
[request]
[horizontal_expansion]
Change-Id: Ifbcbae54f95c176bf585d3be2f6266460bd27434
-rw-r--r-- | include/com-core.h | 28 | ||||
-rw-r--r-- | include/com-core_thread.h | 3 | ||||
-rw-r--r-- | include/secure_socket.h | 10 | ||||
-rw-r--r-- | packaging/libcom-core.spec | 2 | ||||
-rw-r--r-- | src/com-core.c | 1030 | ||||
-rw-r--r-- | src/com-core_packet.c | 1078 | ||||
-rw-r--r-- | src/com-core_thread.c | 1385 | ||||
-rw-r--r-- | src/secure_socket.c | 785 |
8 files changed, 2217 insertions, 2104 deletions
diff --git a/include/com-core.h b/include/com-core.h index 0631a71..16d743c 100644 --- a/include/com-core.h +++ b/include/com-core.h @@ -133,6 +133,34 @@ extern int com_core_recv(int handle, char *buffer, int size, int *sender_pid, do */ extern int com_core_send(int handle, const char *buffer, int size, double timeout); +/** + * @brief + * @details + * @remarks + * @param[in] handle + * @param[in] buffer + * @param[in] size + * @param[in] timeout + * @param[in] fd + * @return int + * @retval + * @sa + */ +extern int com_core_send_with_fd(int handle, const char *buffer, int size, double timeout, int fd); + +/** + * @brief + * @details + * @remarks + * @param[in] handle + * @param[out] buffer + * @param[in] size + * @param[out] sender_pid + * @param[in] timeout + * @param[out] fd + */ +extern int com_core_recv_with_fd(int handle, char *buffer, int size, int *sender_pid, double timeout, int *fd); + #ifdef __cplusplus } #endif diff --git a/include/com-core_thread.h b/include/com-core_thread.h index 9e28314..a2463a2 100644 --- a/include/com-core_thread.h +++ b/include/com-core_thread.h @@ -31,6 +31,9 @@ extern int com_core_thread_client_destroy(int handle); extern int com_core_thread_recv(int handle, char *buffer, int size, int *sender_pid, double timeout); extern int com_core_thread_send(int handle, const char *buffer, int size, double timeout); +extern int com_core_thread_recv_with_fd(int handle, char *buffer, int size, int *sender_pid, double timeout, int *fd); +extern int com_core_thread_send_with_fd(int handle, const char *buffer, int size, double timeout, int fd); + #ifdef __cplusplus } #endif diff --git a/include/secure_socket.h b/include/secure_socket.h index b53e52c..8c9d76b 100644 --- a/include/secure_socket.h +++ b/include/secure_socket.h @@ -81,25 +81,27 @@ extern int secure_socket_get_connection_handle(int server_handle); * \param[in] conn * \param[in] buffer * \param[in] size + * \param[in] fd Shared fd which will be used from receiver process. * \return int * \retval * \sa */ -extern int secure_socket_send(int conn, const char *buffer, int size); +extern int secure_socket_send(int conn, const char *buffer, int size, int fd); /*! * \brief Recv data from the connected peer. and its PID value * \details N/A * \remarks N/A * \param[in] connn - * \param[in] buffer + * \param[out] buffer * \param[in] size - * \param[in] sender_pid + * \param[out] sender_pid + * \param[out] fd shared fd which is comes from sender process. * \return int * \retval * \sa */ -extern int secure_socket_recv(int conn, char *buffer, int size, int *sender_pid); +extern int secure_socket_recv(int conn, char *buffer, int size, int *sender_pid, int *fd); /*! * \brief Destroy a connection diff --git a/packaging/libcom-core.spec b/packaging/libcom-core.spec index ebd5bd5..e20f156 100644 --- a/packaging/libcom-core.spec +++ b/packaging/libcom-core.spec @@ -1,6 +1,6 @@ Name: libcom-core Summary: Library for the light-weight IPC -Version: 0.6.0 +Version: 0.7.0 Release: 1 Group: Base/IPC License: Apache-2.0 diff --git a/src/com-core.c b/src/com-core.c index f1973f7..bf627e6 100644 --- a/src/com-core.c +++ b/src/com-core.c @@ -37,643 +37,657 @@ #include "util.h" static struct { - struct dlist *watch_list; - struct dlist *conn_cb_list; - struct dlist *disconn_cb_list; - enum processing_event_callback { - PROCESSING_NONE = 0x0, - PROCESSING_DISCONNECTION = 0x01, - PROCESSING_CONNECTION = 0x02, - } processing_event_callback; + struct dlist *watch_list; + struct dlist *conn_cb_list; + struct dlist *disconn_cb_list; + enum processing_event_callback { + PROCESSING_NONE = 0x0, + PROCESSING_DISCONNECTION = 0x01, + PROCESSING_CONNECTION = 0x02, + } processing_event_callback; } s_info = { - .watch_list = NULL, - .conn_cb_list = NULL, - .disconn_cb_list = NULL, - .processing_event_callback = PROCESSING_NONE, + .watch_list = NULL, + .conn_cb_list = NULL, + .disconn_cb_list = NULL, + .processing_event_callback = PROCESSING_NONE, }; struct watch_item { - int server_fd; - int fd; - guint id; - void *cbdata; + int server_fd; + int fd; + guint id; + void *cbdata; }; struct cbdata { - int (*service_cb)(int fd, void *data); - void *data; + int (*service_cb)(int fd, void *data); + void *data; }; struct evtdata { - int deleted; - int (*evt_cb)(int fd, void *data); - void *data; + int deleted; + int (*evt_cb)(int fd, void *data); + void *data; }; static int watch_item_create(int server_fd, int handle, guint id, void *cbdata) { - struct watch_item *item; + struct watch_item *item; - item = malloc(sizeof(*item)); - if (!item) { - return -ENOMEM; - } + item = malloc(sizeof(*item)); + if (!item) { + return -ENOMEM; + } - item->server_fd = server_fd; - item->fd = handle; - item->id = id; - item->cbdata = cbdata; + item->server_fd = server_fd; + item->fd = handle; + item->id = id; + item->cbdata = cbdata; - DbgPrint("Watch Item is created for %d/%d\n", server_fd, handle); - s_info.watch_list = dlist_append(s_info.watch_list, item); - return 0; + DbgPrint("Watch Item is created for %d/%d\n", server_fd, handle); + s_info.watch_list = dlist_append(s_info.watch_list, item); + return 0; } static int watch_item_destroy(int handle, int remove_id, int remove_cbdata) { - struct dlist *l; - struct dlist *n; - struct watch_item *item; + struct dlist *l; + struct dlist *n; + struct watch_item *item; - dlist_foreach_safe(s_info.watch_list, l, n, item) { - if (item->fd == handle) { - s_info.watch_list = dlist_remove(s_info.watch_list, l); + dlist_foreach_safe(s_info.watch_list, l, n, item) { + if (item->fd == handle) { + s_info.watch_list = dlist_remove(s_info.watch_list, l); - DbgPrint("Watch item is destroyed for %d/%d\n", item->server_fd, item->fd); + DbgPrint("Watch item is destroyed for %d/%d\n", item->server_fd, item->fd); - if (remove_id && item->id) { - g_source_remove(item->id); - } + if (remove_id && item->id) { + g_source_remove(item->id); + } - if (remove_cbdata && item->cbdata) { - free(item->cbdata); - } + if (remove_cbdata && item->cbdata) { + free(item->cbdata); + } - free(item); - return 0; - } + free(item); + return 0; } + } - DbgPrint("No entry found\n"); - return -ENOENT; + DbgPrint("No entry found\n"); + return -ENOENT; } static void watch_item_destroy_all(int socket_fd) { - struct dlist *l; - struct dlist *n; - struct watch_item *item; - - dlist_foreach_safe(s_info.watch_list, l, n, item) { - if (item->server_fd == socket_fd) { - DbgPrint("Watch item removed: %d/%d\n", item->server_fd, item->fd); - /*! - * \WARN - * If the watch_list item is removed from disconnected - * callback, this list loop can be broken. - * Please check it again. - */ - invoke_disconn_cb_list(item->fd, 0, 0, 0); - - s_info.watch_list = dlist_remove(s_info.watch_list, l); - if (item->id > 0) { - g_source_remove(item->id); - } - free(item->cbdata); - free(item); - } - } + struct dlist *l; + struct dlist *n; + struct watch_item *item; + + dlist_foreach_safe(s_info.watch_list, l, n, item) { + if (item->server_fd == socket_fd) { + DbgPrint("Watch item removed: %d/%d\n", item->server_fd, item->fd); + /*! + * \WARN + * If the watch_list item is removed from disconnected + * callback, this list loop can be broken. + * Please check it again. + */ + invoke_disconn_cb_list(item->fd, 0, 0, 0); + + s_info.watch_list = dlist_remove(s_info.watch_list, l); + if (item->id > 0) { + g_source_remove(item->id); + } + free(item->cbdata); + free(item); + } + } } HAPI void invoke_con_cb_list(int server_fd, int handle, guint id, void *data, int watch) { - struct dlist *l; - struct dlist *n; - struct evtdata *cbdata; - - if (watch) { - if (watch_item_create(server_fd, handle, id, data) < 0) { - ErrPrint("Failed to create a watch item\n"); - } - } - - s_info.processing_event_callback |= PROCESSING_CONNECTION; - dlist_foreach_safe(s_info.conn_cb_list, l, n, cbdata) { - /*! - * \NOTE - * cbdata->deleted must has to be checked before call the function and - * return from the function call. - */ - if (cbdata->deleted || cbdata->evt_cb(handle, cbdata->data) < 0 || cbdata->deleted) { - s_info.conn_cb_list = dlist_remove(s_info.conn_cb_list, l); - free(cbdata); - } - } - s_info.processing_event_callback &= ~PROCESSING_CONNECTION; + struct dlist *l; + struct dlist *n; + struct evtdata *cbdata; + + if (watch) { + if (watch_item_create(server_fd, handle, id, data) < 0) { + ErrPrint("Failed to create a watch item\n"); + } + } + + s_info.processing_event_callback |= PROCESSING_CONNECTION; + dlist_foreach_safe(s_info.conn_cb_list, l, n, cbdata) { + /*! + * \NOTE + * cbdata->deleted must has to be checked before call the function and + * return from the function call. + */ + if (cbdata->deleted || cbdata->evt_cb(handle, cbdata->data) < 0 || cbdata->deleted) { + s_info.conn_cb_list = dlist_remove(s_info.conn_cb_list, l); + free(cbdata); + } + } + s_info.processing_event_callback &= ~PROCESSING_CONNECTION; } HAPI void invoke_disconn_cb_list(int handle, int remove_id, int remove_data, int watch) { - struct dlist *l; - struct dlist *n; - struct evtdata *cbdata; - - s_info.processing_event_callback |= PROCESSING_DISCONNECTION; - dlist_foreach_safe(s_info.disconn_cb_list, l, n, cbdata) { - /*! - * \NOTE - * cbdata->deleted must has to be checked before call the function and - * return from the function call. - */ - if (cbdata->deleted || cbdata->evt_cb(handle, cbdata->data) < 0 || cbdata->deleted) { - s_info.disconn_cb_list = dlist_remove(s_info.disconn_cb_list, l); - free(cbdata); - } - } - s_info.processing_event_callback &= ~PROCESSING_DISCONNECTION; - - if (watch) { - if (watch_item_destroy(handle, remove_id, remove_data) < 0) { - ErrPrint("Failed to destroy watch item\n"); - } - } + struct dlist *l; + struct dlist *n; + struct evtdata *cbdata; + + s_info.processing_event_callback |= PROCESSING_DISCONNECTION; + dlist_foreach_safe(s_info.disconn_cb_list, l, n, cbdata) { + /*! + * \NOTE + * cbdata->deleted must has to be checked before call the function and + * return from the function call. + */ + if (cbdata->deleted || cbdata->evt_cb(handle, cbdata->data) < 0 || cbdata->deleted) { + s_info.disconn_cb_list = dlist_remove(s_info.disconn_cb_list, l); + free(cbdata); + } + } + s_info.processing_event_callback &= ~PROCESSING_DISCONNECTION; + + if (watch) { + if (watch_item_destroy(handle, remove_id, remove_data) < 0) { + ErrPrint("Failed to destroy watch item\n"); + } + } } static int validate_handle(int fd) { - int error; - socklen_t len; + int error; + socklen_t len; - len = sizeof(error); - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { - ErrPrint("getsockopt: %s\n", strerror(errno)); - return 0; - } + len = sizeof(error); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + ErrPrint("getsockopt: %s\n", strerror(errno)); + return 0; + } - return !(error == EBADF); + return !(error == EBADF); } static gboolean client_cb(GIOChannel *src, GIOCondition cond, gpointer data) { - int client_fd; - struct cbdata *cbdata = data; - int ret; - - client_fd = g_io_channel_unix_get_fd(src); - - if (!(cond & G_IO_IN)) { - DbgPrint("Client is disconencted\n"); - invoke_disconn_cb_list(client_fd, 0, 1, 1); - secure_socket_destroy_handle(client_fd); - return FALSE; - } - - if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) { - DbgPrint("Client connection is lost\n"); - invoke_disconn_cb_list(client_fd, 0, 1, 1); - secure_socket_destroy_handle(client_fd); - return FALSE; - } - - ret = cbdata->service_cb(client_fd, cbdata->data); - if (ret < 0) { - DbgPrint("service callback returns %d < 0\n", ret); - invoke_disconn_cb_list(client_fd, 0, 1, 1); - secure_socket_destroy_handle(client_fd); - return FALSE; - } - - /* Check whether the socket FD is closed or not */ - if (!validate_handle(client_fd)) { - invoke_disconn_cb_list(client_fd, 0, 1, 1); - secure_socket_destroy_handle(client_fd); - return FALSE; - } - - return TRUE; + int client_fd; + struct cbdata *cbdata = data; + int ret; + + client_fd = g_io_channel_unix_get_fd(src); + + if (!(cond & G_IO_IN)) { + DbgPrint("Client is disconencted\n"); + invoke_disconn_cb_list(client_fd, 0, 1, 1); + secure_socket_destroy_handle(client_fd); + return FALSE; + } + + if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) { + DbgPrint("Client connection is lost\n"); + invoke_disconn_cb_list(client_fd, 0, 1, 1); + secure_socket_destroy_handle(client_fd); + return FALSE; + } + + ret = cbdata->service_cb(client_fd, cbdata->data); + if (ret < 0) { + DbgPrint("service callback returns %d < 0\n", ret); + invoke_disconn_cb_list(client_fd, 0, 1, 1); + secure_socket_destroy_handle(client_fd); + return FALSE; + } + + /* Check whether the socket FD is closed or not */ + if (!validate_handle(client_fd)) { + invoke_disconn_cb_list(client_fd, 0, 1, 1); + secure_socket_destroy_handle(client_fd); + return FALSE; + } + + return TRUE; } static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata) { - int socket_fd; - int client_fd; - GIOChannel *gio; - guint id; - - socket_fd = g_io_channel_unix_get_fd(src); - if (!(cond & G_IO_IN)) { - ErrPrint("Accept socket closed\n"); - watch_item_destroy_all(socket_fd); - secure_socket_destroy_handle(socket_fd); - free(cbdata); - return FALSE; - } - - if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) { - ErrPrint("Client connection is lost\n"); - watch_item_destroy_all(socket_fd); - secure_socket_destroy_handle(socket_fd); - free(cbdata); - return FALSE; - } - - client_fd = secure_socket_get_connection_handle(socket_fd); - if (client_fd < 0) { - /* Keep server running */ - return TRUE; - } - DbgPrint("New connectino arrived: server(%d), client(%d)\n", socket_fd, client_fd); + int socket_fd; + int client_fd; + GIOChannel *gio; + guint id; + + socket_fd = g_io_channel_unix_get_fd(src); + if (!(cond & G_IO_IN)) { + ErrPrint("Accept socket closed\n"); + watch_item_destroy_all(socket_fd); + secure_socket_destroy_handle(socket_fd); + free(cbdata); + return FALSE; + } + + if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) { + ErrPrint("Client connection is lost\n"); + watch_item_destroy_all(socket_fd); + secure_socket_destroy_handle(socket_fd); + free(cbdata); + return FALSE; + } + + client_fd = secure_socket_get_connection_handle(socket_fd); + if (client_fd < 0) { + /* Keep server running */ + return TRUE; + } + DbgPrint("New connectino arrived: server(%d), client(%d)\n", socket_fd, client_fd); - if (fcntl(client_fd, F_SETFD, FD_CLOEXEC) < 0) { - ErrPrint("Error: %s\n", strerror(errno)); - } + if (fcntl(client_fd, F_SETFD, FD_CLOEXEC) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + } - if (fcntl(client_fd, F_SETFL, O_NONBLOCK) < 0) { - ErrPrint("Error: %s\n", strerror(errno)); - } + if (fcntl(client_fd, F_SETFL, O_NONBLOCK) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + } - gio = g_io_channel_unix_new(client_fd); - if (!gio) { - ErrPrint("Failed to get gio\n"); - secure_socket_destroy_handle(client_fd); - /* Keep server running */ - return TRUE; - } + gio = g_io_channel_unix_new(client_fd); + if (!gio) { + ErrPrint("Failed to get gio\n"); + secure_socket_destroy_handle(client_fd); + /* Keep server running */ + return TRUE; + } - g_io_channel_set_close_on_unref(gio, FALSE); + g_io_channel_set_close_on_unref(gio, FALSE); - id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)client_cb, cbdata); - if (id <= 0) { - GError *err = NULL; + id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)client_cb, cbdata); + if (id <= 0) { + GError *err = NULL; - ErrPrint("Failed to add IO watch\n"); - g_io_channel_shutdown(gio, TRUE, &err); - if (err) { - ErrPrint("Shutdown: %s\n", err->message); - g_error_free(err); - } - g_io_channel_unref(gio); - secure_socket_destroy_handle(client_fd); - /* Keep server running */ - return TRUE; + ErrPrint("Failed to add IO watch\n"); + g_io_channel_shutdown(gio, TRUE, &err); + if (err) { + ErrPrint("Shutdown: %s\n", err->message); + g_error_free(err); } - g_io_channel_unref(gio); - - invoke_con_cb_list(socket_fd, client_fd, id, NULL, 1); - - if (!validate_handle(socket_fd)) { - watch_item_destroy_all(socket_fd); - return FALSE; - } - + secure_socket_destroy_handle(client_fd); /* Keep server running */ return TRUE; -} - -EAPI int com_core_server_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data) -{ - GIOChannel *gio; - guint id; - int fd; - struct cbdata *cbdata; - - cbdata = malloc(sizeof(*cbdata)); - if (!cbdata) { - ErrPrint("Heap: %s\n", strerror(errno)); - return -ENOMEM; - } - - cbdata->service_cb = service_cb; - cbdata->data = data; + } - fd = secure_socket_create_server(addr); - if (fd < 0) { - free(cbdata); - return fd; - } + g_io_channel_unref(gio); - if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { - ErrPrint("fcntl: %s\n", strerror(errno)); - } + invoke_con_cb_list(socket_fd, client_fd, id, NULL, 1); - if (!is_sync && fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - ErrPrint("fcntl: %s\n", strerror(errno)); - } + if (!validate_handle(socket_fd)) { + watch_item_destroy_all(socket_fd); + return FALSE; + } - DbgPrint("Create new IO channel for server FD: %d\n", fd); - gio = g_io_channel_unix_new(fd); - if (!gio) { - ErrPrint("Failed to create new io channel\n"); - free(cbdata); - secure_socket_destroy_handle(fd); - return -EIO; - } + /* Keep server running */ + return TRUE; +} - g_io_channel_set_close_on_unref(gio, FALSE); - - id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc)accept_cb, cbdata); - if (id <= 0) { - GError *err = NULL; - ErrPrint("Failed to add IO watch\n"); - free(cbdata); - g_io_channel_shutdown(gio, TRUE, &err); - if (err) { - ErrPrint("Shutdown: %s\n", err->message); - g_error_free(err); - } - g_io_channel_unref(gio); - secure_socket_destroy_handle(fd); - return -EIO; +EAPI int com_core_server_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data) +{ + GIOChannel *gio; + guint id; + int fd; + struct cbdata *cbdata; + + cbdata = malloc(sizeof(*cbdata)); + if (!cbdata) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + cbdata->service_cb = service_cb; + cbdata->data = data; + + fd = secure_socket_create_server(addr); + if (fd < 0) { + free(cbdata); + return fd; + } + + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { + ErrPrint("fcntl: %s\n", strerror(errno)); + } + + if (!is_sync && fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + ErrPrint("fcntl: %s\n", strerror(errno)); + } + + DbgPrint("Create new IO channel for server FD: %d\n", fd); + gio = g_io_channel_unix_new(fd); + if (!gio) { + ErrPrint("Failed to create new io channel\n"); + free(cbdata); + secure_socket_destroy_handle(fd); + return -EIO; + } + + g_io_channel_set_close_on_unref(gio, FALSE); + + id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc)accept_cb, cbdata); + if (id <= 0) { + GError *err = NULL; + ErrPrint("Failed to add IO watch\n"); + free(cbdata); + g_io_channel_shutdown(gio, TRUE, &err); + if (err) { + ErrPrint("Shutdown: %s\n", err->message); + g_error_free(err); } + g_io_channel_unref(gio); + secure_socket_destroy_handle(fd); + return -EIO; + } - if (watch_item_create(fd, fd, id, cbdata) < 0) { - GError *err = NULL; + if (watch_item_create(fd, fd, id, cbdata) < 0) { + GError *err = NULL; - ErrPrint("Failed to create a watch item\n"); - g_source_remove(id); + ErrPrint("Failed to create a watch item\n"); + g_source_remove(id); - free(cbdata); - g_io_channel_shutdown(gio, TRUE, &err); - if (err) { - ErrPrint("Shutdown: %s\n", err->message); - g_error_free(err); - } - g_io_channel_unref(gio); - secure_socket_destroy_handle(fd); - return -ENOMEM; + free(cbdata); + g_io_channel_shutdown(gio, TRUE, &err); + if (err) { + ErrPrint("Shutdown: %s\n", err->message); + g_error_free(err); } - g_io_channel_unref(gio); - return fd; + secure_socket_destroy_handle(fd); + return -ENOMEM; + } + + g_io_channel_unref(gio); + return fd; } EAPI int com_core_client_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data) { - GIOChannel *gio; - guint id; - int client_fd; - struct cbdata *cbdata; - - cbdata = malloc(sizeof(*cbdata)); - if (!cbdata) { - ErrPrint("Heap: %s\n", strerror(errno)); - return -ENOMEM; + GIOChannel *gio; + guint id; + int client_fd; + struct cbdata *cbdata; + + cbdata = malloc(sizeof(*cbdata)); + if (!cbdata) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + cbdata->service_cb = service_cb; + cbdata->data = data; + + client_fd = secure_socket_create_client(addr); + if (client_fd < 0) { + free(cbdata); + return client_fd; + } + + if (fcntl(client_fd, F_SETFD, FD_CLOEXEC) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + } + + if (!is_sync && fcntl(client_fd, F_SETFL, O_NONBLOCK) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + } + + gio = g_io_channel_unix_new(client_fd); + if (!gio) { + ErrPrint("Failed to create a new IO channel\n"); + free(cbdata); + secure_socket_destroy_handle(client_fd); + return -EIO; + } + + g_io_channel_set_close_on_unref(gio, FALSE); + + id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)client_cb, cbdata); + if (id <= 0) { + GError *err = NULL; + ErrPrint("Failed to add IO watch\n"); + free(cbdata); + g_io_channel_shutdown(gio, TRUE, &err); + if (err) { + ErrPrint("Shutdown: %s\n", err->message); + g_error_free(err); } + g_io_channel_unref(gio); + secure_socket_destroy_handle(client_fd); + return -EIO; + } - cbdata->service_cb = service_cb; - cbdata->data = data; + g_io_channel_unref(gio); - client_fd = secure_socket_create_client(addr); - if (client_fd < 0) { - free(cbdata); - return client_fd; - } + invoke_con_cb_list(client_fd, client_fd, id, cbdata, 1); + return client_fd; +} - if (fcntl(client_fd, F_SETFD, FD_CLOEXEC) < 0) { - ErrPrint("Error: %s\n", strerror(errno)); - } +EAPI int com_core_add_event_callback(enum com_core_event_type type, int (*evt_cb)(int handle, void *data), void *data) +{ + struct evtdata *cbdata; + cbdata = malloc(sizeof(*cbdata)); + if (!cbdata) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + cbdata->evt_cb = evt_cb; + cbdata->data = data; + cbdata->deleted = 0; + + if (type == CONNECTOR_CONNECTED) { + s_info.conn_cb_list = dlist_append(s_info.conn_cb_list, cbdata); + } else { + s_info.disconn_cb_list = dlist_append(s_info.disconn_cb_list, cbdata); + } + return 0; +} - if (!is_sync && fcntl(client_fd, F_SETFL, O_NONBLOCK) < 0) { - ErrPrint("Error: %s\n", strerror(errno)); +EAPI int com_core_recv_with_fd(int handle, char *buffer, int size, int *sender_pid, double timeout, int *fd) +{ + int readsize; + int ret; + int *recv_fd; + + fd_set set; + + recv_fd = fd; + readsize = 0; + while (size > 0) { + FD_ZERO(&set); + FD_SET(handle, &set); + + if (timeout > 0.0f) { + struct timeval tv; + + tv.tv_sec = (unsigned long)timeout; + tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u; + ret = select(handle + 1, &set, NULL, NULL, &tv); + } else if (timeout == 0.0f) { + ret = select(handle + 1, &set, NULL, NULL, NULL); + } else { + ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout); + return -EINVAL; } - gio = g_io_channel_unix_new(client_fd); - if (!gio) { - ErrPrint("Failed to create a new IO channel\n"); - free(cbdata); - secure_socket_destroy_handle(client_fd); - return -EIO; + if (ret < 0) { + ret = -errno; + if (errno == EINTR) { + DbgPrint("Select receives INTR\n"); + continue; + } + ErrPrint("Error: %s\n", strerror(errno)); + return ret; + } else if (ret == 0) { + ErrPrint("Timeout expired\n"); + break; } - g_io_channel_set_close_on_unref(gio, FALSE); - - id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)client_cb, cbdata); - if (id <= 0) { - GError *err = NULL; - ErrPrint("Failed to add IO watch\n"); - free(cbdata); - g_io_channel_shutdown(gio, TRUE, &err); - if (err) { - ErrPrint("Shutdown: %s\n", err->message); - g_error_free(err); - } - g_io_channel_unref(gio); - secure_socket_destroy_handle(client_fd); - return -EIO; + if (!FD_ISSET(handle, &set)) { + ErrPrint("Unexpected handle is toggled\n"); + return -EINVAL; } - g_io_channel_unref(gio); - - invoke_con_cb_list(client_fd, client_fd, id, cbdata, 1); - return client_fd; + ret = secure_socket_recv(handle, buffer + readsize, size, sender_pid, recv_fd); + if (ret < 0) { + if (ret == -EAGAIN) { + DbgPrint("Retry to get data (%d:%d)\n", readsize, size); + continue; + } + DbgPrint("[%d] recv returns: %d\n", handle, ret); + return ret; + } else if (ret == 0) { + DbgPrint("Disconnected(req.size: %d)\n", size); + return 0; + } + + recv_fd = NULL; /** Get it only for the first time */ + size -= ret; + readsize += ret; + } + + return readsize; } -EAPI int com_core_add_event_callback(enum com_core_event_type type, int (*evt_cb)(int handle, void *data), void *data) +EAPI int com_core_recv(int handle, char *buffer, int size, int *sender_pid, double timeout) { - struct evtdata *cbdata; - cbdata = malloc(sizeof(*cbdata)); - if (!cbdata) { - ErrPrint("Heap: %s\n", strerror(errno)); - return -ENOMEM; - } - - cbdata->evt_cb = evt_cb; - cbdata->data = data; - cbdata->deleted = 0; - - if (type == CONNECTOR_CONNECTED) { - s_info.conn_cb_list = dlist_append(s_info.conn_cb_list, cbdata); - } else { - s_info.disconn_cb_list = dlist_append(s_info.disconn_cb_list, cbdata); - } - return 0; + return com_core_recv_with_fd(handle, buffer, size, sender_pid, timeout, NULL); } -EAPI int com_core_recv(int handle, char *buffer, int size, int *sender_pid, double timeout) +EAPI int com_core_send_with_fd(int handle, const char *buffer, int size, double timeout, int fd) { - int readsize; - int ret; + int writesize; + int ret; - fd_set set; + fd_set set; - readsize = 0; - while (size > 0) { - FD_ZERO(&set); - FD_SET(handle, &set); + writesize = 0; + while (size > 0) { - if (timeout > 0.0f) { - struct timeval tv; + FD_ZERO(&set); + FD_SET(handle, &set); - tv.tv_sec = (unsigned long)timeout; - tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u; - ret = select(handle + 1, &set, NULL, NULL, &tv); - } else if (timeout == 0.0f) { - ret = select(handle + 1, &set, NULL, NULL, NULL); - } else { - ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout); - return -EINVAL; - } + if (timeout > 0.0f) { + struct timeval tv; - if (ret < 0) { - ret = -errno; - if (errno == EINTR) { - DbgPrint("Select receives INTR\n"); - continue; - } - ErrPrint("Error: %s\n", strerror(errno)); - return ret; - } else if (ret == 0) { - ErrPrint("Timeout expired\n"); - break; - } + tv.tv_sec = (unsigned long)timeout; + tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u; - if (!FD_ISSET(handle, &set)) { - ErrPrint("Unexpected handle is toggled\n"); - return -EINVAL; - } + ret = select(handle + 1, NULL, &set, NULL, &tv); + } else if (timeout == 0.0f) { + ret = select(handle + 1, NULL, &set, NULL, NULL); + } else { + ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout); + return -EINVAL; + } - ret = secure_socket_recv(handle, buffer + readsize, size, sender_pid); - if (ret < 0) { - if (ret == -EAGAIN) { - DbgPrint("Retry to get data (%d:%d)\n", readsize, size); - continue; - } - DbgPrint("[%d] recv returns: %d\n", handle, ret); - return ret; - } else if (ret == 0) { - DbgPrint("Disconnected(req.size: %d)\n", size); - return 0; - } + if (ret < 0) { + ret = -errno; + if (errno == EINTR) { + DbgPrint("Select receives INTR\n"); + continue; + } + ErrPrint("Error: %s\n", strerror(errno)); + return ret; + } else if (ret == 0) { + ErrPrint("Timeout expired\n"); + break; + } - size -= ret; - readsize += ret; + if (!FD_ISSET(handle, &set)) { + ErrPrint("Unexpected handle is toggled\n"); + return -EINVAL; } - return readsize; + ret = secure_socket_send(handle, buffer + writesize, size, fd); + if (ret < 0) { + if (ret == -EAGAIN) { + DbgPrint("Retry to send data (%d:%d)\n", writesize, size); + continue; + } + DbgPrint("Failed to send: %d\n", ret); + return ret; + } else if (ret == 0) { + DbgPrint("Disconnected? : Send bytes: 0\n"); + return 0; + } + + fd = -1; /** Send only once if it is fd */ + size -= ret; + writesize += ret; + } + + return writesize; } EAPI int com_core_send(int handle, const char *buffer, int size, double timeout) { - int writesize; - int ret; - - fd_set set; - - writesize = 0; - while (size > 0) { - - FD_ZERO(&set); - FD_SET(handle, &set); + return com_core_send_with_fd(handle, buffer, size, timeout, -1); +} - if (timeout > 0.0f) { - struct timeval tv; +EAPI void *com_core_del_event_callback(enum com_core_event_type type, int (*cb)(int handle, void *data), void *data) +{ + struct dlist *l; + struct dlist *n; + struct evtdata *cbdata; - tv.tv_sec = (unsigned long)timeout; - tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u; + if (type == CONNECTOR_CONNECTED) { + dlist_foreach_safe(s_info.conn_cb_list, l, n, cbdata) { + if (cbdata->evt_cb == cb && cbdata->data == data) { + void *data; + data = cbdata->data; - ret = select(handle + 1, NULL, &set, NULL, &tv); - } else if (timeout == 0.0f) { - ret = select(handle + 1, NULL, &set, NULL, NULL); + if ((s_info.processing_event_callback & PROCESSING_CONNECTION) == PROCESSING_CONNECTION) { + cbdata->deleted = 1; } else { - ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout); - return -EINVAL; + dlist_remove_data(s_info.conn_cb_list, cbdata); + free(cbdata); } - if (ret < 0) { - ret = -errno; - if (errno == EINTR) { - DbgPrint("Select receives INTR\n"); - continue; - } - ErrPrint("Error: %s\n", strerror(errno)); - return ret; - } else if (ret == 0) { - ErrPrint("Timeout expired\n"); - break; - } - - if (!FD_ISSET(handle, &set)) { - ErrPrint("Unexpected handle is toggled\n"); - return -EINVAL; - } - - ret = secure_socket_send(handle, buffer + writesize, size); - if (ret < 0) { - if (ret == -EAGAIN) { - DbgPrint("Retry to send data (%d:%d)\n", writesize, size); - continue; - } - DbgPrint("Failed to send: %d\n", ret); - return ret; - } else if (ret == 0) { - DbgPrint("Disconnected? : Send bytes: 0\n"); - return 0; - } - - size -= ret; - writesize += ret; + return data; + } } + } else { + dlist_foreach_safe(s_info.disconn_cb_list, l, n, cbdata) { + if (cbdata->evt_cb == cb && cbdata->data == data) { + void *data; + data = cbdata->data; - return writesize; -} - -EAPI void *com_core_del_event_callback(enum com_core_event_type type, int (*cb)(int handle, void *data), void *data) -{ - struct dlist *l; - struct dlist *n; - struct evtdata *cbdata; - - if (type == CONNECTOR_CONNECTED) { - dlist_foreach_safe(s_info.conn_cb_list, l, n, cbdata) { - if (cbdata->evt_cb == cb && cbdata->data == data) { - void *data; - data = cbdata->data; - - if ((s_info.processing_event_callback & PROCESSING_CONNECTION) == PROCESSING_CONNECTION) { - cbdata->deleted = 1; - } else { - dlist_remove_data(s_info.conn_cb_list, cbdata); - free(cbdata); - } - - return data; - } - } - } else { - dlist_foreach_safe(s_info.disconn_cb_list, l, n, cbdata) { - if (cbdata->evt_cb == cb && cbdata->data == data) { - void *data; - data = cbdata->data; - - if ((s_info.processing_event_callback & PROCESSING_DISCONNECTION) == PROCESSING_DISCONNECTION) { - cbdata->deleted = 1; - } else { - dlist_remove_data(s_info.disconn_cb_list, cbdata); - free(cbdata); - } - return data; - } + if ((s_info.processing_event_callback & PROCESSING_DISCONNECTION) == PROCESSING_DISCONNECTION) { + cbdata->deleted = 1; + } else { + dlist_remove_data(s_info.disconn_cb_list, cbdata); + free(cbdata); } + return data; + } } + } - return NULL; + return NULL; } EAPI int com_core_server_destroy(int handle) { - DbgPrint("Close server handle[%d]\n", handle); - invoke_disconn_cb_list(handle, 1, 1, 1); - secure_socket_destroy_handle(handle); - return 0; + DbgPrint("Close server handle[%d]\n", handle); + invoke_disconn_cb_list(handle, 1, 1, 1); + secure_socket_destroy_handle(handle); + return 0; } EAPI int com_core_client_destroy(int handle) { - DbgPrint("Close client handle[%d]\n", handle); - invoke_disconn_cb_list(handle, 1, 1, 1); - secure_socket_destroy_handle(handle); - return 0; + DbgPrint("Close client handle[%d]\n", handle); + invoke_disconn_cb_list(handle, 1, 1, 1); + secure_socket_destroy_handle(handle); + return 0; } /* End of a file */ diff --git a/src/com-core_packet.c b/src/com-core_packet.c index 1f4169d..ea9ffc6 100644 --- a/src/com-core_packet.c +++ b/src/com-core_packet.c @@ -44,706 +44,720 @@ */ static struct info { - struct dlist *recv_list; - struct dlist *request_list; - char *addr; + struct dlist *recv_list; + struct dlist *request_list; + char *addr; - struct { - int (*server_create)(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data); - int (*client_create)(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data); - int (*server_destroy)(int handle); - int (*client_destroy)(int handle); + struct { + int (*server_create)(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data); + int (*client_create)(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data); + int (*server_destroy)(int handle); + int (*client_destroy)(int handle); - int (*recv)(int handle, char *buffer, int size, int *sender_pid, double timeout); - int (*send)(int handle, const char *buffer, int size, double timeout); - } vtable; + int (*recv)(int handle, char *buffer, int size, int *sender_pid, double timeout); + int (*send)(int handle, const char *buffer, int size, double timeout); - int initialized; + int (*recv_with_fd)(int handle, char *buffer, int size, int *sender_pid, double timeout, int *fd); + int (*send_with_fd)(int handle, const char *buffer, int size, double timeout, int fd); + } vtable; + + int initialized; } s_info = { - .recv_list = NULL, - .request_list = NULL, - .addr = NULL, - .vtable = { - .server_create = com_core_server_create, - .client_create = com_core_client_create, - .server_destroy = com_core_server_destroy, - .client_destroy = com_core_client_destroy, - .recv = com_core_recv, - .send = com_core_send, - }, - .initialized = 0, + .recv_list = NULL, + .request_list = NULL, + .addr = NULL, + .vtable = { + .server_create = com_core_server_create, + .client_create = com_core_client_create, + .server_destroy = com_core_server_destroy, + .client_destroy = com_core_client_destroy, + .recv = com_core_recv, + .send = com_core_send, + .recv_with_fd = com_core_recv_with_fd, + .send_with_fd = com_core_send_with_fd, + }, + .initialized = 0, }; struct request_ctx { - pid_t pid; - int handle; + pid_t pid; + int handle; - struct packet *packet; - int (*recv_cb)(pid_t pid, int handle, const struct packet *packet, void *data); - void *data; + struct packet *packet; + int (*recv_cb)(pid_t pid, int handle, const struct packet *packet, void *data); + void *data; - int inuse; + int inuse; }; struct recv_ctx { - enum { - RECV_STATE_INIT, - RECV_STATE_HEADER, - RECV_STATE_BODY, - RECV_STATE_READY - } state; - int handle; - int offset; - pid_t pid; - struct packet *packet; - double timeout; - - int inuse; + enum { + RECV_STATE_INIT, + RECV_STATE_HEADER, + RECV_STATE_BODY, + RECV_STATE_READY + } state; + int handle; + int offset; + pid_t pid; + struct packet *packet; + double timeout; + + int inuse; }; static inline struct request_ctx *find_request_ctx(int handle, double seq) { - struct request_ctx *ctx; - struct dlist *l; + struct request_ctx *ctx; + struct dlist *l; - dlist_foreach(s_info.request_list, l, ctx) { - if (ctx->handle == handle && packet_seq(ctx->packet) == seq) { - return ctx; - } + dlist_foreach(s_info.request_list, l, ctx) { + if (ctx->handle == handle && packet_seq(ctx->packet) == seq) { + return ctx; } + } - return NULL; + return NULL; } static inline void destroy_request_ctx(struct request_ctx *ctx) { - struct dlist *l; + struct dlist *l; - if (ctx->inuse) { - return; - } + if (ctx->inuse) { + return; + } - l = dlist_find_data(s_info.request_list, ctx); - if (!l) { - return; - } + l = dlist_find_data(s_info.request_list, ctx); + if (!l) { + return; + } - s_info.request_list = dlist_remove(s_info.request_list, l); + s_info.request_list = dlist_remove(s_info.request_list, l); - packet_unref(ctx->packet); - free(ctx); + packet_unref(ctx->packet); + free(ctx); } static inline struct request_ctx *create_request_ctx(int handle) { - struct request_ctx *ctx; + struct request_ctx *ctx; - ctx = malloc(sizeof(*ctx)); - if (!ctx) { - ErrPrint("Heap: %s\n", strerror(errno)); - return NULL; - } + ctx = malloc(sizeof(*ctx)); + if (!ctx) { + ErrPrint("Heap: %s\n", strerror(errno)); + return NULL; + } - ctx->handle = handle; - ctx->pid = (pid_t)-1; - ctx->packet = NULL; - ctx->recv_cb = NULL; - ctx->data = NULL; - ctx->inuse = 0; + ctx->handle = handle; + ctx->pid = (pid_t)-1; + ctx->packet = NULL; + ctx->recv_cb = NULL; + ctx->data = NULL; + ctx->inuse = 0; - s_info.request_list = dlist_append(s_info.request_list, ctx); - return ctx; + s_info.request_list = dlist_append(s_info.request_list, ctx); + return ctx; } static inline struct recv_ctx *find_recv_ctx(int handle) { - struct recv_ctx *ctx; - struct dlist *l; + struct recv_ctx *ctx; + struct dlist *l; - dlist_foreach(s_info.recv_list, l, ctx) { - if (ctx->handle == handle) { - return ctx; - } + dlist_foreach(s_info.recv_list, l, ctx) { + if (ctx->handle == handle) { + return ctx; } + } - return NULL; + return NULL; } static inline void recreate_recv_ctx(struct recv_ctx *ctx) { - if (ctx->packet) { - packet_destroy(ctx->packet); - ctx->packet = NULL; - } - ctx->state = RECV_STATE_INIT; - ctx->offset = 0; - ctx->pid = (pid_t)-1; - // ctx->inuse - // ctx->handle - // ctx->timeout + if (ctx->packet) { + packet_destroy(ctx->packet); + ctx->packet = NULL; + } + ctx->state = RECV_STATE_INIT; + ctx->offset = 0; + ctx->pid = (pid_t)-1; + // ctx->inuse + // ctx->handle + // ctx->timeout } static inline void destroy_recv_ctx(struct recv_ctx *ctx) { - struct dlist *l; + struct dlist *l; - if (ctx->inuse) { - return; - } + if (ctx->inuse) { + return; + } - l = dlist_find_data(s_info.recv_list, ctx); - if (!l) { - return; - } + l = dlist_find_data(s_info.recv_list, ctx); + if (!l) { + return; + } - s_info.recv_list = dlist_remove(s_info.recv_list, l); + s_info.recv_list = dlist_remove(s_info.recv_list, l); - packet_destroy(ctx->packet); - free(ctx); + packet_destroy(ctx->packet); + free(ctx); } static inline struct recv_ctx *create_recv_ctx(int handle, double timeout) { - struct recv_ctx *ctx; + struct recv_ctx *ctx; - ctx = malloc(sizeof(*ctx)); - if (!ctx) { - ErrPrint("heap: %s\n", strerror(errno)); - return NULL; - } + ctx = malloc(sizeof(*ctx)); + if (!ctx) { + ErrPrint("heap: %s\n", strerror(errno)); + return NULL; + } - ctx->state = RECV_STATE_INIT, + ctx->state = RECV_STATE_INIT, ctx->offset = 0; - ctx->packet = NULL; - ctx->handle = handle; - ctx->pid = (pid_t)-1; - ctx->timeout = timeout; - ctx->inuse = 0; - - s_info.recv_list = dlist_append(s_info.recv_list, ctx); - return ctx; + ctx->packet = NULL; + ctx->handle = handle; + ctx->pid = (pid_t)-1; + ctx->timeout = timeout; + ctx->inuse = 0; + + s_info.recv_list = dlist_append(s_info.recv_list, ctx); + return ctx; } static inline int packet_ready(int handle, struct recv_ctx *receive, struct method *table) { - struct request_ctx *request; - double sequence; - struct packet *result; - register int i; - int ret; - const char *cmd; - unsigned int cmd_idx; + struct request_ctx *request; + double sequence; + struct packet *result; + register int i; + int ret; + const char *cmd; + unsigned int cmd_idx; - ret = 0; + ret = 0; - switch (packet_type(receive->packet)) { + switch (packet_type(receive->packet)) { case PACKET_ACK: - sequence = packet_seq(receive->packet); - request = find_request_ctx(handle, sequence); - if (!request) { - ErrPrint("This is not requested packet (%s)\n", packet_command(receive->packet)); - break; - } - - if (request->recv_cb) { - request->inuse = 1; - receive->inuse = 1; - request->recv_cb(receive->pid, handle, receive->packet, request->data); - receive->inuse = 0; - request->inuse = 0; - } - - destroy_request_ctx(request); + sequence = packet_seq(receive->packet); + request = find_request_ctx(handle, sequence); + if (!request) { + ErrPrint("This is not requested packet (%s)\n", packet_command(receive->packet)); break; + } + + if (request->recv_cb) { + request->inuse = 1; + receive->inuse = 1; + request->recv_cb(receive->pid, handle, receive->packet, request->data); + receive->inuse = 0; + request->inuse = 0; + } + + destroy_request_ctx(request); + break; case PACKET_REQ: - cmd_idx = 0xFFFFFFFF; - cmd = packet_command(receive->packet); - if (cmd[0] == PACKET_CMD_INT_TAG) { - unsigned int *p_cmd_idx = (unsigned int *)cmd; - - /* Get rid of LSB 8 bits */ - cmd_idx = *p_cmd_idx >> 8; - } else { - for (i = 0; table[i].cmd; i++) { - if (strcmp(table[i].cmd, packet_command(receive->packet))) { - continue; - } - - cmd_idx = (unsigned int)i; - break; - } - } + cmd_idx = 0xFFFFFFFF; + cmd = packet_command(receive->packet); + if (cmd[0] == PACKET_CMD_INT_TAG) { + unsigned int *p_cmd_idx = (unsigned int *)cmd; + + /* Get rid of LSB 8 bits */ + cmd_idx = *p_cmd_idx >> 8; + } else { + for (i = 0; table[i].cmd; i++) { + if (strcmp(table[i].cmd, packet_command(receive->packet))) { + continue; + } - if (cmd_idx != 0xFFFFFFFF) { - receive->inuse = 1; - result = table[cmd_idx].handler(receive->pid, handle, receive->packet); - receive->inuse = 0; - if (result) { - ret = s_info.vtable.send(handle, (void *)packet_data(result), packet_size(result), DEFAULT_TIMEOUT); - if (ret < 0) { - ErrPrint("Failed to send an ack packet\n"); - } else { - ret = 0; - } - packet_destroy(result); - } + cmd_idx = (unsigned int)i; + break; } + } + + if (cmd_idx != 0xFFFFFFFF) { + receive->inuse = 1; + result = table[cmd_idx].handler(receive->pid, handle, receive->packet); + receive->inuse = 0; + if (result) { + ret = s_info.vtable.send(handle, (void *)packet_data(result), packet_size(result), DEFAULT_TIMEOUT); + if (ret < 0) { + ErrPrint("Failed to send an ack packet\n"); + } else { + ret = 0; + } + packet_destroy(result); + } + } - break; + break; case PACKET_REQ_NOACK: - cmd_idx = 0xFFFFFFFF; - cmd = packet_command(receive->packet); - if (cmd[0] == PACKET_CMD_INT_TAG) { - unsigned int *p_cmd_idx = (unsigned int *)cmd; - - /* Get rid of LSB 8 bits */ - cmd_idx = *p_cmd_idx >> 8; - } else { - for (i = 0; table[i].cmd; i++) { - if (strcmp(table[i].cmd, packet_command(receive->packet))) { - continue; - } - - cmd_idx = (unsigned int)i; - break; - } + cmd_idx = 0xFFFFFFFF; + cmd = packet_command(receive->packet); + if (cmd[0] == PACKET_CMD_INT_TAG) { + unsigned int *p_cmd_idx = (unsigned int *)cmd; + + /* Get rid of LSB 8 bits */ + cmd_idx = *p_cmd_idx >> 8; + } else { + for (i = 0; table[i].cmd; i++) { + if (strcmp(table[i].cmd, packet_command(receive->packet))) { + continue; + } + + cmd_idx = (unsigned int)i; + break; } + } - if (cmd_idx != 0xFFFFFFFF) { - receive->inuse = 1; - result = table[cmd_idx].handler(receive->pid, handle, receive->packet); - receive->inuse = 0; - if (result) { - packet_destroy(result); - } + if (cmd_idx != 0xFFFFFFFF) { + receive->inuse = 1; + result = table[cmd_idx].handler(receive->pid, handle, receive->packet); + receive->inuse = 0; + if (result) { + packet_destroy(result); } - break; + } + break; default: - break; - } + break; + } - /*! - * Return negative value will make call the disconnected_cb - */ - return ret; + /*! + * Return negative value will make call the disconnected_cb + */ + return ret; } static int client_disconnected_cb(int handle, void *data) { - struct recv_ctx *receive; - struct request_ctx *request; - struct dlist *l; - struct dlist *n; - int inuse_found = 0; - pid_t pid = (pid_t)-1; - - receive = find_recv_ctx(handle); - if (receive) { - pid = receive->pid; - } - - DbgPrint("Clean up all requests and a receive context for handle(%d) for pid(%d)\n", handle, pid); + struct recv_ctx *receive; + struct request_ctx *request; + struct dlist *l; + struct dlist *n; + int inuse_found = 0; + pid_t pid = (pid_t)-1; - dlist_foreach_safe(s_info.request_list, l, n, request) { - if (request->handle != handle) { - continue; - } + receive = find_recv_ctx(handle); + if (receive) { + pid = receive->pid; + } - if (request->inuse) { - inuse_found = 1; - continue; - } + DbgPrint("Clean up all requests and a receive context for handle(%d) for pid(%d)\n", handle, pid); - if (request->recv_cb) { - request->recv_cb(pid, handle, NULL, request->data); - } + dlist_foreach_safe(s_info.request_list, l, n, request) { + if (request->handle != handle) { + continue; + } - destroy_request_ctx(request); + if (request->inuse) { + inuse_found = 1; + continue; } - if (receive && !inuse_found) { - destroy_recv_ctx(receive); + if (request->recv_cb) { + request->recv_cb(pid, handle, NULL, request->data); } - return 0; + destroy_request_ctx(request); + } + + if (receive && !inuse_found) { + destroy_recv_ctx(receive); + } + + return 0; } static int service_cb(int handle, void *data) { - struct recv_ctx *receive; - pid_t pid; - int ret; - int size; - char *ptr; - - receive = find_recv_ctx(handle); + struct recv_ctx *receive; + pid_t pid; + int ret; + int size; + char *ptr; + + receive = find_recv_ctx(handle); + if (!receive) { + receive = create_recv_ctx(handle, DEFAULT_TIMEOUT); if (!receive) { - receive = create_recv_ctx(handle, DEFAULT_TIMEOUT); - if (!receive) { - ErrPrint("Couldn't find or create a receive context\n"); - return -EIO; - } + ErrPrint("Couldn't find or create a receive context\n"); + return -EIO; } + } - switch (receive->state) { + switch (receive->state) { case RECV_STATE_INIT: - receive->state = RECV_STATE_HEADER; - receive->offset = 0; + receive->state = RECV_STATE_HEADER; + receive->offset = 0; case RECV_STATE_HEADER: - size = packet_header_size() - receive->offset; - /*! - * \note - * Getting header - */ - ptr = malloc(size); - if (!ptr) { - ErrPrint("Heap: %s\n", strerror(errno)); - return -ENOMEM; + size = packet_header_size() - receive->offset; + /*! + * \note + * Getting header + */ + ptr = malloc(size); + if (!ptr) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + ret = s_info.vtable.recv(handle, ptr, size, &pid, receive->timeout); + if (ret < 0) { + ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid); + free(ptr); + return -EIO; /*!< Return negative value will invoke the client_disconnected_cb */ + } else if (ret > 0) { + if (receive->pid != -1 && receive->pid != pid) { + ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid); + free(ptr); + return -EIO; /*!< Return negative value will invoke the client_disconnected_cb */ } - ret = s_info.vtable.recv(handle, ptr, size, &pid, receive->timeout); - if (ret < 0) { - ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid); - free(ptr); - return -EIO; /*!< Return negative value will invoke the client_disconnected_cb */ - } else if (ret > 0) { - if (receive->pid != -1 && receive->pid != pid) { - ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid); - free(ptr); - return -EIO; /*!< Return negative value will invoke the client_disconnected_cb */ - } - - receive->pid = pid; - receive->packet = packet_build(receive->packet, receive->offset, ptr, ret); - free(ptr); - - if (!receive->packet) { - ErrPrint("Built packet is not valid\n"); - return -EFAULT; /*!< Return negative value will invoke the client_disconnected_cb */ - } - - receive->offset += ret; - - if (receive->offset == packet_header_size()) { - if (packet_size(receive->packet) == receive->offset) { - receive->state = RECV_STATE_READY; - } else { - receive->state = RECV_STATE_BODY; - } - } - } else { - DbgPrint("ZERO bytes receives(%d)\n", pid); - free(ptr); - return -ECONNRESET; + receive->pid = pid; + receive->packet = packet_build(receive->packet, receive->offset, ptr, ret); + free(ptr); + + if (!receive->packet) { + ErrPrint("Built packet is not valid\n"); + return -EFAULT; /*!< Return negative value will invoke the client_disconnected_cb */ } - break; - case RECV_STATE_BODY: - size = packet_size(receive->packet) - receive->offset; - if (size == 0) { + + receive->offset += ret; + + if (receive->offset == packet_header_size()) { + if (packet_size(receive->packet) == receive->offset) { receive->state = RECV_STATE_READY; - break; + } else { + receive->state = RECV_STATE_BODY; + } } - /*! - * \note - * Getting body - */ - ptr = malloc(size); - if (!ptr) { - ErrPrint("Heap: %s\n", strerror(errno)); - return -ENOMEM; + } else { + DbgPrint("ZERO bytes receives(%d)\n", pid); + free(ptr); + return -ECONNRESET; + } + break; + case RECV_STATE_BODY: + size = packet_size(receive->packet) - receive->offset; + if (size == 0) { + receive->state = RECV_STATE_READY; + break; + } + /*! + * \note + * Getting body + */ + ptr = malloc(size); + if (!ptr) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + ret = s_info.vtable.recv(handle, ptr, size, &pid, receive->timeout); + if (ret < 0) { + ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid); + free(ptr); + return -EIO; + } else if (ret > 0) { + if (receive->pid != pid) { + ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid); + free(ptr); + return -EIO; } - ret = s_info.vtable.recv(handle, ptr, size, &pid, receive->timeout); - if (ret < 0) { - ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid); - free(ptr); - return -EIO; - } else if (ret > 0) { - if (receive->pid != pid) { - ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid); - free(ptr); - return -EIO; - } - - receive->packet = packet_build(receive->packet, receive->offset, ptr, ret); - free(ptr); - - if (!receive->packet) { - ErrPrint("Built packet is not valid\n"); - return -EFAULT; - } - - receive->offset += ret; - - if (receive->offset == packet_size(receive->packet)) { - receive->state = RECV_STATE_READY; - } - } else { - DbgPrint("ZERO bytes receives(%d)\n", pid); - free(ptr); - return -ECONNRESET; + receive->packet = packet_build(receive->packet, receive->offset, ptr, ret); + free(ptr); + + if (!receive->packet) { + ErrPrint("Built packet is not valid\n"); + return -EFAULT; } - break; + receive->offset += ret; + + if (receive->offset == packet_size(receive->packet)) { + receive->state = RECV_STATE_READY; + } + } else { + DbgPrint("ZERO bytes receives(%d)\n", pid); + free(ptr); + return -ECONNRESET; + } + + break; case RECV_STATE_READY: default: - break; - } + break; + } - if (receive->state == RECV_STATE_READY) { - ret = packet_ready(handle, receive, data); - if (ret == 0) { - /*! - * If ret is negative value, the receive context will be destroyed from disconnected callback - */ - recreate_recv_ctx(receive); - } - /*! - * if ret is negative value, disconnected_cb will be called after this function - */ - } else { - ret = 0; + if (receive->state == RECV_STATE_READY) { + ret = packet_ready(handle, receive, data); + if (ret == 0) { + /*! + * If ret is negative value, the receive context will be destroyed from disconnected callback + */ + recreate_recv_ctx(receive); } + /*! + * if ret is negative value, disconnected_cb will be called after this function + */ + } else { + ret = 0; + } - return ret; + return ret; } EAPI int com_core_packet_async_send(int handle, struct packet *packet, double timeout, int (*recv_cb)(pid_t pid, int handle, const struct packet *packet, void *data), void *data) { - int ret; - struct request_ctx *ctx; - - if (handle < 0 || !packet) { - ErrPrint("Invalid argument\n"); - return -EINVAL; - } - - if (packet_type(packet) != PACKET_REQ) { - ErrPrint("Invalid packet - should be PACKET_REQ\n"); - return -EINVAL; - } - - ctx = create_request_ctx(handle); - if (!ctx) { - return -ENOMEM; - } - - ctx->recv_cb = recv_cb; - ctx->data = data; - ctx->packet = packet_ref(packet); - - ret = s_info.vtable.send(handle, (void *)packet_data(packet), packet_size(packet), DEFAULT_TIMEOUT); - if (ret != packet_size(packet)) { - ErrPrint("Send failed. %d <> %d (handle: %d)\n", ret, packet_size(packet), handle); - destroy_request_ctx(ctx); - return -EIO; - } - - return 0; + int ret; + struct request_ctx *ctx; + + if (handle < 0 || !packet) { + ErrPrint("Invalid argument\n"); + return -EINVAL; + } + + if (packet_type(packet) != PACKET_REQ) { + ErrPrint("Invalid packet - should be PACKET_REQ\n"); + return -EINVAL; + } + + ctx = create_request_ctx(handle); + if (!ctx) { + return -ENOMEM; + } + + ctx->recv_cb = recv_cb; + ctx->data = data; + ctx->packet = packet_ref(packet); + + ret = s_info.vtable.send(handle, (void *)packet_data(packet), packet_size(packet), DEFAULT_TIMEOUT); + if (ret != packet_size(packet)) { + ErrPrint("Send failed. %d <> %d (handle: %d)\n", ret, packet_size(packet), handle); + destroy_request_ctx(ctx); + return -EIO; + } + + return 0; } EAPI int com_core_packet_send_only(int handle, struct packet *packet) { - int ret; + int ret; - if (packet_type(packet) != PACKET_REQ_NOACK) { - ErrPrint("Invalid type - should be PACKET_REQ_NOACK (%p)\n", packet); - return -EINVAL; - } + if (packet_type(packet) != PACKET_REQ_NOACK) { + ErrPrint("Invalid type - should be PACKET_REQ_NOACK (%p)\n", packet); + return -EINVAL; + } - ret = s_info.vtable.send(handle, (void *)packet_data(packet), packet_size(packet), DEFAULT_TIMEOUT); - if (ret != packet_size(packet)) { - ErrPrint("Failed to send whole packet\n"); - return -EIO; - } + ret = s_info.vtable.send(handle, (void *)packet_data(packet), packet_size(packet), DEFAULT_TIMEOUT); + if (ret != packet_size(packet)) { + ErrPrint("Failed to send whole packet\n"); + return -EIO; + } - return 0; + return 0; } EAPI struct packet *com_core_packet_oneshot_send(const char *addr, struct packet *packet, double timeout) { - int ret; - int fd; - pid_t pid; - int offset; - struct packet *result = NULL; - void *ptr; - int size; - - if (!addr || !packet) { - ErrPrint("Invalid argument\n"); - return NULL; - } - - fd = secure_socket_create_client(addr); - if (fd < 0) { - return NULL; - } - - if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { - ErrPrint("fcntl: %s\n", strerror(errno)); - } - - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - ErrPrint("Error: %s\n", strerror(errno)); - } - - ret = com_core_send(fd, (char *)packet_data(packet), packet_size(packet), DEFAULT_TIMEOUT); - if (ret < 0) { - goto out; - } - - ptr = malloc(packet_header_size()); - if (!ptr) { - ErrPrint("Heap: %s\n", strerror(errno)); - goto out; - } - - offset = 0; - ret = com_core_recv(fd, (char *)ptr, packet_header_size(), &pid, timeout); - if (ret <= 0) { - DbgPrint("Recv returns %d\n", ret); - free(ptr); - goto out; - } else { - DbgPrint("Recv'd size: %d (header: %d) pid: %d\n", ret, packet_header_size(), pid); - result = packet_build(result, offset, ptr, ret); - offset += ret; - free(ptr); - if (!result) { - ErrPrint("Failed to build a packet\n"); - goto out; - } - } - - size = packet_payload_size(result); - if (size < 0) { - packet_destroy(result); - result = NULL; - goto out; - } - - if (size == 0) { - DbgPrint("Has no payload\n"); - goto out; - } - - ptr = malloc(size); - if (!ptr) { - ErrPrint("Heap: %s\n", strerror(errno)); - packet_destroy(result); - result = NULL; - goto out; - } + int ret; + int fd; + pid_t pid; + int offset; + struct packet *result = NULL; + void *ptr; + int size; + + if (!addr || !packet) { + ErrPrint("Invalid argument\n"); + return NULL; + } - ret = com_core_recv(fd, (char *)ptr, size, &pid, timeout); - if (ret <= 0) { - DbgPrint("Recv returns %d\n", ret); - free(ptr); - packet_destroy(result); - result = NULL; - } else { - DbgPrint("Recv'd %d bytes (pid: %d)\n", ret, pid); - result = packet_build(result, offset, ptr, ret); - offset += ret; - free(ptr); - } + fd = secure_socket_create_client(addr); + if (fd < 0) { + return NULL; + } + + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { + ErrPrint("fcntl: %s\n", strerror(errno)); + } + + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + } + + ret = com_core_send(fd, (char *)packet_data(packet), packet_size(packet), DEFAULT_TIMEOUT); + if (ret < 0) { + goto out; + } + + ptr = malloc(packet_header_size()); + if (!ptr) { + ErrPrint("Heap: %s\n", strerror(errno)); + goto out; + } + + offset = 0; + ret = com_core_recv(fd, (char *)ptr, packet_header_size(), &pid, timeout); + if (ret <= 0) { + DbgPrint("Recv returns %d\n", ret); + free(ptr); + goto out; + } else { + DbgPrint("Recv'd size: %d (header: %d) pid: %d\n", ret, packet_header_size(), pid); + result = packet_build(result, offset, ptr, ret); + offset += ret; + free(ptr); + if (!result) { + ErrPrint("Failed to build a packet\n"); + goto out; + } + } + + size = packet_payload_size(result); + if (size < 0) { + packet_destroy(result); + result = NULL; + goto out; + } + + if (size == 0) { + DbgPrint("Has no payload\n"); + goto out; + } + + ptr = malloc(size); + if (!ptr) { + ErrPrint("Heap: %s\n", strerror(errno)); + packet_destroy(result); + result = NULL; + goto out; + } + + ret = com_core_recv(fd, (char *)ptr, size, &pid, timeout); + if (ret <= 0) { + DbgPrint("Recv returns %d\n", ret); + free(ptr); + packet_destroy(result); + result = NULL; + } else { + DbgPrint("Recv'd %d bytes (pid: %d)\n", ret, pid); + result = packet_build(result, offset, ptr, ret); + offset += ret; + free(ptr); + } out: - secure_socket_destroy_handle(fd); - DbgPrint("Close connection: %d\n", fd); - return result; + secure_socket_destroy_handle(fd); + DbgPrint("Close connection: %d\n", fd); + return result; } static inline int com_core_packet_init(void) { - int ret; - if (s_info.initialized) { - return 0; - } + int ret; + if (s_info.initialized) { + return 0; + } - ret = com_core_add_event_callback(CONNECTOR_DISCONNECTED, client_disconnected_cb, NULL); - s_info.initialized = (ret == 0); - return ret; + ret = com_core_add_event_callback(CONNECTOR_DISCONNECTED, client_disconnected_cb, NULL); + s_info.initialized = (ret == 0); + return ret; } static inline int com_core_packet_fini(void) { - if (!s_info.initialized) { - return 0; - } - - s_info.initialized = 0; - com_core_del_event_callback(CONNECTOR_DISCONNECTED, client_disconnected_cb, NULL); + if (!s_info.initialized) { return 0; + } + + s_info.initialized = 0; + com_core_del_event_callback(CONNECTOR_DISCONNECTED, client_disconnected_cb, NULL); + return 0; } EAPI int com_core_packet_client_init(const char *addr, int is_sync, struct method *table) { - int ret; + int ret; - ret = com_core_packet_init(); - if (ret < 0) { - return ret; - } + ret = com_core_packet_init(); + if (ret < 0) { + return ret; + } - ret = s_info.vtable.client_create(addr, is_sync, service_cb, table); - if (ret < 0) { - com_core_packet_fini(); - } + ret = s_info.vtable.client_create(addr, is_sync, service_cb, table); + if (ret < 0) { + com_core_packet_fini(); + } - return ret; + return ret; } EAPI int com_core_packet_client_fini(int handle) { - s_info.vtable.client_destroy(handle); - com_core_packet_fini(); - return 0; + s_info.vtable.client_destroy(handle); + com_core_packet_fini(); + return 0; } EAPI int com_core_packet_server_init(const char *addr, struct method *table) { - int ret; + int ret; - ret = com_core_packet_init(); - if (ret < 0) { - return ret; - } + ret = com_core_packet_init(); + if (ret < 0) { + return ret; + } - ret = s_info.vtable.server_create(addr, 0, service_cb, table); - if (ret < 0) { - com_core_packet_fini(); - } + ret = s_info.vtable.server_create(addr, 0, service_cb, table); + if (ret < 0) { + com_core_packet_fini(); + } - return ret; + return ret; } EAPI int com_core_packet_server_fini(int handle) { - s_info.vtable.server_destroy(handle); - com_core_packet_fini(); - return 0; + s_info.vtable.server_destroy(handle); + com_core_packet_fini(); + return 0; } EAPI void com_core_packet_use_thread(int flag) { - if (!!flag) { - s_info.vtable.server_create = com_core_thread_server_create; - s_info.vtable.client_create = com_core_thread_client_create; - s_info.vtable.server_destroy = com_core_thread_server_destroy; - s_info.vtable.client_destroy = com_core_thread_client_destroy; - s_info.vtable.recv = com_core_thread_recv; - s_info.vtable.send = com_core_thread_send; - } else { - s_info.vtable.server_create = com_core_server_create; - s_info.vtable.client_create = com_core_client_create; - s_info.vtable.server_destroy = com_core_server_destroy; - s_info.vtable.client_destroy = com_core_client_destroy; - s_info.vtable.recv = com_core_recv; - s_info.vtable.send = com_core_send; - } + if (s_info.initialized) { + ErrPrint("com-core method is in use\n"); + return; + } + + if (!!flag) { + s_info.vtable.server_create = com_core_thread_server_create; + s_info.vtable.client_create = com_core_thread_client_create; + s_info.vtable.server_destroy = com_core_thread_server_destroy; + s_info.vtable.client_destroy = com_core_thread_client_destroy; + s_info.vtable.recv = com_core_thread_recv; + s_info.vtable.send = com_core_thread_send; + s_info.vtable.recv_with_fd = com_core_thread_recv_with_fd; + s_info.vtable.send_with_fd = com_core_thread_send_with_fd; + } else { + s_info.vtable.server_create = com_core_server_create; + s_info.vtable.client_create = com_core_client_create; + s_info.vtable.server_destroy = com_core_server_destroy; + s_info.vtable.client_destroy = com_core_client_destroy; + s_info.vtable.recv = com_core_recv; + s_info.vtable.send = com_core_send; + s_info.vtable.recv_with_fd = com_core_recv_with_fd; + s_info.vtable.send_with_fd = com_core_send_with_fd; + } } /* End of a file */ diff --git a/src/com-core_thread.c b/src/com-core_thread.c index f5fc9c6..42348c6 100644 --- a/src/com-core_thread.c +++ b/src/com-core_thread.c @@ -41,76 +41,77 @@ int errno; #define EVENT_TERM 'e' static struct { - struct dlist *tcb_list; - struct dlist *server_list; + struct dlist *tcb_list; + struct dlist *server_list; } s_info = { - .tcb_list = NULL, - .server_list = NULL, + .tcb_list = NULL, + .server_list = NULL, }; /*! * \brief Representing the Server Object */ struct server { - int (*service_cb)(int fd, void *data); - void *data; + int (*service_cb)(int fd, void *data); + void *data; - guint id; - int handle; + guint id; + int handle; }; /*! * \brief This is used to holds a packet */ struct chunk { - char *data; - int offset; - int size; - pid_t pid; + char *data; + int offset; + int size; + pid_t pid; + int fd; }; /*! * \brief Thread Control Block */ struct tcb { - pthread_t thid; - int handle; - struct dlist *chunk_list; - int evt_pipe[PIPE_MAX]; - int ctrl_pipe[PIPE_MAX]; - pthread_mutex_t chunk_lock; - guint id; /*!< g_io_watch */ - - int server_handle; - - int (*service_cb)(int fd, void *data); - void *data; + pthread_t thid; + int handle; + struct dlist *chunk_list; + int evt_pipe[PIPE_MAX]; + int ctrl_pipe[PIPE_MAX]; + pthread_mutex_t chunk_lock; + guint id; /*!< g_io_watch */ + + int server_handle; + + int (*service_cb)(int fd, void *data); + void *data; }; static ssize_t write_safe(int fd, const void *data, size_t bufsz) { - int ret; - int again; - - do { - again = 0; - ret = write(fd, data, bufsz); - if (ret < 0) { - ret = -errno; - switch (ret) { - case -EAGAIN: - case -EINTR: - again = 1; - ErrPrint("Interrupted[%d] Again[%d]\n", fd, -ret); - break; - default: - ErrPrint("Failed to write: %s (%d)\n", strerror(-ret), -ret); - return ret; - } - } - } while (again); + int ret; + int again; - return ret; + do { + again = 0; + ret = write(fd, data, bufsz); + if (ret < 0) { + ret = -errno; + switch (ret) { + case -EAGAIN: + case -EINTR: + again = 1; + ErrPrint("Interrupted[%d] Again[%d]\n", fd, -ret); + break; + default: + ErrPrint("Failed to write: %s (%d)\n", strerror(-ret), -ret); + return ret; + } + } + } while (again); + + return ret; } /*! @@ -119,17 +120,17 @@ static ssize_t write_safe(int fd, const void *data, size_t bufsz) */ static inline void server_destroy(struct server *server) { - dlist_remove_data(s_info.server_list, server); + dlist_remove_data(s_info.server_list, server); - if (server->id > 0) { - g_source_remove(server->id); - } + if (server->id > 0) { + g_source_remove(server->id); + } - if (server->handle > 0) { - secure_socket_destroy_handle(server->handle); - } + if (server->handle > 0) { + secure_socket_destroy_handle(server->handle); + } - free(server); + free(server); } /*! @@ -138,20 +139,20 @@ static inline void server_destroy(struct server *server) */ static inline struct server *server_create(int handle, int (*service_cb)(int fd, void *data), void *data) { - struct server *server; + struct server *server; - server = malloc(sizeof(*server)); - if (!server) { - ErrPrint("Heap: %s\n", strerror(errno)); - return NULL; - } + server = malloc(sizeof(*server)); + if (!server) { + ErrPrint("Heap: %s\n", strerror(errno)); + return NULL; + } - server->handle = handle; - server->service_cb = service_cb; - server->data = data; + server->handle = handle; + server->service_cb = service_cb; + server->data = data; - s_info.server_list = dlist_append(s_info.server_list, server); - return server; + s_info.server_list = dlist_append(s_info.server_list, server); + return server; } /*! @@ -160,8 +161,8 @@ static inline struct server *server_create(int handle, int (*service_cb)(int fd, */ static inline void destroy_chunk(struct chunk *chunk) { - free(chunk->data); - free(chunk); + free(chunk->data); + free(chunk); } /*! @@ -170,33 +171,33 @@ static inline void destroy_chunk(struct chunk *chunk) */ static inline void terminate_thread(struct tcb *tcb) { - int status; - struct dlist *l; - struct dlist *n; - void *res = NULL; - struct chunk *chunk; - - if (write_safe(tcb->ctrl_pipe[PIPE_WRITE], &tcb, sizeof(tcb)) != sizeof(tcb)) { - ErrPrint("Unable to write CTRL pipe (%d)\n", sizeof(tcb)); - } - - secure_socket_destroy_handle(tcb->handle); - - status = pthread_join(tcb->thid, &res); - if (status != 0) { - ErrPrint("Join: %s\n", strerror(status)); - } else { - ErrPrint("Thread returns: %d\n", (int)res); - } - - dlist_foreach_safe(tcb->chunk_list, l, n, chunk) { - /*! - * Discarding all packets - */ - DbgPrint("Discarding chunks\n"); - tcb->chunk_list = dlist_remove(tcb->chunk_list, l); - destroy_chunk(chunk); - } + int status; + struct dlist *l; + struct dlist *n; + void *res = NULL; + struct chunk *chunk; + + if (write_safe(tcb->ctrl_pipe[PIPE_WRITE], &tcb, sizeof(tcb)) != sizeof(tcb)) { + ErrPrint("Unable to write CTRL pipe (%d)\n", sizeof(tcb)); + } + + secure_socket_destroy_handle(tcb->handle); + + status = pthread_join(tcb->thid, &res); + if (status != 0) { + ErrPrint("Join: %s\n", strerror(status)); + } else { + ErrPrint("Thread returns: %d\n", (int)res); + } + + dlist_foreach_safe(tcb->chunk_list, l, n, chunk) { + /*! + * Discarding all packets + */ + DbgPrint("Discarding chunks\n"); + tcb->chunk_list = dlist_remove(tcb->chunk_list, l); + destroy_chunk(chunk); + } } /*! @@ -205,21 +206,21 @@ static inline void terminate_thread(struct tcb *tcb) */ static inline void chunk_remove(struct tcb *tcb, struct chunk *chunk) { - char event_ch; + char event_ch; - /* Consuming the event */ - if (read(tcb->evt_pipe[PIPE_READ], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) { - ErrPrint("Failed to get readsize\n"); - return; - } + /* Consuming the event */ + if (read(tcb->evt_pipe[PIPE_READ], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) { + ErrPrint("Failed to get readsize\n"); + return; + } - CRITICAL_SECTION_BEGIN(&tcb->chunk_lock); + CRITICAL_SECTION_BEGIN(&tcb->chunk_lock); - dlist_remove_data(tcb->chunk_list, chunk); + dlist_remove_data(tcb->chunk_list, chunk); - CRITICAL_SECTION_END(&tcb->chunk_lock); + CRITICAL_SECTION_END(&tcb->chunk_lock); - destroy_chunk(chunk); + destroy_chunk(chunk); } /*! @@ -228,32 +229,32 @@ static inline void chunk_remove(struct tcb *tcb, struct chunk *chunk) */ static inline int chunk_append(struct tcb *tcb, struct chunk *chunk) { - char event_ch = EVENT_READY; - int ret; + char event_ch = EVENT_READY; + int ret; - CRITICAL_SECTION_BEGIN(&tcb->chunk_lock); + CRITICAL_SECTION_BEGIN(&tcb->chunk_lock); - tcb->chunk_list = dlist_append(tcb->chunk_list, chunk); + tcb->chunk_list = dlist_append(tcb->chunk_list, chunk); - CRITICAL_SECTION_END(&tcb->chunk_lock); + CRITICAL_SECTION_END(&tcb->chunk_lock); - ret = write_safe(tcb->evt_pipe[PIPE_WRITE], &event_ch, sizeof(event_ch)); - if (ret < 0) { - CRITICAL_SECTION_BEGIN(&tcb->chunk_lock); + ret = write_safe(tcb->evt_pipe[PIPE_WRITE], &event_ch, sizeof(event_ch)); + if (ret < 0) { + CRITICAL_SECTION_BEGIN(&tcb->chunk_lock); - dlist_remove_data(tcb->chunk_list, chunk); + dlist_remove_data(tcb->chunk_list, chunk); - CRITICAL_SECTION_END(&tcb->chunk_lock); - return ret; - } + CRITICAL_SECTION_END(&tcb->chunk_lock); + return ret; + } - if (ret != sizeof(event_ch)) { - ErrPrint("Failed to trigger reader\n"); - } + if (ret != sizeof(event_ch)) { + ErrPrint("Failed to trigger reader\n"); + } - /* Take a breathe */ - pthread_yield(); - return 0; + /* Take a breathe */ + pthread_yield(); + return 0; } /*! @@ -262,44 +263,44 @@ static inline int chunk_append(struct tcb *tcb, struct chunk *chunk) */ static inline int wait_event(struct tcb *tcb, double timeout) { - fd_set set; - int ret; - - FD_ZERO(&set); - FD_SET(tcb->evt_pipe[PIPE_READ], &set); - - if (timeout > 0.0f) { - struct timeval tv; - tv.tv_sec = (unsigned long)timeout; - tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u; - ret = select(tcb->evt_pipe[PIPE_READ] + 1, &set, NULL, NULL, &tv); - } else if (timeout == 0.0f) { - ret = select(tcb->evt_pipe[PIPE_READ] + 1, &set, NULL, NULL, NULL); - } else { - ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout); - return -EINVAL; + fd_set set; + int ret; + + FD_ZERO(&set); + FD_SET(tcb->evt_pipe[PIPE_READ], &set); + + if (timeout > 0.0f) { + struct timeval tv; + tv.tv_sec = (unsigned long)timeout; + tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u; + ret = select(tcb->evt_pipe[PIPE_READ] + 1, &set, NULL, NULL, &tv); + } else if (timeout == 0.0f) { + ret = select(tcb->evt_pipe[PIPE_READ] + 1, &set, NULL, NULL, NULL); + } else { + ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout); + return -EINVAL; + } + + if (ret < 0) { + ret = -errno; + if (errno == EINTR) { + DbgPrint("Select receives INTR\n"); + return -EAGAIN; } - if (ret < 0) { - ret = -errno; - if (errno == EINTR) { - DbgPrint("Select receives INTR\n"); - return -EAGAIN; - } - - ErrPrint("Error: %s\n", strerror(errno)); - return ret; - } else if (ret == 0) { - ErrPrint("Timeout expired\n"); - return -ETIMEDOUT; - } + ErrPrint("Error: %s\n", strerror(errno)); + return ret; + } else if (ret == 0) { + ErrPrint("Timeout expired\n"); + return -ETIMEDOUT; + } - if (!FD_ISSET(tcb->evt_pipe[PIPE_READ], &set)) { - ErrPrint("Unexpected handle is toggled\n"); - return -EINVAL; - } + if (!FD_ISSET(tcb->evt_pipe[PIPE_READ], &set)) { + ErrPrint("Unexpected handle is toggled\n"); + return -EINVAL; + } - return 0; + return 0; } /*! @@ -308,25 +309,26 @@ static inline int wait_event(struct tcb *tcb, double timeout) */ static inline struct chunk *create_chunk(int size) { - struct chunk *chunk; + struct chunk *chunk; - chunk = malloc(sizeof(*chunk)); - if (!chunk) { - ErrPrint("Heap: %s\n", strerror(errno)); - return NULL; - } + chunk = malloc(sizeof(*chunk)); + if (!chunk) { + ErrPrint("Heap: %s\n", strerror(errno)); + return NULL; + } - chunk->data = malloc(size); - if (!chunk->data) { - ErrPrint("Heap: %s\n", strerror(errno)); - free(chunk); - return NULL; - } + chunk->data = malloc(size); + if (!chunk->data) { + ErrPrint("Heap: %s\n", strerror(errno)); + free(chunk); + return NULL; + } - chunk->pid = (pid_t)-1; - chunk->size = size; - chunk->offset = 0; - return chunk; + chunk->pid = (pid_t)-1; + chunk->size = size; + chunk->offset = 0; + chunk->fd = -1; + return chunk; } /*! @@ -335,106 +337,106 @@ static inline struct chunk *create_chunk(int size) */ static void *client_cb(void *data) { - struct tcb *tcb = data; - struct chunk *chunk; - int ret = 0; - fd_set set; - int readsize; - char event_ch; - int fd; - - DbgPrint("Thread is created for %d (server: %d)\n", tcb->handle, tcb->server_handle); - /*! - * \NOTE - * Read all data from the socket as possible as it can do - */ - while (1) { - FD_ZERO(&set); - FD_SET(tcb->handle, &set); - FD_SET(tcb->ctrl_pipe[PIPE_READ], &set); - - fd = tcb->handle > tcb->ctrl_pipe[PIPE_READ] ? tcb->handle : tcb->ctrl_pipe[PIPE_READ]; - - ret = select(fd + 1, &set, NULL, NULL, NULL); - if (ret < 0) { - if (errno == EINTR) { - DbgPrint("Select receives INTR\n"); - continue; - } - ret = -errno; - /*!< Error */ - ErrPrint("Error: %s\n", strerror(errno)); - break; - } else if (ret == 0) { - ErrPrint("What happens? [%d]\n", tcb->handle); - continue; - } + struct tcb *tcb = data; + struct chunk *chunk; + int ret = 0; + fd_set set; + int readsize; + char event_ch; + int fd; + + DbgPrint("Thread is created for %d (server: %d)\n", tcb->handle, tcb->server_handle); + /*! + * \NOTE + * Read all data from the socket as possible as it can do + */ + while (1) { + FD_ZERO(&set); + FD_SET(tcb->handle, &set); + FD_SET(tcb->ctrl_pipe[PIPE_READ], &set); - if (FD_ISSET(tcb->ctrl_pipe[PIPE_READ], &set)) { - DbgPrint("Thread is canceled\n"); - ret = -ECANCELED; - break; - } + fd = tcb->handle > tcb->ctrl_pipe[PIPE_READ] ? tcb->handle : tcb->ctrl_pipe[PIPE_READ]; - if (!FD_ISSET(tcb->handle, &set)) { - ErrPrint("Unexpected handle is toggled\n"); - ret = -EINVAL; - break; - } + ret = select(fd + 1, &set, NULL, NULL, NULL); + if (ret < 0) { + if (errno == EINTR) { + DbgPrint("Select receives INTR\n"); + continue; + } + ret = -errno; + /*!< Error */ + ErrPrint("Error: %s\n", strerror(errno)); + break; + } else if (ret == 0) { + ErrPrint("What happens? [%d]\n", tcb->handle); + continue; + } - readsize = 0; - ret = ioctl(tcb->handle, FIONREAD, &readsize); - if (ret < 0) { - ErrPrint("ioctl: %s\n", strerror(errno)); - break; - } + if (FD_ISSET(tcb->ctrl_pipe[PIPE_READ], &set)) { + DbgPrint("Thread is canceled\n"); + ret = -ECANCELED; + break; + } - if (readsize <= 0) { - ErrPrint("Available data: %d\n", readsize); - ret = -ECONNRESET; - break; - } + if (!FD_ISSET(tcb->handle, &set)) { + ErrPrint("Unexpected handle is toggled\n"); + ret = -EINVAL; + break; + } - chunk = create_chunk(readsize); - if (!chunk) { - ErrPrint("Failed to create a new chunk: %d\n", readsize); - ret = -ENOMEM; - break; - } + readsize = 0; + ret = ioctl(tcb->handle, FIONREAD, &readsize); + if (ret < 0) { + ErrPrint("ioctl: %s\n", strerror(errno)); + break; + } - ret = secure_socket_recv(tcb->handle, chunk->data, chunk->size, &chunk->pid); - if (ret <= 0) { - destroy_chunk(chunk); - if (ret == -EAGAIN) { - DbgPrint("Retry to get data\n"); - continue; - } + if (readsize <= 0) { + ErrPrint("Available data: %d\n", readsize); + ret = -ECONNRESET; + break; + } - DbgPrint("Recv returns: %d\n", ret); - break; - } + chunk = create_chunk(readsize); + if (!chunk) { + ErrPrint("Failed to create a new chunk: %d\n", readsize); + ret = -ENOMEM; + break; + } - /* Update chunk size */ - chunk->size = ret; + ret = secure_socket_recv(tcb->handle, chunk->data, chunk->size, &chunk->pid, &chunk->fd); + if (ret <= 0) { + destroy_chunk(chunk); + if (ret == -EAGAIN) { + DbgPrint("Retry to get data\n"); + continue; + } - /*! - * Count of chunk elements are same with PIPE'd data - */ - if (chunk_append(tcb, chunk) < 0) { - destroy_chunk(chunk); - break; - } + DbgPrint("Recv returns: %d\n", ret); + break; } - DbgPrint("Client CB is terminated (%d)\n", tcb->handle); - /* Wake up main thread to get disconnected event */ - event_ch = EVENT_TERM; + /* Update chunk size */ + chunk->size = ret; - if (write_safe(tcb->evt_pipe[PIPE_WRITE], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) { - ErrPrint("%d byte is not written\n", sizeof(event_ch)); + /*! + * Count of chunk elements are same with PIPE'd data + */ + if (chunk_append(tcb, chunk) < 0) { + destroy_chunk(chunk); + break; } + } + + DbgPrint("Client CB is terminated (%d)\n", tcb->handle); + /* Wake up main thread to get disconnected event */ + event_ch = EVENT_TERM; - return (void *)(unsigned long)ret; + if (write_safe(tcb->evt_pipe[PIPE_WRITE], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) { + ErrPrint("%d byte is not written\n", sizeof(event_ch)); + } + + return (void *)(unsigned long)ret; } /*! @@ -443,23 +445,23 @@ static void *client_cb(void *data) */ static inline void tcb_destroy(struct tcb *tcb) { - int status; + int status; - dlist_remove_data(s_info.tcb_list, tcb); + dlist_remove_data(s_info.tcb_list, tcb); - if (tcb->id > 0) { - g_source_remove(tcb->id); - } + if (tcb->id > 0) { + g_source_remove(tcb->id); + } - CLOSE_PIPE(tcb->evt_pipe); - CLOSE_PIPE(tcb->ctrl_pipe); + CLOSE_PIPE(tcb->evt_pipe); + CLOSE_PIPE(tcb->ctrl_pipe); - status = pthread_mutex_destroy(&tcb->chunk_lock); - if (status != 0) { - ErrPrint("Failed to destroy mutex: %s\n", strerror(status)); - } + status = pthread_mutex_destroy(&tcb->chunk_lock); + if (status != 0) { + ErrPrint("Failed to destroy mutex: %s\n", strerror(status)); + } - free(tcb); + free(tcb); } /*! @@ -468,41 +470,41 @@ static inline void tcb_destroy(struct tcb *tcb) */ static gboolean evt_pipe_cb(GIOChannel *src, GIOCondition cond, gpointer data) { - int pipe_read; - struct tcb *tcb = data; - int ret; + int pipe_read; + struct tcb *tcb = data; + int ret; - pipe_read = g_io_channel_unix_get_fd(src); + pipe_read = g_io_channel_unix_get_fd(src); - if (tcb->evt_pipe[PIPE_READ] != pipe_read) { - ErrPrint("Closed handle (%d <> %d)\n", tcb->evt_pipe[PIPE_READ], pipe_read); - goto errout; - } + if (tcb->evt_pipe[PIPE_READ] != pipe_read) { + ErrPrint("Closed handle (%d <> %d)\n", tcb->evt_pipe[PIPE_READ], pipe_read); + goto errout; + } - if (!(cond & G_IO_IN)) { - ErrPrint("PIPE is not valid\n"); - goto errout; - } + if (!(cond & G_IO_IN)) { + ErrPrint("PIPE is not valid\n"); + goto errout; + } - if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) { - ErrPrint("PIPE is not valid\n"); - goto errout; - } + if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) { + ErrPrint("PIPE is not valid\n"); + goto errout; + } - ret = tcb->service_cb(tcb->handle, tcb->data); - if (ret < 0) { - DbgPrint("Service callback returns %d < 0\n", ret); - goto errout; - } + ret = tcb->service_cb(tcb->handle, tcb->data); + if (ret < 0) { + DbgPrint("Service callback returns %d < 0\n", ret); + goto errout; + } - return TRUE; + return TRUE; errout: - DbgPrint("Disconnecting\n"); - invoke_disconn_cb_list(tcb->handle, 0, 0, 0); - terminate_thread(tcb); - tcb_destroy(tcb); - return FALSE; + DbgPrint("Disconnecting\n"); + invoke_disconn_cb_list(tcb->handle, 0, 0, 0); + terminate_thread(tcb); + tcb_destroy(tcb); + return FALSE; } /*! @@ -511,54 +513,54 @@ errout: */ static inline struct tcb *tcb_create(int client_fd, int is_sync, int (*service_cb)(int fd, void *data), void *data) { - struct tcb *tcb; - int status; + struct tcb *tcb; + int status; - tcb = malloc(sizeof(*tcb)); - if (!tcb) { - ErrPrint("Error: %s\n", strerror(errno)); - return NULL; - } + tcb = malloc(sizeof(*tcb)); + if (!tcb) { + ErrPrint("Error: %s\n", strerror(errno)); + return NULL; + } - tcb->handle = client_fd; - tcb->chunk_list = NULL; - tcb->service_cb = service_cb; - tcb->data = data; - tcb->id = 0; + tcb->handle = client_fd; + tcb->chunk_list = NULL; + tcb->service_cb = service_cb; + tcb->data = data; + tcb->id = 0; - status = pthread_mutex_init(&tcb->chunk_lock, NULL); - if (status != 0) { - ErrPrint("Error: %s\n", strerror(status)); - free(tcb); - return NULL; - } + status = pthread_mutex_init(&tcb->chunk_lock, NULL); + if (status != 0) { + ErrPrint("Error: %s\n", strerror(status)); + free(tcb); + return NULL; + } - if (pipe2(tcb->evt_pipe, O_CLOEXEC) < 0) { - ErrPrint("Error: %s\n", strerror(errno)); - status = pthread_mutex_destroy(&tcb->chunk_lock); - if (status != 0) { - ErrPrint("Error: %s\n", strerror(status)); - } - free(tcb); - return NULL; + if (pipe2(tcb->evt_pipe, O_CLOEXEC) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + status = pthread_mutex_destroy(&tcb->chunk_lock); + if (status != 0) { + ErrPrint("Error: %s\n", strerror(status)); } + free(tcb); + return NULL; + } - if (pipe2(tcb->ctrl_pipe, O_CLOEXEC) < 0) { - ErrPrint("Error: %s\n", strerror(errno)); - - CLOSE_PIPE(tcb->evt_pipe); + if (pipe2(tcb->ctrl_pipe, O_CLOEXEC) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); - status = pthread_mutex_destroy(&tcb->chunk_lock); - if (status != 0) { - ErrPrint("Error: %s\n", strerror(status)); - } + CLOSE_PIPE(tcb->evt_pipe); - free(tcb); - return NULL; + status = pthread_mutex_destroy(&tcb->chunk_lock); + if (status != 0) { + ErrPrint("Error: %s\n", strerror(status)); } - DbgPrint("[%d] New TCB created: R(%d), W(%d)\n", client_fd, tcb->evt_pipe[PIPE_READ], tcb->evt_pipe[PIPE_WRITE]); - return tcb; + free(tcb); + return NULL; + } + + DbgPrint("[%d] New TCB created: R(%d), W(%d)\n", client_fd, tcb->evt_pipe[PIPE_READ], tcb->evt_pipe[PIPE_WRITE]); + return tcb; } /*! @@ -567,94 +569,94 @@ static inline struct tcb *tcb_create(int client_fd, int is_sync, int (*service_c */ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer data) { - int socket_fd; - int fd; - int ret; - struct tcb *tcb; - GIOChannel *gio; - struct server *server = data; - - socket_fd = g_io_channel_unix_get_fd(src); - if (!(cond & G_IO_IN)) { - ErrPrint("Accept socket closed\n"); - server_destroy(server); - return FALSE; - } - - if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) { - DbgPrint("Socket connection is lost\n"); - server_destroy(server); - return FALSE; - } - - fd = secure_socket_get_connection_handle(socket_fd); - if (fd < 0) { - ErrPrint("Failed to get client fd from socket\n"); - server_destroy(server); - return FALSE; - } + int socket_fd; + int fd; + int ret; + struct tcb *tcb; + GIOChannel *gio; + struct server *server = data; + + socket_fd = g_io_channel_unix_get_fd(src); + if (!(cond & G_IO_IN)) { + ErrPrint("Accept socket closed\n"); + server_destroy(server); + return FALSE; + } - if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { - ErrPrint("Error: %s\n", strerror(errno)); - } + if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) { + DbgPrint("Socket connection is lost\n"); + server_destroy(server); + return FALSE; + } - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - ErrPrint("Error: %s\n", strerror(errno)); - } + fd = secure_socket_get_connection_handle(socket_fd); + if (fd < 0) { + ErrPrint("Failed to get client fd from socket\n"); + server_destroy(server); + return FALSE; + } - tcb = tcb_create(fd, 0, server->service_cb, server->data); - if (!tcb) { - ErrPrint("Failed to create a TCB\n"); - secure_socket_destroy_handle(fd); - server_destroy(server); - return FALSE; - } + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + } - tcb->server_handle = socket_fd; + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + } - s_info.tcb_list = dlist_append(s_info.tcb_list, tcb); + tcb = tcb_create(fd, 0, server->service_cb, server->data); + if (!tcb) { + ErrPrint("Failed to create a TCB\n"); + secure_socket_destroy_handle(fd); + server_destroy(server); + return FALSE; + } - gio = g_io_channel_unix_new(tcb->evt_pipe[PIPE_READ]); - if (!gio) { - ErrPrint("Failed to get gio\n"); - secure_socket_destroy_handle(tcb->handle); - tcb_destroy(tcb); - server_destroy(server); - return FALSE; - } + tcb->server_handle = socket_fd; - g_io_channel_set_close_on_unref(gio, FALSE); + s_info.tcb_list = dlist_append(s_info.tcb_list, tcb); - tcb->id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)evt_pipe_cb, tcb); - if (tcb->id == 0) { - GError *err = NULL; - ErrPrint("Failed to add IO Watch\n"); - g_io_channel_shutdown(gio, TRUE, &err); - if (err) { - ErrPrint("Shutdown: %s\n", err->message); - g_error_free(err); - } - g_io_channel_unref(gio); - secure_socket_destroy_handle(tcb->handle); - tcb_destroy(tcb); - server_destroy(server); - return FALSE; + gio = g_io_channel_unix_new(tcb->evt_pipe[PIPE_READ]); + if (!gio) { + ErrPrint("Failed to get gio\n"); + secure_socket_destroy_handle(tcb->handle); + tcb_destroy(tcb); + server_destroy(server); + return FALSE; + } + + g_io_channel_set_close_on_unref(gio, FALSE); + + tcb->id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)evt_pipe_cb, tcb); + if (tcb->id == 0) { + GError *err = NULL; + ErrPrint("Failed to add IO Watch\n"); + g_io_channel_shutdown(gio, TRUE, &err); + if (err) { + ErrPrint("Shutdown: %s\n", err->message); + g_error_free(err); } g_io_channel_unref(gio); + secure_socket_destroy_handle(tcb->handle); + tcb_destroy(tcb); + server_destroy(server); + return FALSE; + } + g_io_channel_unref(gio); - invoke_con_cb_list(tcb->handle, tcb->handle, 0, NULL, 0); + invoke_con_cb_list(tcb->handle, tcb->handle, 0, NULL, 0); - ret = pthread_create(&tcb->thid, NULL, client_cb, tcb); - if (ret != 0) { - ErrPrint("Thread creation failed: %s\n", strerror(ret)); - invoke_disconn_cb_list(tcb->handle, 0, 0, 0); - secure_socket_destroy_handle(tcb->handle); - tcb_destroy(tcb); - server_destroy(server); - return FALSE; - } + ret = pthread_create(&tcb->thid, NULL, client_cb, tcb); + if (ret != 0) { + ErrPrint("Thread creation failed: %s\n", strerror(ret)); + invoke_disconn_cb_list(tcb->handle, 0, 0, 0); + secure_socket_destroy_handle(tcb->handle); + tcb_destroy(tcb); + server_destroy(server); + return FALSE; + } - return TRUE; + return TRUE; } /*! @@ -663,74 +665,74 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer data) */ EAPI int com_core_thread_client_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data) { - GIOChannel *gio; - int client_fd; - struct tcb *tcb; - int ret; - - client_fd = secure_socket_create_client(addr); - if (client_fd < 0) { - return client_fd; - } - - if (fcntl(client_fd, F_SETFD, FD_CLOEXEC) < 0) { - ErrPrint("Error: %s\n", strerror(errno)); - } - - if (fcntl(client_fd, F_SETFL, O_NONBLOCK) < 0) { - ErrPrint("Error: %s\n", strerror(errno)); - } - - tcb = tcb_create(client_fd, is_sync, service_cb, data); - if (!tcb) { - ErrPrint("Failed to create a new TCB\n"); - secure_socket_destroy_handle(client_fd); - return -EFAULT; - } - - tcb->server_handle = -1; - - s_info.tcb_list = dlist_append(s_info.tcb_list, tcb); - - gio = g_io_channel_unix_new(tcb->evt_pipe[PIPE_READ]); - if (!gio) { - ErrPrint("Failed to get gio\n"); - secure_socket_destroy_handle(tcb->handle); - tcb_destroy(tcb); - return -EIO; - } - - g_io_channel_set_close_on_unref(gio, FALSE); - - tcb->id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)evt_pipe_cb, tcb); - if (tcb->id == 0) { - GError *err = NULL; - ErrPrint("Failed to add IO Watch\n"); - g_io_channel_shutdown(gio, TRUE, &err); - if (err) { - ErrPrint("Shutdown: %s\n", err->message); - g_error_free(err); - } - g_io_channel_unref(gio); - secure_socket_destroy_handle(tcb->handle); - tcb_destroy(tcb); - return -EIO; + GIOChannel *gio; + int client_fd; + struct tcb *tcb; + int ret; + + client_fd = secure_socket_create_client(addr); + if (client_fd < 0) { + return client_fd; + } + + if (fcntl(client_fd, F_SETFD, FD_CLOEXEC) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + } + + if (fcntl(client_fd, F_SETFL, O_NONBLOCK) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + } + + tcb = tcb_create(client_fd, is_sync, service_cb, data); + if (!tcb) { + ErrPrint("Failed to create a new TCB\n"); + secure_socket_destroy_handle(client_fd); + return -EFAULT; + } + + tcb->server_handle = -1; + + s_info.tcb_list = dlist_append(s_info.tcb_list, tcb); + + gio = g_io_channel_unix_new(tcb->evt_pipe[PIPE_READ]); + if (!gio) { + ErrPrint("Failed to get gio\n"); + secure_socket_destroy_handle(tcb->handle); + tcb_destroy(tcb); + return -EIO; + } + + g_io_channel_set_close_on_unref(gio, FALSE); + + tcb->id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)evt_pipe_cb, tcb); + if (tcb->id == 0) { + GError *err = NULL; + ErrPrint("Failed to add IO Watch\n"); + g_io_channel_shutdown(gio, TRUE, &err); + if (err) { + ErrPrint("Shutdown: %s\n", err->message); + g_error_free(err); } - g_io_channel_unref(gio); + secure_socket_destroy_handle(tcb->handle); + tcb_destroy(tcb); + return -EIO; + } - invoke_con_cb_list(tcb->handle, tcb->handle, 0, NULL, 0); + g_io_channel_unref(gio); - ret = pthread_create(&tcb->thid, NULL, client_cb, tcb); - if (ret != 0) { - ErrPrint("Thread creation failed: %s\n", strerror(ret)); - invoke_disconn_cb_list(tcb->handle, 0, 0, 0); - secure_socket_destroy_handle(tcb->handle); - tcb_destroy(tcb); - return -EFAULT; - } + invoke_con_cb_list(tcb->handle, tcb->handle, 0, NULL, 0); + + ret = pthread_create(&tcb->thid, NULL, client_cb, tcb); + if (ret != 0) { + ErrPrint("Thread creation failed: %s\n", strerror(ret)); + invoke_disconn_cb_list(tcb->handle, 0, 0, 0); + secure_socket_destroy_handle(tcb->handle); + tcb_destroy(tcb); + return -EFAULT; + } - return tcb->handle; + return tcb->handle; } /*! @@ -739,55 +741,55 @@ EAPI int com_core_thread_client_create(const char *addr, int is_sync, int (*serv */ EAPI int com_core_thread_server_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data) { - GIOChannel *gio; - int fd; - struct server *server; - - fd = secure_socket_create_server(addr); - if (fd < 0) { - return fd; - } - - if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { - ErrPrint("fcntl: %s\n", strerror(errno)); + GIOChannel *gio; + int fd; + struct server *server; + + fd = secure_socket_create_server(addr); + if (fd < 0) { + return fd; + } + + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { + ErrPrint("fcntl: %s\n", strerror(errno)); + } + + if (!is_sync && fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + ErrPrint("fcntl: %s\n", strerror(errno)); + } + + server = server_create(fd, service_cb, data); + if (!server) { + secure_socket_destroy_handle(fd); + return -ENOMEM; + } + + DbgPrint("Create new IO channel for socket FD: %d\n", fd); + gio = g_io_channel_unix_new(server->handle); + if (!gio) { + ErrPrint("Failed to create new io channel\n"); + server_destroy(server); + return -EIO; + } + + g_io_channel_set_close_on_unref(gio, FALSE); + + server->id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc)accept_cb, server); + if (server->id == 0) { + GError *err = NULL; + ErrPrint("Failed to add IO watch\n"); + g_io_channel_shutdown(gio, TRUE, &err); + if (err) { + ErrPrint("Shutdown: %s\n", err->message); + g_error_free(err); } - - if (!is_sync && fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - ErrPrint("fcntl: %s\n", strerror(errno)); - } - - server = server_create(fd, service_cb, data); - if (!server) { - secure_socket_destroy_handle(fd); - return -ENOMEM; - } - - DbgPrint("Create new IO channel for socket FD: %d\n", fd); - gio = g_io_channel_unix_new(server->handle); - if (!gio) { - ErrPrint("Failed to create new io channel\n"); - server_destroy(server); - return -EIO; - } - - g_io_channel_set_close_on_unref(gio, FALSE); - - server->id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc)accept_cb, server); - if (server->id == 0) { - GError *err = NULL; - ErrPrint("Failed to add IO watch\n"); - g_io_channel_shutdown(gio, TRUE, &err); - if (err) { - ErrPrint("Shutdown: %s\n", err->message); - g_error_free(err); - } - g_io_channel_unref(gio); - server_destroy(server); - return -EIO; - } - g_io_channel_unref(gio); - return server->handle; + server_destroy(server); + return -EIO; + } + + g_io_channel_unref(gio); + return server->handle; } /*! @@ -796,201 +798,226 @@ EAPI int com_core_thread_server_create(const char *addr, int is_sync, int (*serv */ static inline struct tcb *find_tcb_by_handle(int handle) { - struct dlist *l; - struct tcb *tcb; + struct dlist *l; + struct tcb *tcb; - dlist_foreach(s_info.tcb_list, l, tcb) { - if (tcb->handle == handle) { - return tcb; - } + dlist_foreach(s_info.tcb_list, l, tcb) { + if (tcb->handle == handle) { + return tcb; } + } - return NULL; + return NULL; } -/*! - * \NOTE - * Running thread: Main - */ -EAPI int com_core_thread_send(int handle, const char *buffer, int size, double timeout) +EAPI int com_core_thread_send_with_fd(int handle, const char *buffer, int size, double timeout, int fd) { - int writesize; - int ret; - struct tcb *tcb; + int writesize; + int ret; + struct tcb *tcb; - fd_set set; + fd_set set; - tcb = find_tcb_by_handle(handle); - if (!tcb) { - ErrPrint("TCB is not found\n"); - return -EINVAL; - } - - writesize = 0; - while (size > 0) { - FD_ZERO(&set); - FD_SET(tcb->handle, &set); + tcb = find_tcb_by_handle(handle); + if (!tcb) { + ErrPrint("TCB is not found\n"); + return -EINVAL; + } - if (timeout > 0.0f) { - struct timeval tv; + writesize = 0; + while (size > 0) { + FD_ZERO(&set); + FD_SET(tcb->handle, &set); - tv.tv_sec = (unsigned long)timeout; - tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u; + if (timeout > 0.0f) { + struct timeval tv; - ret = select(tcb->handle + 1, NULL, &set, NULL, &tv); - } else if (timeout == 0.0f) { - ret = select(tcb->handle + 1, NULL, &set, NULL, NULL); - } else { - ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout); - return -EINVAL; - } + tv.tv_sec = (unsigned long)timeout; + tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u; - if (ret < 0) { - ret = -errno; - if (errno == EINTR) { - DbgPrint("Select receives INTR\n"); - continue; - } - - ErrPrint("Error: %s\n", strerror(errno)); - return ret; - } else if (ret == 0) { - ErrPrint("Timeout expired\n"); - break; - } + ret = select(tcb->handle + 1, NULL, &set, NULL, &tv); + } else if (timeout == 0.0f) { + ret = select(tcb->handle + 1, NULL, &set, NULL, NULL); + } else { + ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout); + return -EINVAL; + } - if (!FD_ISSET(tcb->handle, &set)) { - ErrPrint("Unexpected handle is toggled\n"); - return -EINVAL; - } + if (ret < 0) { + ret = -errno; + if (errno == EINTR) { + DbgPrint("Select receives INTR\n"); + continue; + } + + ErrPrint("Error: %s\n", strerror(errno)); + return ret; + } else if (ret == 0) { + ErrPrint("Timeout expired\n"); + break; + } - ret = secure_socket_send(tcb->handle, buffer + writesize, size); - if (ret < 0) { - if (ret == -EAGAIN) { - DbgPrint("Retry to send data (%d:%d)\n", writesize, size); - continue; - } - DbgPrint("Failed to send: %d\n", ret); - return ret; - } else if (ret == 0) { - DbgPrint("Disconnected? : Send bytes: 0\n"); - return 0; - } + if (!FD_ISSET(tcb->handle, &set)) { + ErrPrint("Unexpected handle is toggled\n"); + return -EINVAL; + } - size -= ret; - writesize += ret; + ret = secure_socket_send(tcb->handle, buffer + writesize, size, fd); + if (ret < 0) { + if (ret == -EAGAIN) { + DbgPrint("Retry to send data (%d:%d)\n", writesize, size); + continue; + } + DbgPrint("Failed to send: %d\n", ret); + return ret; + } else if (ret == 0) { + DbgPrint("Disconnected? : Send bytes: 0\n"); + return 0; } - return writesize; + fd = -1; /* Send only once if it is fd */ + size -= ret; + writesize += ret; + } + + return writesize; } /*! * \NOTE * Running thread: Main */ -EAPI int com_core_thread_recv(int handle, char *buffer, int size, int *sender_pid, double timeout) +EAPI int com_core_thread_send(int handle, const char *buffer, int size, double timeout) { - int readsize; - int ret; - struct chunk *chunk; - struct dlist *l; - struct tcb *tcb; - - tcb = find_tcb_by_handle(handle); - if (!tcb) { - ErrPrint("TCB is not exists\n"); - return -EINVAL; - } + return com_core_thread_send_with_fd(handle, buffer, size, timeout, -1); +} - readsize = 0; - while (readsize < size) { - l = dlist_nth(tcb->chunk_list, 0); - chunk = dlist_data(l); - /*! - * \note - * Pumping up the pipe data - * This is the first time to use a chunk - */ - if (!chunk) { - ret = wait_event(tcb, timeout); - if (ret == -EAGAIN) { - /* Log is printed from wait_event */ - continue; - } else if (ret == -ECONNRESET) { - DbgPrint("Connection is lost\n"); - break; - } else if (ret < 0) { - /* Log is printed from wait_event */ - return ret; - } - - l = dlist_nth(tcb->chunk_list, 0); - chunk = dlist_data(l); - if (!chunk) { - char event_ch; - - /* Consuming the event */ - if (read(tcb->evt_pipe[PIPE_READ], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) { - ErrPrint("Failed to get readsize: %s\n", strerror(errno)); - } else if (event_ch == EVENT_READY) { - ErrPrint("Failed to get a new chunk\n"); - } else if (event_ch == EVENT_TERM) { - DbgPrint("Disconnected\n"); - } - - break; - } +EAPI int com_core_thread_recv_with_fd(int handle, char *buffer, int size, int *sender_pid, double timeout, int *fd) +{ + int readsize; + int ret; + struct chunk *chunk; + struct dlist *l; + struct tcb *tcb; + int _sender_pid; + int _fd; + + tcb = find_tcb_by_handle(handle); + if (!tcb) { + ErrPrint("TCB is not exists\n"); + return -EINVAL; + } + + if (!sender_pid) { + sender_pid = &_sender_pid; + } + + if (!fd) { + fd = &_fd; + } + + *fd = -1; + readsize = 0; + while (readsize < size) { + l = dlist_nth(tcb->chunk_list, 0); + chunk = dlist_data(l); + /*! + * \note + * Pumping up the pipe data + * This is the first time to use a chunk + */ + if (!chunk) { + ret = wait_event(tcb, timeout); + if (ret == -EAGAIN) { + /* Log is printed from wait_event */ + continue; + } else if (ret == -ECONNRESET) { + DbgPrint("Connection is lost\n"); + break; + } else if (ret < 0) { + /* Log is printed from wait_event */ + return ret; + } + + l = dlist_nth(tcb->chunk_list, 0); + chunk = dlist_data(l); + if (!chunk) { + char event_ch; + + /* Consuming the event */ + if (read(tcb->evt_pipe[PIPE_READ], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) { + ErrPrint("Failed to get readsize: %s\n", strerror(errno)); + } else if (event_ch == EVENT_READY) { + ErrPrint("Failed to get a new chunk\n"); + } else if (event_ch == EVENT_TERM) { + DbgPrint("Disconnected\n"); } - ret = chunk->size - chunk->offset; - ret = ret > (size - readsize) ? (size - readsize) : ret; - memcpy(buffer + readsize, chunk->data + chunk->offset, ret); - readsize += ret; - chunk->offset += ret; + break; + } + } - *sender_pid = chunk->pid; + ret = chunk->size - chunk->offset; + ret = ret > (size - readsize) ? (size - readsize) : ret; + memcpy(buffer + readsize, chunk->data + chunk->offset, ret); + readsize += ret; + chunk->offset += ret; - if (chunk->offset == chunk->size) { - chunk_remove(tcb, chunk); - } + *sender_pid = chunk->pid; + if (chunk->fd >= 0) { + *fd = chunk->fd; + } + + if (chunk->offset == chunk->size) { + chunk_remove(tcb, chunk); } + } - return readsize; + return readsize; } /*! * \NOTE * Running thread: Main */ -EAPI int com_core_thread_server_destroy(int handle) +EAPI int com_core_thread_recv(int handle, char *buffer, int size, int *sender_pid, double timeout) { - struct dlist *l; - struct dlist *n; - struct tcb *tcb; - struct server *server; - - dlist_foreach_safe(s_info.tcb_list, l, n, tcb) { - if (tcb->server_handle != handle) { - continue; - } + return com_core_thread_recv_with_fd(handle, buffer, size, sender_pid, timeout, NULL); +} - invoke_disconn_cb_list(handle, 0, 0, 0); - terminate_thread(tcb); - tcb_destroy(tcb); - return 0; +/*! + * \NOTE + * Running thread: Main + */ +EAPI int com_core_thread_server_destroy(int handle) +{ + struct dlist *l; + struct dlist *n; + struct tcb *tcb; + struct server *server; + + dlist_foreach_safe(s_info.tcb_list, l, n, tcb) { + if (tcb->server_handle != handle) { + continue; } - dlist_foreach_safe(s_info.server_list, l, n, server) { - if (server->handle != handle) { - continue; - } + invoke_disconn_cb_list(handle, 0, 0, 0); + terminate_thread(tcb); + tcb_destroy(tcb); + return 0; + } - invoke_disconn_cb_list(handle, 0, 0, 0); - server_destroy(server); - return 0; + dlist_foreach_safe(s_info.server_list, l, n, server) { + if (server->handle != handle) { + continue; } - return -ENOENT; + invoke_disconn_cb_list(handle, 0, 0, 0); + server_destroy(server); + return 0; + } + + return -ENOENT; } /*! @@ -999,17 +1026,17 @@ EAPI int com_core_thread_server_destroy(int handle) */ EAPI int com_core_thread_client_destroy(int handle) { - struct tcb *tcb; + struct tcb *tcb; - tcb = find_tcb_by_handle(handle); - if (!tcb) { - return -ENOENT; - } + tcb = find_tcb_by_handle(handle); + if (!tcb) { + return -ENOENT; + } - invoke_disconn_cb_list(handle, 0, 0, 0); - terminate_thread(tcb); - tcb_destroy(tcb); - return 0; + invoke_disconn_cb_list(handle, 0, 0, 0); + terminate_thread(tcb); + tcb_destroy(tcb); + return 0; } /* End of a file */ diff --git a/src/secure_socket.c b/src/secure_socket.c index c6252df..a1f69eb 100644 --- a/src/secure_socket.c +++ b/src/secure_socket.c @@ -42,482 +42,507 @@ #define RCVBUF_SZ 524288 /*!< 512 KB, this will be doubled by kernel */ enum scheme { - SCHEME_LOCAL = 0x00, - SCHEME_REMOTE = 0x01, - SCHEME_UNKNOWN = 0x02, + SCHEME_LOCAL = 0x00, + SCHEME_REMOTE = 0x01, + SCHEME_UNKNOWN = 0x02, }; struct function_table { - int type; - int (*create_socket)(const char *peer, int port, struct sockaddr *addr); - int (*setup_handle)(int handle); + int type; + int (*create_socket)(const char *peer, int port, struct sockaddr *addr); + int (*setup_handle)(int handle); }; int errno; static inline int create_unix_socket(const char *peer, int port, struct sockaddr *addr) { - int len; - int handle; - struct sockaddr_un *un_addr = (struct sockaddr_un *)addr; - - len = sizeof(*un_addr); - bzero(un_addr, len); - - if (strlen(peer) >= sizeof(un_addr->sun_path)) { - ErrPrint("peer %s is too long to remember it\\n", peer); - return -1; - } - - /* We can believe this has no prob, because - * we already check the size of add.rsun_path - */ - strcpy(un_addr->sun_path, peer); - un_addr->sun_family = AF_UNIX; - - handle = socket(PF_UNIX, SOCK_STREAM, 0); - if (handle < 0) { - handle = -errno; - ErrPrint("Failed to create a socket %s\n", strerror(errno)); - } - - return handle; + int len; + int handle; + struct sockaddr_un *un_addr = (struct sockaddr_un *)addr; + + len = sizeof(*un_addr); + bzero(un_addr, len); + + if (strlen(peer) >= sizeof(un_addr->sun_path)) { + ErrPrint("peer %s is too long to remember it\\n", peer); + return -1; + } + + /* We can believe this has no prob, because + * we already check the size of add.rsun_path + */ + strcpy(un_addr->sun_path, peer); + un_addr->sun_family = AF_UNIX; + + handle = socket(PF_UNIX, SOCK_STREAM, 0); + if (handle < 0) { + handle = -errno; + ErrPrint("Failed to create a socket %s\n", strerror(errno)); + } + + return handle; } static inline int create_inet_socket(const char *peer, int port, struct sockaddr *addr) { - int handle; - struct sockaddr_in *in_addr = (struct sockaddr_in *)addr; - - bzero(in_addr, sizeof(*in_addr)); - - in_addr->sin_port = htons(port); - in_addr->sin_family = AF_INET; - if (*peer == '\0') { - in_addr->sin_addr.s_addr = htonl(INADDR_ANY); - } else { - in_addr->sin_addr.s_addr = inet_addr(peer); - } - - handle = socket(AF_INET, SOCK_STREAM, 0); - if (handle < 0) { - handle = -errno; - ErrPrint("socket: %s\n", strerror(errno)); - } - - return handle; + int handle; + struct sockaddr_in *in_addr = (struct sockaddr_in *)addr; + + bzero(in_addr, sizeof(*in_addr)); + + in_addr->sin_port = htons(port); + in_addr->sin_family = AF_INET; + if (*peer == '\0') { + in_addr->sin_addr.s_addr = htonl(INADDR_ANY); + } else { + in_addr->sin_addr.s_addr = inet_addr(peer); + } + + handle = socket(AF_INET, SOCK_STREAM, 0); + if (handle < 0) { + handle = -errno; + ErrPrint("socket: %s\n", strerror(errno)); + } + + return handle; } static inline int create_systemd_socket(const char *peer, int port, struct sockaddr *addr) { - int handle = -1; - int cnt; - - cnt = sd_listen_fds(0); - if (cnt > 1) { - ErrPrint("To many file descriptors are received on socket activation: %d\n", cnt); - } else if (cnt == 1) { - handle = SD_LISTEN_FDS_START + 0; - } else { - handle = create_inet_socket(peer, port, addr); - } - - return handle; + int handle = -1; + int cnt; + + cnt = sd_listen_fds(0); + if (cnt > 1) { + ErrPrint("To many file descriptors are received on socket activation: %d\n", cnt); + } else if (cnt == 1) { + handle = SD_LISTEN_FDS_START + 0; + } else { + handle = create_inet_socket(peer, port, addr); + } + + return handle; } static inline int setup_unix_handle(int handle) { - int on = 1; - int sndbuf = SNDBUF_SZ; - int rcvbuf = RCVBUF_SZ; - - if (setsockopt(handle, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) { - int ret; - ret = -errno; - ErrPrint("Failed to change sock opt : %s\n", strerror(errno)); - return ret; - } + int on = 1; + int sndbuf = SNDBUF_SZ; + int rcvbuf = RCVBUF_SZ; - (void)setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)); - (void)setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)); - (void)setsockopt(handle, IPPROTO_IP, TCP_NODELAY, &on, sizeof(on)); + if (setsockopt(handle, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) { + int ret; + ret = -errno; + ErrPrint("Failed to change sock opt : %s\n", strerror(errno)); + return ret; + } - return 0; + (void)setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)); + (void)setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)); + (void)setsockopt(handle, IPPROTO_IP, TCP_NODELAY, &on, sizeof(on)); + + return 0; } static inline int setup_inet_handle(int handle) { - int on = 1; + int on = 1; - (void)setsockopt(handle, IPPROTO_IP, TCP_NODELAY, &on, sizeof(on)); + (void)setsockopt(handle, IPPROTO_IP, TCP_NODELAY, &on, sizeof(on)); - return 0; + return 0; } static inline char *parse_scheme(const char *peer, int *port, struct function_table *vtable) { - int _port; - char *addr = NULL; - - if (!port) - port = &_port; - - *port = 0; - - if (!strncasecmp(peer, COM_CORE_LOCAL_SCHEME, COM_CORE_LOCAL_SCHEME_LEN)) { - vtable->type = (int)SCHEME_LOCAL; - peer += COM_CORE_LOCAL_SCHEME_LEN; - - addr = strdup(peer); - if (!addr) { - ErrPrint("Heap: %s\n", strerror(errno)); - } - - vtable->create_socket = create_unix_socket; - vtable->setup_handle = setup_unix_handle; - } else if (!strncasecmp(peer, COM_CORE_SD_LOCAL_SCHEME, COM_CORE_SD_LOCAL_SCHEME_LEN)) { - vtable->type = (int)SCHEME_LOCAL; - peer += COM_CORE_SD_LOCAL_SCHEME_LEN; - - addr = strdup(peer); - if (!addr) { - ErrPrint("Heap: %s\n", strerror(errno)); - } - - vtable->create_socket = create_systemd_socket; - vtable->setup_handle = setup_unix_handle; - } else if (!strncasecmp(peer, COM_CORE_REMOTE_SCHEME, COM_CORE_REMOTE_SCHEME_LEN)) { - register int len; - char *endptr; - - vtable->type = (int)SCHEME_REMOTE; - peer += COM_CORE_REMOTE_SCHEME_LEN; - - for (len = 0; peer[len] && peer[len] != ':'; len++); - if (peer[len] != ':') { - ErrPrint("Invalid syntax: %s\n", peer); - goto out; - } - - addr = malloc(len + 1); - if (!addr) { - ErrPrint("Heap: %s\n", strerror(errno)); - goto out; - } - - if (len > 0) { - strncpy(addr, peer, len); - } - - addr[len] = '\0'; - - peer += len + 1; - *port = strtoul(peer, &endptr, 10); - if (*endptr != '\0' || peer == endptr) { - ErrPrint("Invalid: %s[%d]\n", peer - len - 1, len + 1); - free(addr); - addr = NULL; - goto out; - } - - vtable->create_socket = create_inet_socket; - vtable->setup_handle = setup_inet_handle; - } else { - /* Fallback to local scheme */ - vtable->type = (int)SCHEME_LOCAL; - addr = strdup(peer); - if (!addr) { - ErrPrint("Heap: %s\n", strerror(errno)); - goto out; - } - - vtable->create_socket = create_unix_socket; - vtable->setup_handle = setup_unix_handle; - } + int _port; + char *addr = NULL; -out: - return addr; -} + if (!port) + port = &_port; -EAPI int secure_socket_create_client(const char *peer) -{ - int port; - char *addr; - int ret; - struct function_table vtable; - struct sockaddr *sockaddr; - struct sockaddr_in in_addr; - struct sockaddr_un un_addr; - int handle; - int addrlen; - - addr = parse_scheme(peer, &port, &vtable); + *port = 0; + + if (!strncasecmp(peer, COM_CORE_LOCAL_SCHEME, COM_CORE_LOCAL_SCHEME_LEN)) { + vtable->type = (int)SCHEME_LOCAL; + peer += COM_CORE_LOCAL_SCHEME_LEN; + + addr = strdup(peer); if (!addr) { - ErrPrint("peer: [%s] is not valid\n", peer); - return -EINVAL; + ErrPrint("Heap: %s\n", strerror(errno)); } - switch (vtable.type) { - case SCHEME_LOCAL: - sockaddr = (struct sockaddr *)&un_addr; - addrlen = sizeof(un_addr); - break; - case SCHEME_REMOTE: - sockaddr = (struct sockaddr *)&in_addr; - addrlen = sizeof(in_addr); - break; - default: - free(addr); - return -EINVAL; - } + vtable->create_socket = create_unix_socket; + vtable->setup_handle = setup_unix_handle; + } else if (!strncasecmp(peer, COM_CORE_SD_LOCAL_SCHEME, COM_CORE_SD_LOCAL_SCHEME_LEN)) { + vtable->type = (int)SCHEME_LOCAL; + peer += COM_CORE_SD_LOCAL_SCHEME_LEN; - handle = vtable.create_socket(addr, port, sockaddr); - free(addr); - if (handle < 0) { - return handle; + addr = strdup(peer); + if (!addr) { + ErrPrint("Heap: %s\n", strerror(errno)); } - ret = connect(handle, sockaddr, addrlen); - if (ret < 0) { - ret = -errno; - ErrPrint("Failed to connect to server [%s] %s\n", - peer, strerror(errno)); - if (close(handle) < 0) { - ErrPrint("close: %s\n", strerror(errno)); - } - - return ret; + vtable->create_socket = create_systemd_socket; + vtable->setup_handle = setup_unix_handle; + } else if (!strncasecmp(peer, COM_CORE_REMOTE_SCHEME, COM_CORE_REMOTE_SCHEME_LEN)) { + register int len; + char *endptr; + + vtable->type = (int)SCHEME_REMOTE; + peer += COM_CORE_REMOTE_SCHEME_LEN; + + for (len = 0; peer[len] && peer[len] != ':'; len++); + if (peer[len] != ':') { + ErrPrint("Invalid syntax: %s\n", peer); + goto out; } - ret = vtable.setup_handle(handle); - if (ret < 0) { - if (close(handle) < 0) { - ErrPrint("close: %s\n", strerror(errno)); - } + addr = malloc(len + 1); + if (!addr) { + ErrPrint("Heap: %s\n", strerror(errno)); + goto out; + } - return ret; + if (len > 0) { + strncpy(addr, peer, len); } - return handle; -} + addr[len] = '\0'; -EAPI int secure_socket_create_server(const char *peer) -{ - int port; - char *addr; - int handle; - int ret; - struct sockaddr *sockaddr; - struct sockaddr_in in_addr; - struct sockaddr_un un_addr; - struct function_table vtable; - int addrlen; + peer += len + 1; + *port = strtoul(peer, &endptr, 10); + if (*endptr != '\0' || peer == endptr) { + ErrPrint("Invalid: %s[%d]\n", peer - len - 1, len + 1); + free(addr); + addr = NULL; + goto out; + } - addr = parse_scheme(peer, &port, &vtable); + vtable->create_socket = create_inet_socket; + vtable->setup_handle = setup_inet_handle; + } else { + /* Fallback to local scheme */ + vtable->type = (int)SCHEME_LOCAL; + addr = strdup(peer); if (!addr) { - ErrPrint("Failed to parse scheme\n"); - return -EINVAL; + ErrPrint("Heap: %s\n", strerror(errno)); + goto out; } - switch (vtable.type) { + vtable->create_socket = create_unix_socket; + vtable->setup_handle = setup_unix_handle; + } + +out: + return addr; +} + +EAPI int secure_socket_create_client(const char *peer) +{ + int port; + char *addr; + int ret; + struct function_table vtable; + struct sockaddr *sockaddr; + struct sockaddr_in in_addr; + struct sockaddr_un un_addr; + int handle; + int addrlen; + + addr = parse_scheme(peer, &port, &vtable); + if (!addr) { + ErrPrint("peer: [%s] is not valid\n", peer); + return -EINVAL; + } + + switch (vtable.type) { case SCHEME_LOCAL: - sockaddr = (struct sockaddr *)&un_addr; - addrlen = sizeof(un_addr); - break; + sockaddr = (struct sockaddr *)&un_addr; + addrlen = sizeof(un_addr); + break; case SCHEME_REMOTE: - sockaddr = (struct sockaddr *)&in_addr; - addrlen = sizeof(in_addr); - break; + sockaddr = (struct sockaddr *)&in_addr; + addrlen = sizeof(in_addr); + break; default: - free(addr); - return -EINVAL; - } + free(addr); + return -EINVAL; + } - handle = vtable.create_socket(addr, port, sockaddr); - free(addr); - if (handle < 0) { - return handle; - } + handle = vtable.create_socket(addr, port, sockaddr); + free(addr); + if (handle < 0) { + return handle; + } - ret = bind(handle, sockaddr, addrlen); - if (ret < 0) { - ret = -errno; - ErrPrint("bind: %s\n", strerror(errno)); - if (close(handle) < 0) { - ErrPrint("close: %s\n", strerror(errno)); - } - return ret; + ret = connect(handle, sockaddr, addrlen); + if (ret < 0) { + ret = -errno; + ErrPrint("Failed to connect to server [%s] %s\n", + peer, strerror(errno)); + if (close(handle) < 0) { + ErrPrint("close: %s\n", strerror(errno)); } - ret = listen(handle, BACKLOG); - if (ret < 0) { - ret = -errno; - ErrPrint("listen: %s\n", strerror(errno)); - if (close(handle) < 0) { - ErrPrint("close: %s\n", strerror(errno)); - } - return ret; - } + return ret; + } - if (vtable.type == SCHEME_LOCAL) { - if (chmod(peer, 0666) < 0) { - ErrPrint("Failed to change the permission of a socket (%s)\n", strerror(errno)); - } + ret = vtable.setup_handle(handle); + if (ret < 0) { + if (close(handle) < 0) { + ErrPrint("close: %s\n", strerror(errno)); } - return handle; + return ret; + } + + return handle; } -EAPI int secure_socket_get_connection_handle(int server_handle) +EAPI int secure_socket_create_server(const char *peer) { - struct sockaddr_in in_addr; - struct sockaddr_un un_addr; - struct sockaddr *addr; - int handle; - int ret; - socklen_t size = sizeof(un_addr); - - /* Finding the largest buffer */ - if (sizeof(in_addr) > sizeof(un_addr)) { - addr = (struct sockaddr *)&in_addr; - size = sizeof(in_addr); - } else { - addr = (struct sockaddr *)&un_addr; - size = sizeof(un_addr); + int port; + char *addr; + int handle; + int ret; + struct sockaddr *sockaddr; + struct sockaddr_in in_addr; + struct sockaddr_un un_addr; + struct function_table vtable; + int addrlen; + + addr = parse_scheme(peer, &port, &vtable); + if (!addr) { + ErrPrint("Failed to parse scheme\n"); + return -EINVAL; + } + + switch (vtable.type) { + case SCHEME_LOCAL: + sockaddr = (struct sockaddr *)&un_addr; + addrlen = sizeof(un_addr); + break; + case SCHEME_REMOTE: + sockaddr = (struct sockaddr *)&in_addr; + addrlen = sizeof(in_addr); + break; + default: + free(addr); + return -EINVAL; + } + + handle = vtable.create_socket(addr, port, sockaddr); + free(addr); + if (handle < 0) { + return handle; + } + + ret = bind(handle, sockaddr, addrlen); + if (ret < 0) { + ret = -errno; + ErrPrint("bind: %s\n", strerror(errno)); + if (close(handle) < 0) { + ErrPrint("close: %s\n", strerror(errno)); } + return ret; + } - handle = accept(server_handle, addr, &size); - if (handle < 0) { - ret = -errno; - ErrPrint("Failed to accept a new client %s\n", strerror(errno)); - return ret; + ret = listen(handle, BACKLOG); + if (ret < 0) { + ret = -errno; + ErrPrint("listen: %s\n", strerror(errno)); + if (close(handle) < 0) { + ErrPrint("close: %s\n", strerror(errno)); } + return ret; + } - if (addr->sa_family == AF_UNIX) { - ret = setup_unix_handle(handle); - if (ret < 0) { - if (close(handle) < 0) { - ErrPrint("close: %s\n", strerror(errno)); - } - - handle = ret; - } - } else if (addr->sa_family == AF_INET) { - ret = setup_inet_handle(handle); - if (ret < 0) { - if (close(handle) < 0) { - ErrPrint("close: %s\n", strerror(errno)); - } - - handle = ret; - } - } else { - ErrPrint("Unknown address family: %d\n", addr->sa_family); + if (vtable.type == SCHEME_LOCAL) { + if (chmod(peer, 0666) < 0) { + ErrPrint("Failed to change the permission of a socket (%s)\n", strerror(errno)); } + } - return handle; + return handle; } -EAPI int secure_socket_send(int handle, const char *buffer, int size) +EAPI int secure_socket_get_connection_handle(int server_handle) { - struct msghdr msg; - struct iovec iov; - int ret; + struct sockaddr_in in_addr; + struct sockaddr_un un_addr; + struct sockaddr *addr; + int handle; + int ret; + socklen_t size = sizeof(un_addr); + + /* Finding the largest buffer */ + if (sizeof(in_addr) > sizeof(un_addr)) { + addr = (struct sockaddr *)&in_addr; + size = sizeof(in_addr); + } else { + addr = (struct sockaddr *)&un_addr; + size = sizeof(un_addr); + } + + handle = accept(server_handle, addr, &size); + if (handle < 0) { + ret = -errno; + ErrPrint("Failed to accept a new client %s\n", strerror(errno)); + return ret; + } + + if (addr->sa_family == AF_UNIX) { + ret = setup_unix_handle(handle); + if (ret < 0) { + if (close(handle) < 0) { + ErrPrint("close: %s\n", strerror(errno)); + } - if (!buffer || size <= 0) { - ErrPrint("Reject: 0 byte data sending\n"); - return -EINVAL; + handle = ret; } - - memset(&msg, 0, sizeof(msg)); - iov.iov_base = (char *)buffer; - iov.iov_len = size; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - ret = sendmsg(handle, &msg, 0); + } else if (addr->sa_family == AF_INET) { + ret = setup_inet_handle(handle); if (ret < 0) { - ret = -errno; - if (errno == EAGAIN || errno == EWOULDBLOCK) { - ErrPrint("handle[%d] size[%d] Try again [%s]\n", handle, size, strerror(errno)); - return -EAGAIN; - } - ErrPrint("Failed to send message [%s]\n", strerror(errno)); - return ret; + if (close(handle) < 0) { + ErrPrint("close: %s\n", strerror(errno)); + } + + handle = ret; } + } else { + ErrPrint("Unknown address family: %d\n", addr->sa_family); + } - return iov.iov_len; + return handle; } -EAPI int secure_socket_recv(int handle, char *buffer, int size, int *sender_pid) +EAPI int secure_socket_send(int handle, const char *buffer, int size, int fd) { - struct msghdr msg; + struct msghdr msg; + struct iovec iov; + union { + struct cmsghdr hdr; + char control[CMSG_SPACE(sizeof(int))]; + } cmsgu; + int ret; + + if (!buffer || size <= 0) { + ErrPrint("Reject: 0 byte data sending\n"); + return -EINVAL; + } + + memset(&msg, 0, sizeof(msg)); + iov.iov_base = (char *)buffer; + iov.iov_len = size; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + if (fd >= 0) { struct cmsghdr *cmsg; - struct iovec iov; - char control[1024]; - int _pid; - int ret; - - if (size <= 0 || !buffer) { - return -EINVAL; - } + int *cdata; - if (!sender_pid) { - sender_pid = &_pid; - } + msg.msg_control = cmsgu.control; + msg.msg_controllen = sizeof(cmsgu.control); - memset(&msg, 0, sizeof(msg)); - iov.iov_base = buffer; - iov.iov_len = size; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = control; - msg.msg_controllen = sizeof(control); - - ret = recvmsg(handle, &msg, 0); - if (ret == 0) { - /*!< Disconnected */ - DbgPrint("Disconnected\n"); - return 0; + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cdata = (int *)CMSG_DATA(cmsg); + *cdata = fd; + } + + ret = sendmsg(handle, &msg, 0); + if (ret < 0) { + ret = -errno; + if (errno == EAGAIN || errno == EWOULDBLOCK) { + ErrPrint("handle[%d] size[%d] Try again [%s]\n", handle, size, strerror(errno)); + return -EAGAIN; } + ErrPrint("Failed to send message [%s]\n", strerror(errno)); + return ret; + } - if (ret < 0) { - ret = -errno; - if (errno == EAGAIN || errno == EWOULDBLOCK) { - ErrPrint("handle[%d] size[%d] Try again [%s]\n", handle, size, strerror(errno)); - return -EAGAIN; - } - - ErrPrint("Failed to recvmsg [%s]\n", strerror(errno)); - return ret; - } + return iov.iov_len; +} - *sender_pid = -1; /* In case of remote socket, cannot delivery this */ - cmsg = CMSG_FIRSTHDR(&msg); - while (cmsg) { - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { - struct ucred *cred; +EAPI int secure_socket_recv(int handle, char *buffer, int size, int *sender_pid, int *fd) +{ + struct msghdr msg; + struct cmsghdr *cmsg; + struct iovec iov; + char control[1024]; + int _pid; + int ret; + + if (size <= 0 || !buffer) { + return -EINVAL; + } + + if (!sender_pid) { + sender_pid = &_pid; + } + + memset(&msg, 0, sizeof(msg)); + iov.iov_base = buffer; + iov.iov_len = size; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + + ret = recvmsg(handle, &msg, 0); + if (ret == 0) { + /*!< Disconnected */ + DbgPrint("Disconnected\n"); + return 0; + } - cred = (struct ucred *)CMSG_DATA(cmsg); - *sender_pid = cred->pid; - } + if (ret < 0) { + ret = -errno; + if (errno == EAGAIN || errno == EWOULDBLOCK) { + ErrPrint("handle[%d] size[%d] Try again [%s]\n", handle, size, strerror(errno)); + return -EAGAIN; + } - cmsg = CMSG_NXTHDR(&msg, cmsg); + ErrPrint("Failed to recvmsg [%s]\n", strerror(errno)); + return ret; + } + + *sender_pid = -1; /* In case of remote socket, cannot delivery this */ + cmsg = CMSG_FIRSTHDR(&msg); + while (cmsg) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { + struct ucred *cred; + + cred = (struct ucred *)CMSG_DATA(cmsg); + *sender_pid = cred->pid; + } else if (fd && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int *cdata; + cdata = (int *)CMSG_DATA(cmsg); + *fd = *cdata; } - return iov.iov_len; + cmsg = CMSG_NXTHDR(&msg, cmsg); + } + + return iov.iov_len; } EAPI int secure_socket_destroy_handle(int handle) { - if (close(handle) < 0) { - int ret; - ret = -errno; - ErrPrint("close: %s\n", strerror(errno)); - return ret; - } + if (close(handle) < 0) { + int ret; + ret = -errno; + ErrPrint("close: %s\n", strerror(errno)); + return ret; + } - return 0; + return 0; } #undef _GNU_SOURCE |