diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/com-core.c | 163 | ||||
-rw-r--r-- | src/com-core_thread.c | 17 |
2 files changed, 155 insertions, 25 deletions
diff --git a/src/com-core.c b/src/com-core.c index d254014..f1973f7 100644 --- a/src/com-core.c +++ b/src/com-core.c @@ -37,6 +37,7 @@ #include "util.h" static struct { + struct dlist *watch_list; struct dlist *conn_cb_list; struct dlist *disconn_cb_list; enum processing_event_callback { @@ -45,11 +46,19 @@ static struct { PROCESSING_CONNECTION = 0x02, } processing_event_callback; } s_info = { + .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; +}; + struct cbdata { int (*service_cb)(int fd, void *data); void *data; @@ -61,12 +70,93 @@ struct evtdata { void *data; }; -HAPI void invoke_con_cb_list(int handle) +static int watch_item_create(int server_fd, int handle, guint id, void *cbdata) +{ + struct watch_item *item; + + item = malloc(sizeof(*item)); + if (!item) { + return -ENOMEM; + } + + 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; +} + +static int watch_item_destroy(int handle, int remove_id, int remove_cbdata) +{ + 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); + + 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_cbdata && item->cbdata) { + free(item->cbdata); + } + + free(item); + return 0; + } + } + + 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); + } + } +} + +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) { /*! @@ -82,7 +172,7 @@ HAPI void invoke_con_cb_list(int handle) s_info.processing_event_callback &= ~PROCESSING_CONNECTION; } -HAPI void invoke_disconn_cb_list(int handle) +HAPI void invoke_disconn_cb_list(int handle, int remove_id, int remove_data, int watch) { struct dlist *l; struct dlist *n; @@ -101,6 +191,12 @@ HAPI void invoke_disconn_cb_list(int handle) } } 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) @@ -127,14 +223,14 @@ static gboolean client_cb(GIOChannel *src, GIOCondition cond, gpointer data) if (!(cond & G_IO_IN)) { DbgPrint("Client is disconencted\n"); - invoke_disconn_cb_list(client_fd); + 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); + invoke_disconn_cb_list(client_fd, 0, 1, 1); secure_socket_destroy_handle(client_fd); return FALSE; } @@ -142,13 +238,19 @@ static gboolean client_cb(GIOChannel *src, GIOCondition cond, gpointer data) 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); + 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 */ - return validate_handle(client_fd) ? TRUE : FALSE; + 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) @@ -161,6 +263,7 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata) 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; @@ -168,6 +271,7 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata) 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; @@ -175,8 +279,8 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata) client_fd = secure_socket_get_connection_handle(socket_fd); if (client_fd < 0) { - free(cbdata); - return FALSE; + /* Keep server running */ + return TRUE; } DbgPrint("New connectino arrived: server(%d), client(%d)\n", socket_fd, client_fd); @@ -192,8 +296,8 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata) if (!gio) { ErrPrint("Failed to get gio\n"); secure_socket_destroy_handle(client_fd); - free(cbdata); - return FALSE; + /* Keep server running */ + return TRUE; } g_io_channel_set_close_on_unref(gio, FALSE); @@ -201,6 +305,7 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata) 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) { @@ -209,14 +314,21 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata) } g_io_channel_unref(gio); secure_socket_destroy_handle(client_fd); - free(cbdata); - return FALSE; + /* Keep server running */ + return TRUE; } g_io_channel_unref(gio); - invoke_con_cb_list(client_fd); - return validate_handle(socket_fd) ? TRUE : FALSE; + invoke_con_cb_list(socket_fd, client_fd, id, NULL, 1); + + if (!validate_handle(socket_fd)) { + watch_item_destroy_all(socket_fd); + return FALSE; + } + + /* 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) @@ -275,6 +387,23 @@ EAPI int com_core_server_create(const char *addr, int is_sync, int (*service_cb) return -EIO; } + if (watch_item_create(fd, fd, id, cbdata) < 0) { + GError *err = NULL; + + 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; + } + g_io_channel_unref(gio); return fd; } @@ -336,7 +465,7 @@ EAPI int com_core_client_create(const char *addr, int is_sync, int (*service_cb) g_io_channel_unref(gio); - invoke_con_cb_list(client_fd); + invoke_con_cb_list(client_fd, client_fd, id, cbdata, 1); return client_fd; } @@ -534,7 +663,7 @@ EAPI void *com_core_del_event_callback(enum com_core_event_type type, int (*cb)( EAPI int com_core_server_destroy(int handle) { DbgPrint("Close server handle[%d]\n", handle); - invoke_disconn_cb_list(handle); + invoke_disconn_cb_list(handle, 1, 1, 1); secure_socket_destroy_handle(handle); return 0; } @@ -542,7 +671,7 @@ EAPI int com_core_server_destroy(int handle) EAPI int com_core_client_destroy(int handle) { DbgPrint("Close client handle[%d]\n", handle); - invoke_disconn_cb_list(handle); + invoke_disconn_cb_list(handle, 1, 1, 1); secure_socket_destroy_handle(handle); return 0; } diff --git a/src/com-core_thread.c b/src/com-core_thread.c index eaa88b5..2a8fc5a 100644 --- a/src/com-core_thread.c +++ b/src/com-core_thread.c @@ -499,7 +499,7 @@ static gboolean evt_pipe_cb(GIOChannel *src, GIOCondition cond, gpointer data) errout: DbgPrint("Disconnecting\n"); - invoke_disconn_cb_list(tcb->handle); + invoke_disconn_cb_list(tcb->handle, 0, 0, 0); terminate_thread(tcb); tcb_destroy(tcb); return FALSE; @@ -624,6 +624,7 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer data) } 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; @@ -641,12 +642,12 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer data) } g_io_channel_unref(gio); - invoke_con_cb_list(tcb->handle); + 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); + invoke_disconn_cb_list(tcb->handle, 0, 0, 0); secure_socket_destroy_handle(tcb->handle); tcb_destroy(tcb); server_destroy(server); @@ -717,12 +718,12 @@ EAPI int com_core_thread_client_create(const char *addr, int is_sync, int (*serv g_io_channel_unref(gio); - invoke_con_cb_list(tcb->handle); + 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); + invoke_disconn_cb_list(tcb->handle, 0, 0, 0); secure_socket_destroy_handle(tcb->handle); tcb_destroy(tcb); return -EFAULT; @@ -972,7 +973,7 @@ EAPI int com_core_thread_server_destroy(int handle) continue; } - invoke_disconn_cb_list(handle); + invoke_disconn_cb_list(handle, 0, 0, 0); terminate_thread(tcb); tcb_destroy(tcb); return 0; @@ -983,7 +984,7 @@ EAPI int com_core_thread_server_destroy(int handle) continue; } - invoke_disconn_cb_list(handle); + invoke_disconn_cb_list(handle, 0, 0, 0); server_destroy(server); return 0; } @@ -1004,7 +1005,7 @@ EAPI int com_core_thread_client_destroy(int handle) return -ENOENT; } - invoke_disconn_cb_list(handle); + invoke_disconn_cb_list(handle, 0, 0, 0); terminate_thread(tcb); tcb_destroy(tcb); return 0; |