diff --git a/src/communication.c b/src/communication.c index db92cda..d1c9806 100644 --- a/src/communication.c +++ b/src/communication.c @@ -50,8 +50,7 @@ struct ipc_error ipc_ctx_init (struct ipc_ctx **ctx) * for example by managing allocations of thousands of structures at once. * WARNING: Store and remove only pointers on allocated structures. */ -struct ipc_error -ipc_ctx_new_alloc (struct ipc_ctx *ctx) +struct ipc_error ipc_ctx_new_alloc (struct ipc_ctx *ctx) { ctx->size++; @@ -59,8 +58,7 @@ ipc_ctx_new_alloc (struct ipc_ctx *ctx) if (ctx->size == 1 && ctx->cinfos == NULL && ctx->pollfd == NULL) { SECURE_BUFFER_HEAP_ALLOCATION_R (ctx->cinfos, sizeof (struct ipc_connection_info),, IPC_ERROR_ADD__MALLOC); - SECURE_BUFFER_HEAP_ALLOCATION_R (ctx->pollfd, sizeof (struct pollfd),, - IPC_ERROR_ADD__MALLOC_POLLFD); + SECURE_BUFFER_HEAP_ALLOCATION_R (ctx->pollfd, sizeof (struct pollfd),, IPC_ERROR_ADD__MALLOC_POLLFD); } else { ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size); ctx->pollfd = realloc (ctx->pollfd, sizeof (struct pollfd ) * ctx->size); @@ -70,38 +68,39 @@ ipc_ctx_new_alloc (struct ipc_ctx *ctx) T_R ((ctx->pollfd == NULL), IPC_ERROR_ADD__EMPTY_LIST); // Clean the last entry. - memset (ctx->cinfos[ctx-size -1], 0, sizeof (struct ipc_connection_info)); - memset (ctx->pollfd[ctx-size -1], 0, sizeof (struct pollfd)); + memset (&ctx->cinfos[ctx->size -1], 0, sizeof (struct ipc_connection_info)); + memset (&ctx->pollfd[ctx->size -1], 0, sizeof (struct pollfd)); - IPC_RETURN_ERROR; + IPC_RETURN_NO_ERROR; } -struct ipc_error -ipc_server_init (char **env, struct ipc_ctx **ctx, const char *sname) +struct ipc_error ipc_server_init (struct ipc_ctx **ctx, const char *sname) { - T_R ((env == NULL), IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM); T_R ((sname == NULL), IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM); - ipc_ctx_init(ctx); - - // gets the service path - SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); - TEST_IPC_RR (service_path (buf, sname), "cannot get server path"); - - size_t s = strlen (buf); + ipc_ctx_init(ctx); // Allocate the context. + // Declaration and instanciation of the new connection (ipc_connection_info + pollfd). SECURE_DECLARATION (struct ipc_connection_info, srv); srv.type = IPC_CONNECTION_TYPE_SERVER; SECURE_DECLARATION(struct pollfd, pollfd); pollfd.events = POLLIN; + // Get the service path. + SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); + TEST_IPC_RR (service_path (buf, sname), "cannot get server path"); + size_t s = strlen (buf); + if (s > PATH_MAX) + s = PATH_MAX; SECURE_BUFFER_HEAP_ALLOCATION_R (srv.spath, s + 1,, IPC_ERROR_SERVER_INIT__MALLOC); memcpy (srv.spath, buf, s); srv.spath[s] = '\0'; // to be sure + // Socket initialisation for the service. TEST_IPC_RETURN_ON_ERROR (usock_init (&pollfd.fd, srv.spath)); // Add the server to the listened file descriptors. + // ipc_add allocate memory then copy the data of srv and pollfd in ctx. TEST_IPC_RR (ipc_add (*ctx, &srv, &pollfd), "cannot add the server in the context"); IPC_RETURN_NO_ERROR; @@ -166,9 +165,8 @@ struct ipc_error ipc_contact_networkd (int *pfd, const char *sname) } // Create context, contact networkd, connects to the service. -struct ipc_error ipc_connection (char **env, struct ipc_ctx **ctx, const char *sname) +struct ipc_error ipc_connection (struct ipc_ctx **ctx, const char *sname) { - T_R ((env == NULL), IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM); T_R ((ctx == NULL), IPC_ERROR_CONNECTION__NO_CTX); T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME); @@ -195,46 +193,63 @@ struct ipc_error ipc_connection (char **env, struct ipc_ctx **ctx, const char *s IPC_RETURN_NO_ERROR; } -struct ipc_error ipc_server_close (struct ipc_connection_info *srv) +struct ipc_error ipc_close_all (struct ipc_ctx *ctx) { - usock_close (srv->pollfd.fd); - struct ipc_error ret = usock_remove (srv->spath); - if (srv->spath != NULL) { - free (srv->spath); - srv->spath = NULL; + for (size_t i = 0 ; i < ctx->size ; i++) { + TEST_IPC_P (ipc_close (ctx, i), "cannot close a connection in handle_message"); } - return ret; -} - -struct ipc_error ipc_close (struct ipc_connection_info *p) -{ - return usock_close (p->pollfd.fd); -} - -struct ipc_error ipc_accept ( - struct ipc_connection_info *srv - , struct ipc_connection_info *p) -{ - T_R ((srv == NULL), IPC_ERROR_ACCEPT__NO_SERVICE_PARAM); - T_R ((p == NULL), IPC_ERROR_ACCEPT__NO_CLIENT_PARAM); - - TEST_IPC_RR (usock_accept (srv->pollfd.fd, &p->pollfd.fd), "cannot accept IPC connection"); - p->pollfd.events = POLLIN; // Tell to poll(2) to watch for incoming data from this fd. - p->type = IPC_CONNECTION_TYPE_IPC; IPC_RETURN_NO_ERROR; } +struct ipc_error ipc_close (struct ipc_ctx *ctx, uint32_t index) +{ + struct ipc_error ret = usock_close (ctx->pollfd[index].fd); + + if (ctx->cinfos[i]->type == IPC_CONNECTION_TYPE_SERVER) { + struct ipc_error ret = usock_remove (ctx->cinfos[i]->spath); + if (srv->spath != NULL) { + free (srv->spath); + srv->spath = NULL; + } + } + + return ret; +} + +// New connection from a client. +struct ipc_error ipc_accept_add (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index) +{ + T_R ((ctx == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM); + T_R ((index >= ctx->size), IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX); + + // Memory reallocation. + ipc_ctx_new_alloc (ctx); + + int server_fd = ctx->pollfd[index].fd; + int *client_fd = &ctx->pollfd[ctx->size -1].fd; + + TEST_IPC_RR (usock_accept (server_fd, client_fd), "cannot accept IPC connection"); + ctx->pollfd[ctx->size -1].events = POLLIN; // Tell to poll(2) to watch for incoming data from this fd. + ctx->cinfos[ctx->size -1].type = IPC_CONNECTION_TYPE_IPC; + + struct ipc_connection_info *new_client = &ctx->cinfos[ctx->size]; + ctx->size++; + + IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client); + IPC_RETURN_NO_ERROR; +} + // receive then format in an ipc_message structure -struct ipc_error ipc_read (const struct ipc_connection_info *p, struct ipc_message *m) +struct ipc_error ipc_read (const struct ipc_ctx *ctx, uint32_t index, struct ipc_message *m) { T_R ((m == NULL), IPC_ERROR_READ__NO_MESSAGE_PARAM); char *buf = NULL; size_t msize = IPC_MAX_MESSAGE_SIZE; - // on error or closed recipient, the buffer already freed - TEST_IPC_RETURN_ON_ERROR (usock_recv (p->pollfd.fd, &buf, &msize)); + // On error or closed recipient, the buffer already freed. + TEST_IPC_RETURN_ON_ERROR (usock_recv (ctx->pollfd[index].fd, &buf, &msize)); TEST_IPC_RETURN_ON_ERROR_FREE (ipc_message_format_read (m, buf, msize), buf); free (buf); @@ -262,32 +277,130 @@ struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m) IPC_RETURN_NO_ERROR; } -struct ipc_error ipc_write (const struct ipc_connection_info *p, const struct ipc_message *m) +// TODO: high level API, should be buffered, socket may not be usable for now. +struct ipc_error ipc_write (const struct ipc_ctx *ctx, uint32_t index, const struct ipc_message *m) { - return ipc_write_fd (p->pollfd.fd, m); + return ipc_write_fd (ctx->pollfd[index].fd, m); } -// New connection from a client. -struct ipc_error -ipc_accept_add (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t i) +/** + * Allocate memory then add a new connection to the context. + */ +struct ipc_error ipc_add ( struct ipc_ctx *ctx, struct ipc_connection_info *p, struct pollfd *pollfd) { - T_R ((ctx == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM); - T_R ((i >= ctx->size), IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX); + T_R ((ctx == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS); + T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT); // Memory reallocation. ipc_ctx_new_alloc (ctx); - TEST_IPC_RR (usock_accept (ctx->pollfd[i].fd, &ctx->pollfd[ctx->size -1].fd), "cannot accept IPC connection"); - ctx->pollfd[ctx->size -1].events = POLLIN; // Tell to poll(2) to watch for incoming data from this fd. - ctx->cinfos[ctx->size -1].type = IPC_CONNECTION_TYPE_IPC; + memcpy (ctx->cinfos[ctx->size - 1], p , sizeof (struct ipc_connection_info)); + memcpy (ctx->pollfd[ctx->size - 1], pollfd, sizeof (struct pollfd)); - struct ipc_connection_info *new_client = &ctx->cinfos[ctx->size]; - ctx->size++; - - IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client); IPC_RETURN_NO_ERROR; } +struct ipc_error ipc_del ( + struct ipc_ctx *ctx + , struct ipc_connection_info *p) +{ + T_R ((ctx == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM); + T_R ((p == NULL), IPC_ERROR_DEL__NO_CLIENT_PARAM); + T_R ((ctx->cinfos == NULL), IPC_ERROR_DEL__EMPTY_LIST); + + size_t i; + for (i = 0; i < ctx->size; i++) { + // WARNING: The test is performed on the pointers of both structures, + // this is efficient but it doesn't work if the p structure is a copy. + if (ctx->cinfos[i] == p) { + // TODO: possible memory leak if the ipc_connection_info is not deeply free'ed. + ctx->cinfos[i] = ctx->cinfos[ctx->size - 1]; + ctx->size--; + if (ctx->size == 0) { + ipc_connections_free (ctx); + } else { + ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size); + + if (ctx->cinfos == NULL) { + IPC_RETURN_ERROR (IPC_ERROR_DEL__EMPTIED_LIST); + } + } + + IPC_RETURN_NO_ERROR; + } + } + + IPC_RETURN_ERROR (IPC_ERROR_DEL__CANNOT_FIND_CLIENT); +} + +void ipc_connections_free (struct ipc_ctx *ctx) +{ + if (ctx->cinfos != NULL) { + for (size_t i = 0; i < ctx->size; i++) { + free (ctx->cinfos[i]); + } + free (ctx->cinfos); + ctx->cinfos = NULL; + } + ctx->size = 0; +} + +// add an arbitrary file descriptor to read +struct ipc_error ipc_add_fd (struct ipc_ctx *ctx, int fd) +{ + T_R ((ctx == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS); + + SECURE_DECLARATION (struct ipc_connection_info, cinfo); + cinfo.type = IPC_CONNECTION_TYPE_EXTERNAL; + + SECURE_DECLARATION (struct pollfd, pollfd); + pollfd.fd = fd; + pollfd.events = POLLIN; + + return ipc_add (ctx, &cinfo, &pollfd); +} + +// remove a connection from its file descriptor +struct ipc_error ipc_del_fd (struct ipc_ctx *ctx, int fd) +{ + T_R ((ctx == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS); + T_R ((ctx->cinfos == NULL || ctx->pollfd), IPC_ERROR_DEL_FD__EMPTY_LIST); + + for (size_t i = 0; i < ctx->size; i++) { + + if (ctx->pollfd[i].fd == fd) { + + if (ctx->cinfos[i].spath != NULL) + free (ctx->cinfos[i].spath); + + ctx->size--; + + if (ctx->size == 0) { + // free ctx->cinfos and ctx->pollfd + ipc_connections_free (ctx); + } else { + // The last element in the array replaces the removed one. + ctx->cinfos[i] = ctx->cinfos[ctx->size]; + ctx->pollfd[i] = ctx->pollfd[ctx->size]; + + // Reallocation of the arrays. TODO: should be optimised someday. + ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size); + ctx->pollfd = realloc (ctx->pollfd, sizeof (struct pollfd ) * ctx->size); + + if (ctx->cinfos == NULL || ctx->pollfd == NULL) { + IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__EMPTIED_LIST); + } + } + + IPC_RETURN_NO_ERROR; + } + } + + IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT); +} + +#if 0 + // new message struct ipc_error handle_message ( struct ipc_event *event @@ -380,6 +493,7 @@ struct ipc_error handle_message ( IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc); return rvalue; } + // disconnection: close the client then delete it from ctx if (ret.error_code == IPC_ERROR_CLOSED_RECIPIENT) { TEST_IPC_P (ipc_close (pc), "cannot close a connection on closed recipient in handle_message"); @@ -494,7 +608,6 @@ hungup: IPC_RETURN_NO_ERROR; } -#if 0 struct ipc_error ipc_wait_event_networkd ( struct ipc_ctx *ctx , struct ipc_connection_info *cinfo // NULL for clients @@ -574,7 +687,6 @@ struct ipc_error ipc_wait_event_networkd ( IPC_RETURN_NO_ERROR; } -#endif struct ipc_error ipc_wait_event ( struct ipc_ctx *ctx @@ -584,134 +696,4 @@ struct ipc_error ipc_wait_event ( { return ipc_wait_event_networkd (ctx, cinfo, event, NULL, timer); } - -/** - * Allocate memory then add a new connection to the context. - */ -struct ipc_error -ipc_add ( - struct ipc_ctx *ctx - , struct ipc_connection_info *p - , struct pollfd *pollfd) -{ - T_R ((ctx == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS); - T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT); - - // Memory reallocation. - ipc_ctx_new_alloc (ctx); - - memcpy (ctx->cinfos[ctx->size - 1], p , sizeof (struct ipc_connection_info)); - memcpy (ctx->pollfd[ctx->size - 1], pollfd, sizeof (struct pollfd)); - - IPC_RETURN_NO_ERROR; -} - -struct ipc_error ipc_del ( - struct ipc_ctx *ctx - , struct ipc_connection_info *p) -{ - T_R ((ctx == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM); - T_R ((p == NULL), IPC_ERROR_DEL__NO_CLIENT_PARAM); - T_R ((ctx->cinfos == NULL), IPC_ERROR_DEL__EMPTY_LIST); - - size_t i; - for (i = 0; i < ctx->size; i++) { - // WARNING: The test is performed on the pointers of both structures, - // this is efficient but it doesn't work if the p structure is a copy. - if (ctx->cinfos[i] == p) { - // TODO: possible memory leak if the ipc_connection_info is not deeply free'ed. - ctx->cinfos[i] = ctx->cinfos[ctx->size - 1]; - ctx->size--; - if (ctx->size == 0) { - ipc_connections_free (ctx); - } else { - ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size); - - if (ctx->cinfos == NULL) { - IPC_RETURN_ERROR (IPC_ERROR_DEL__EMPTIED_LIST); - } - } - - IPC_RETURN_NO_ERROR; - } - } - - IPC_RETURN_ERROR (IPC_ERROR_DEL__CANNOT_FIND_CLIENT); -} - -void ipc_connections_close (struct ipc_ctx *ctx) -{ - if (ctx->cinfos != NULL) { - for (size_t i = 0; i < ctx->size; i++) { - ipc_close (ctx->cinfos[i]); - free (ctx->cinfos[i]); - } - free (ctx->cinfos); - ctx->cinfos = NULL; - } - ctx->size = 0; -} - -void ipc_connections_free (struct ipc_ctx *ctx) -{ - if (ctx->cinfos != NULL) { - for (size_t i = 0; i < ctx->size; i++) { - free (ctx->cinfos[i]); - } - free (ctx->cinfos); - ctx->cinfos = NULL; - } - ctx->size = 0; -} - -// add an arbitrary file descriptor to read -struct ipc_error ipc_add_fd (struct ipc_ctx *ctx, int fd) -{ - T_R ((ctx == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS); - - SECURE_DECLARATION (struct ipc_connection_info, cinfo); - cinfo.type = IPC_CONNECTION_TYPE_EXTERNAL; - - SECURE_DECLARATION (struct pollfd, pollfd); - pollfd.fd = fd; - pollfd.events = POLLIN; - - return ipc_add (ctx, &cinfo, &pollfd); -} - -// remove a connection from its file descriptor -struct ipc_error ipc_del_fd (struct ipc_ctx *ctx, int fd) -{ - T_R ((ctx == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS); - T_R ((ctx->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST); - - for (size_t i = 0; i < ctx->size; i++) { - - if (ctx->cinfos[i]->pollfd.fd == fd) { - - ctx->cinfos[i]->pollfd.fd = -1; - free (ctx->cinfos[i]); - ctx->pollfd[i] = NULL; - ctx->size--; - - if (ctx->size == 0) { - // free ctx->cinfos - ipc_connections_free (ctx); - } else { - ctx->cinfos[i] = ctx->cinfos[ctx->size]; - ctx->pollfd[i] = ctx->pollfd[ctx->size]; - - ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size); - ctx->pollfd = realloc (ctx->pollfd, sizeof (struct pollfd ) * ctx->size); - - if (ctx->cinfos == NULL || ctx->pollfd == NULL) { - IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__EMPTIED_LIST); - } - } - - IPC_RETURN_NO_ERROR; - } - } - - IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT); -} +#endif diff --git a/src/ipc.h b/src/ipc.h index 1dbdb09..ab4851b 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -266,20 +266,15 @@ enum ipc_connection_types { * main public functions **/ -struct ipc_error -ipc_server_init ( - char **env - , struct ipc_ctx **ctx - , const char *sname); -struct ipc_error ipc_connection (char **env, struct ipc_ctx **ctx, const char *sname); +struct ipc_error ipc_server_init (struct ipc_ctx **ctx, const char *sname); +struct ipc_error ipc_connection (struct ipc_ctx **ctx, const char *sname); -struct ipc_error ipc_server_close (struct ipc_connection_info *srv); -struct ipc_error ipc_close (struct ipc_connection_info *p); +struct ipc_error ipc_close (struct ipc_ctx *ctx, uint32_t index); +struct ipc_error ipc_close_all (struct ipc_ctx *ctx); -struct ipc_error ipc_read (const struct ipc_connection_info *, struct ipc_message *m); -struct ipc_error ipc_write (const struct ipc_connection_info *, const struct ipc_message *m); +struct ipc_error ipc_read (const struct ipc_ctx *, uint32_t index, struct ipc_message *m); +struct ipc_error ipc_write (const struct ipc_ctx *, uint32_t index, const struct ipc_message *m); -struct ipc_error ipc_wait_event (struct ipc_ctx *, struct ipc_event *, int *timer); struct ipc_error ipc_wait_event (struct ipc_ctx *, struct ipc_event *, int *timer); // store and remove only pointers on allocated structures @@ -291,7 +286,6 @@ struct ipc_error ipc_add_fd (struct ipc_ctx *cinfos, int fd); struct ipc_error ipc_del_fd (struct ipc_ctx *cinfos, int fd); void ipc_connections_free (struct ipc_ctx *); -void ipc_connections_close (struct ipc_ctx *cinfos); /*** * message functions @@ -328,7 +322,8 @@ struct ipc_error ipc_ctx_init (struct ipc_ctx **); void ipc_connection_print (struct ipc_connection_info *cinfo); void ipc_connections_print (struct ipc_ctx *cinfos); -struct ipc_error ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p); +// Last parameter is the index for the server fd in the context structure. +struct ipc_error ipc_accept_add (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index); struct ipc_error ipc_contact_networkd (int *pfd, const char *sname); struct ipc_error service_path (char *path, const char *sname);