diff --git a/include/qb/qbipcs.h b/include/qb/qbipcs.h index b1dc6d9..f8df928 100644 --- a/include/qb/qbipcs.h +++ b/include/qb/qbipcs.h @@ -33,7 +33,9 @@ extern "C" { #endif /* *INDENT-ON* */ -typedef qb_handle_t qb_ipcs_connection_handle_t; +struct qb_ipcs_connection; +typedef struct qb_ipcs_connection qb_ipcs_connection_t; + typedef qb_handle_t qb_ipcs_service_pt; typedef int32_t (*qb_ipcs_dispatch_fn_t) (qb_ipcs_service_pt s, int32_t fd, int32_t revents, @@ -56,21 +58,21 @@ struct qb_ipcs_poll_handlers { * or process resource constraints. * @return 0 to accept or -errno to indicate a failure (sent back to the client) */ -typedef int32_t (*qb_ipcs_connection_accept_fn) (qb_ipcs_connection_handle_t c, uid_t uid, gid_t gid); +typedef int32_t (*qb_ipcs_connection_accept_fn) (qb_ipcs_connection_t *c, uid_t uid, gid_t gid); /** * This is called after a new connection has been created. */ -typedef void (*qb_ipcs_connection_created_fn) (qb_ipcs_connection_handle_t c); +typedef void (*qb_ipcs_connection_created_fn) (qb_ipcs_connection_t *c); /** * This is called after a connection has been destroyed. */ -typedef void (*qb_ipcs_connection_destroyed_fn) (qb_ipcs_connection_handle_t c); +typedef void (*qb_ipcs_connection_destroyed_fn) (qb_ipcs_connection_t *c); /** * This is the message processing calback. * It is called with the message data. */ -typedef void (*qb_ipcs_msg_process_fn) (qb_ipcs_connection_handle_t c, +typedef void (*qb_ipcs_msg_process_fn) (qb_ipcs_connection_t *c, void *data, size_t size); struct qb_ipcs_service_handlers { @@ -108,12 +110,24 @@ void qb_ipcs_destroy(qb_ipcs_service_pt s); /** * send a response to a incomming request. */ -ssize_t qb_ipcs_response_send(qb_ipcs_connection_handle_t c, void *data, size_t size); +ssize_t qb_ipcs_response_send(qb_ipcs_connection_t *c, void *data, size_t size); /** * Send an asyncronous event message to the client. */ -ssize_t qb_ipcs_event_send(qb_ipcs_connection_handle_t c, void *data, size_t size); +ssize_t qb_ipcs_event_send(qb_ipcs_connection_t *c, void *data, size_t size); + + +/** + * Increment the connection's reference counter. + */ +void qb_ipcs_connection_ref_inc(qb_ipcs_connection_t *c); + +/** + * Decrement the connection's reference counter. + */ +void qb_ipcs_connection_ref_dec(qb_ipcs_connection_t *c); + /* *INDENT-OFF* */ #ifdef __cplusplus diff --git a/lib/ipc_int.h b/lib/ipc_int.h index 131232a..d03bcac 100644 --- a/lib/ipc_int.h +++ b/lib/ipc_int.h @@ -157,7 +157,7 @@ struct qb_ipcs_service { }; struct qb_ipcs_connection { - qb_ipcs_connection_handle_t handle; + int32_t refcount; pid_t pid; uid_t euid; gid_t egid; diff --git a/lib/ipc_us.c b/lib/ipc_us.c index 49781b7..184eaa0 100644 --- a/lib/ipc_us.c +++ b/lib/ipc_us.c @@ -265,7 +265,7 @@ cleanup_and_return: if (res == 0) { if (c->service->serv_fns.connection_accept) { - res = c->service->serv_fns.connection_accept(c->handle, + res = c->service->serv_fns.connection_accept(c, c->euid, c->egid); } else { @@ -578,7 +578,7 @@ send_response: if (res == 0) { if (s->serv_fns.connection_created) { - s->serv_fns.connection_created(c->handle); + s->serv_fns.connection_created(c); } } else if (res == -EACCES) { qb_util_log(LOG_ERR, "Invalid IPC credentials."); diff --git a/lib/ipcs.c b/lib/ipcs.c index 65997a7..909318f 100644 --- a/lib/ipcs.c +++ b/lib/ipcs.c @@ -25,10 +25,8 @@ #include static void qb_ipcs_destroy_internal(void *data); -static void qb_ipcs_disconnect_internal(void *data); QB_HDB_DECLARE(qb_ipc_services, qb_ipcs_destroy_internal); -QB_HDB_DECLARE(qb_ipc_connections, qb_ipcs_disconnect_internal); qb_ipcs_service_pt qb_ipcs_create(const char *name, enum qb_ipc_type type) { @@ -132,53 +130,40 @@ static void qb_ipcs_destroy_internal(void *data) s->funcs.destroy(s); } -ssize_t qb_ipcs_response_send(qb_ipcs_connection_handle_t c, void *data, +ssize_t qb_ipcs_response_send(struct qb_ipcs_connection *c, void *data, size_t size) { ssize_t res; - struct qb_ipcs_connection *con; - res = qb_hdb_handle_get(&qb_ipc_connections, c, (void **)&con); - if (res < 0) { - return res; - } - res = con->service->funcs.response_send(con, data, size); - qb_hdb_handle_put(&qb_ipc_connections, c); + qb_ipcs_connection_ref_inc(c); + res = c->service->funcs.response_send(c, data, size); + qb_ipcs_connection_ref_dec(c); return res; } -ssize_t qb_ipcs_event_send(qb_ipcs_connection_handle_t c, void *data, +ssize_t qb_ipcs_event_send(struct qb_ipcs_connection *c, void *data, size_t size) { ssize_t res; - struct qb_ipcs_connection *con; - res = qb_hdb_handle_get(&qb_ipc_connections, c, (void **)&con); - if (res < 0) { - return res; - } - res = con->service->funcs.event_send(con, data, size); + qb_ipcs_connection_ref_inc(c); + res = c->service->funcs.event_send(c, data, size); - if (con->service->needs_sock_for_poll) { - qb_ipc_us_send(con->sock, data, 1); + if (c->service->needs_sock_for_poll) { + qb_ipc_us_send(c->sock, data, 1); } - qb_hdb_handle_put(&qb_ipc_connections, c); + qb_ipcs_connection_ref_dec(c); return res; } struct qb_ipcs_connection *qb_ipcs_connection_alloc(struct qb_ipcs_service *s) { - qb_ipcs_connection_handle_t h; - struct qb_ipcs_connection *c; + struct qb_ipcs_connection *c = malloc(sizeof(struct qb_ipcs_connection)); - qb_hdb_handle_create(&qb_ipc_connections, - sizeof(struct qb_ipcs_connection), &h); - qb_hdb_handle_get(&qb_ipc_connections, h, (void **)&c); - - c->handle = h; + c->refcount = 1; c->service = s; c->pid = 0; c->euid = -1; @@ -190,29 +175,39 @@ struct qb_ipcs_connection *qb_ipcs_connection_alloc(struct qb_ipcs_service *s) return c; } -static void qb_ipcs_disconnect_internal(void *data) +void qb_ipcs_connection_ref_inc(struct qb_ipcs_connection *c) { - struct qb_ipcs_connection *c = (struct qb_ipcs_connection *)data; + // lock + c->refcount++; + qb_util_log(LOG_DEBUG, "%s() %d", __func__, c->refcount); + // unlock +} - qb_util_log(LOG_DEBUG, "%s()", __func__); - qb_list_del(&c->list); - if (c->service->serv_fns.connection_destroyed) { - c->service->serv_fns.connection_destroyed(c->handle); - } - c->service->funcs.disconnect(c); - qb_ipcc_us_disconnect(c->sock); - if (c->receive_buf) { - free(c->receive_buf); +void qb_ipcs_connection_ref_dec(struct qb_ipcs_connection *c) +{ + // lock + c->refcount--; + qb_util_log(LOG_DEBUG, "%s() %d", __func__, c->refcount); + if (c->refcount == 0) { + qb_list_del(&c->list); + // unlock + if (c->service->serv_fns.connection_destroyed) { + c->service->serv_fns.connection_destroyed(c); + } + c->service->funcs.disconnect(c); + qb_ipcc_us_disconnect(c->sock); + if (c->receive_buf) { + free(c->receive_buf); + } + } else { + // unlock } } void qb_ipcs_disconnect(struct qb_ipcs_connection *c) { qb_util_log(LOG_DEBUG, "%s()", __func__); - if (qb_hdb_handle_destroy(&qb_ipc_connections, c->handle) != 0) - perror("qb_ipcs_disconnect:destroy"); - if (qb_hdb_handle_put(&qb_ipc_connections, c->handle) != 0) - perror("qb_ipcs_disconnect:put"); + qb_ipcs_connection_ref_dec(c); } static int32_t _process_request_(struct qb_ipcs_connection *c) @@ -222,6 +217,7 @@ static int32_t _process_request_(struct qb_ipcs_connection *c) hdr = (struct qb_ipc_request_header *)c->receive_buf; + qb_ipcs_connection_ref_inc(c); get_msg_with_live_connection: res = c->service->funcs.request_recv(c, hdr, c->max_msg_size); if (res == -EAGAIN) { @@ -240,10 +236,11 @@ get_msg_with_live_connection: case QB_IPC_MSG_NEW_MESSAGE: default: - c->service->serv_fns.msg_process(c->handle, hdr, hdr->size); + c->service->serv_fns.msg_process(c, hdr, hdr->size); break; } cleanup: + qb_ipcs_connection_ref_dec(c); return res; } diff --git a/tests/bms.c b/tests/bms.c index e770990..188532d 100644 --- a/tests/bms.c +++ b/tests/bms.c @@ -52,7 +52,7 @@ int32_t verbose = 0; static qb_handle_t bms_poll_handle; static qb_ipcs_service_pt s1; -static int32_t s1_connection_accept_fn(qb_ipcs_connection_handle_t conn, uid_t uid, gid_t gid) +static int32_t s1_connection_accept_fn(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) { #if 0 if (uid == 0 && gid == 0) { @@ -70,20 +70,20 @@ static int32_t s1_connection_accept_fn(qb_ipcs_connection_handle_t conn, uid_t u } -static void s1_connection_created_fn(qb_ipcs_connection_handle_t conn) +static void s1_connection_created_fn(qb_ipcs_connection_t *c) { if (verbose) { printf("%s:%d %s\n", __FILE__, __LINE__, __func__); } } -static void s1_connection_destroyed_fn(qb_ipcs_connection_handle_t conn) +static void s1_connection_destroyed_fn(qb_ipcs_connection_t *c) { if (verbose) { printf("%s:%d %s\n", __FILE__, __LINE__, __func__); } } -static void s1_msg_process_fn(qb_ipcs_connection_handle_t conn, +static void s1_msg_process_fn(qb_ipcs_connection_t *c, void *data, size_t size) { struct qb_ipc_request_header *req_pt = (struct qb_ipc_request_header *)data; @@ -99,7 +99,7 @@ static void s1_msg_process_fn(qb_ipcs_connection_handle_t conn, response.id = 13; response.error = 0; if (blocking == 1) { - res = qb_ipcs_response_send(conn, &response, + res = qb_ipcs_response_send(c, &response, sizeof(response)); if (res < 0) { perror("qb_ipcs_response_send");