From 44992e940cda0dab5339610c129abcba841ef74b Mon Sep 17 00:00:00 2001 From: Karchnu Date: Sun, 28 Jun 2020 15:40:02 +0200 Subject: [PATCH] WIP --- examples/pong.c | 4 - examples/pongd.c | 55 ++---- src/communication.c | 424 ++++++++++++++++++++------------------------ src/ipc.h | 3 +- 4 files changed, 209 insertions(+), 277 deletions(-) diff --git a/examples/pong.c b/examples/pong.c index efce69d..e51e368 100644 --- a/examples/pong.c +++ b/examples/pong.c @@ -155,10 +155,6 @@ int main (int argc, char *argv[], char *env[]) srv = malloc (sizeof (struct ipc_connection_info)); memset (srv, 0, sizeof (struct ipc_connection_info)); - // index and version should be filled - srv->index = 0; - srv->version = 0; - if (argc == 4) non_interactive (atoi(argv[1]), (size_t) atoi(argv[2]), argv[3], env); else diff --git a/examples/pongd.c b/examples/pongd.c index 971496a..7b657ba 100644 --- a/examples/pongd.c +++ b/examples/pongd.c @@ -22,9 +22,8 @@ /** ****************************************************************************** * Overview of the main loop: - * 1. "clients" pointer declaration (struct ipc_ctx). - * 1. ipc_init (&clients) - * 1. ipc_server_init (env, srv, SERVICE_NAME) + * 1. "ctx" pointer declaration (struct ipc_ctx). + * 1. ipc_server_init (env, ctx, SERVICE_NAME) ****************************************************************************** */ @@ -32,8 +31,7 @@ int cpt = 0; int verbosity = 1; -struct ipc_connection_info *srv = NULL; -struct ipc_ctx *clients = NULL; +struct ipc_ctx *ctx = NULL; void main_loop () { @@ -41,26 +39,20 @@ void main_loop () double timer = base_timer; SECURE_DECLARATION (struct ipc_error, ret); - /** TODO: should return something */ - ipc_init (&clients); - - // clients = malloc (sizeof (struct ipc_ctx)); - // memset (clients, 0, sizeof (struct ipc_ctx)); - SECURE_DECLARATION (struct ipc_event, event); event.type = IPC_EVENT_TYPE_NOT_SET; while (1) { // ipc_wait_event provides one event at a time // warning: event->m is free'ed if not NULL - TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (clients, srv, &event, &timer), EXIT_FAILURE); + TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (ctx, srv, &event, &timer), EXIT_FAILURE); switch (event.type) { case IPC_EVENT_TYPE_CONNECTION: { cpt++; if (verbosity > 1) { - printf ("connection: %d clients connected, new client is %d\n", cpt, (event.origin)->fd); + printf ("connection: %d ctx connected, new client is %d\n", cpt, (event.origin)->fd); } }; break; @@ -68,7 +60,7 @@ void main_loop () { cpt--; if (verbosity > 1) { - printf ("disconnection: %d clients remaining\n", cpt); + printf ("disconnection: %d ctx remaining\n", cpt); } // free the ipc_client structure @@ -106,7 +98,7 @@ void main_loop () { cpt--; fprintf (stderr, "a problem happened with client %d (now disconnected)", (event.origin)->fd); - fprintf (stderr, ", %d clients remaining\n", cpt); + fprintf (stderr, ", %d ctx remaining\n", cpt); // free the ipc_client structure free (event.origin); @@ -127,17 +119,17 @@ void exit_program (int signal) { printf ("Quitting, signal: %d\n", signal); - // free remaining clients - for (size_t i = 0; i < clients->size; i++) { - struct ipc_connection_info *cli = clients->cinfos[i]; + // free remaining ctx + for (size_t i = 0; i < ctx->size; i++) { + struct ipc_connection_info *cli = ctx->cinfos[i]; if (cli != NULL) { free (cli); } - clients->cinfos[i] = NULL; + ctx->cinfos[i] = NULL; } - ipc_connections_free (clients); - free (clients); + ipc_connections_free (ctx); + free (ctx); // the application will shut down, and close the service struct ipc_error ret = ipc_server_close (srv); @@ -150,7 +142,7 @@ void exit_program (int signal) } /* - * service ping-pong: send back everything sent by the clients + * service ping-pong: send back everything sent by the ctx * stop the program on SIG{TERM,INT,ALRM,USR{1,2},HUP} signals */ @@ -165,32 +157,21 @@ int main (int argc, char *argv[], char **env) printf ("pid = %d\n", getpid ()); - srv = malloc (sizeof (struct ipc_connection_info)); - if (srv == NULL) { - exit (EXIT_FAILURE); - } - memset (srv, 0, sizeof (struct ipc_connection_info)); - srv->type = '\0'; - srv->index = 0; - srv->version = 0; - srv->fd = 0; - srv->spath = NULL; - - struct ipc_error ret = ipc_server_init (env, srv, PONGD_SERVICE_NAME); + struct ipc_error ret = ipc_server_init (env, &ctx, PONGD_SERVICE_NAME); if (ret.error_code != IPC_ERROR_NONE) { PRINTERR (ret, "server init"); return EXIT_FAILURE; } - printf ("Listening on %s.\n", srv->spath); + printf ("Listening on %s.\n", ctx->cinfos[0].spath); printf ("MAIN: server created\n"); - signal (SIGHUP, exit_program); + signal (SIGHUP, exit_program); signal (SIGALRM, exit_program); signal (SIGUSR1, exit_program); signal (SIGUSR2, exit_program); signal (SIGTERM, exit_program); - signal (SIGINT, exit_program); + signal (SIGINT, exit_program); // the service will loop until the end of time, or a signal main_loop (); diff --git a/src/communication.c b/src/communication.c index 76f4207..db92cda 100644 --- a/src/communication.c +++ b/src/communication.c @@ -41,15 +41,41 @@ struct ipc_error ipc_ctx_init (struct ipc_ctx **ctx) T_R ((*ctx == NULL), IPC_ERROR_CTX_INIT__MALLOC_CTX); memset (ctx, 0, sizeof(struct ipc_ctx)); - // (*ctx)->cinfos = malloc(sizeof(struct )); - // T_R (((*ctx)->pollfd == NULL), IPC_ERROR_CTX_INIT__MALLOC_POLLFD); - // - // (*ctx)->pollfd = malloc(sizeof(struct pollfd)); - // T_R (((*ctx)->pollfd == NULL), IPC_ERROR_CTX_INIT__MALLOC_POLLFD); - IPC_RETURN_NO_ERROR; } +/** + * PERFORMANCE POINT: + * Realloc is performed at each new user. There is plenty of room for improvement, + * 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) +{ + ctx->size++; + + // Memory could be not allocated, yet. + 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); + } else { + ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size); + ctx->pollfd = realloc (ctx->pollfd, sizeof (struct pollfd ) * ctx->size); + } + + T_R ((ctx->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST); + 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)); + + IPC_RETURN_ERROR; +} + struct ipc_error ipc_server_init (char **env, struct ipc_ctx **ctx, const char *sname) { @@ -58,46 +84,25 @@ ipc_server_init (char **env, struct ipc_ctx **ctx, const char *sname) ipc_ctx_init(ctx); -#if 0 - // For server init, no need for networkd evaluation - - // TODO: loop over environment variables - // any IPC_NETWORK_* should be shared with the network service - // in order to route requests over any chosen protocol stack - // ex: IPC_NETWORK_AUDIO="tor://some.example.com/" - for (size_t i = 0; env[i] != NULL; i++) { - // TODO: check for every IPC_NETWORK_* environment variable - } -#endif - - struct ipc_connection_info *srv = NULL; - - // Initialize the server IPC structure. - SECURE_BUFFER_HEAP_ALLOCATION_R (srv, sizeof (struct ipc_connection_info),, - IPC_ERROR_SERVER_INIT__NOT_ENOUGH_MEMORY); - - srv->type = IPC_CONNECTION_TYPE_SERVER; - // gets the service path SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); TEST_IPC_RR (service_path (buf, sname), "cannot get server path"); - // gets the service path - if (srv->spath != NULL) { - free (srv->spath); - srv->spath = NULL; - } - size_t s = strlen (buf); - 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 + SECURE_DECLARATION (struct ipc_connection_info, srv); + srv.type = IPC_CONNECTION_TYPE_SERVER; + SECURE_DECLARATION(struct pollfd, pollfd); + pollfd.events = POLLIN; - TEST_IPC_RETURN_ON_ERROR (usock_init (&srv->pollfd.fd, srv->spath)); + 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 + + TEST_IPC_RETURN_ON_ERROR (usock_init (&pollfd.fd, srv.spath)); // Add the server to the listened file descriptors. - TEST_IPC_RR (ipc_add (ctx, srv), "cannot add the server in the context"); + TEST_IPC_RR (ipc_add (*ctx, &srv, &pollfd), "cannot add the server in the context"); IPC_RETURN_NO_ERROR; } @@ -105,14 +110,14 @@ ipc_server_init (char **env, struct ipc_ctx **ctx, const char *sname) struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m); // when networkd is not working properly (or do not retrieve the service): srv->fd = 0 -struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname) +struct ipc_error ipc_contact_networkd (int *pfd, const char *sname) { - T_R ((srv == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM); + T_R ((pfd == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_FD_PARAM); T_R ((sname == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM); char *networkvar = getenv ("IPC_NETWORK"); if (networkvar == NULL) { - srv->pollfd.fd = 0; + *pfd = 0; IPC_RETURN_NO_ERROR; } // TODO: is there another, more interesting way to do this? @@ -128,7 +133,7 @@ struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const ch if (strncmp (networkvar, sname, strlen (sname)) != 0 && strstr (networkvar, columnthensname) == NULL) { // printf ("sname %s not found\n", sname); - srv->pollfd.fd = 0; + *fd = 0; IPC_RETURN_NO_ERROR; } @@ -152,7 +157,7 @@ struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const ch TEST_IPC_RR (ipc_write_fd (networkdfd, &msg), "cannot send a message to networkd"); - struct ipc_error ret = ipc_receive_fd (networkdfd, &srv->pollfd.fd); + struct ipc_error ret = ipc_receive_fd (networkdfd, pfd); if (ret.error_code == IPC_ERROR_NONE) { usock_close (networkdfd); } @@ -167,27 +172,26 @@ struct ipc_error ipc_connection (char **env, struct ipc_ctx **ctx, const char *s T_R ((ctx == NULL), IPC_ERROR_CONNECTION__NO_CTX); T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME); - ipc_ctx_init(ctx); + ipc_ctx_init(ctx); // Allocate memory for the context. - struct ipc_connection_info *srv = NULL; - SECURE_BUFFER_HEAP_ALLOCATION_R (srv, sizeof (struct ipc_connection_info),, - IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY); + SECURE_DECLARATION(struct ipc_connection_info, srv); + srv.type = IPC_CONNECTION_TYPE_IPC; // Data received on the socket = messages, not new clients. + SECURE_DECLARATION(struct pollfd, pollfd); + pollfd.events = POLLIN; - srv->type = IPC_CONNECTION_TYPE_IPC; - - // Add the server to the listened file descriptors. - TEST_IPC_RR (ipc_add (ctx, srv), "cannot add the server in the context"); - - TEST_IPC_P (ipc_contact_networkd (srv, sname), "error during networkd connection"); + TEST_IPC_P (ipc_contact_networkd (&pollfd.fd, sname), "error during networkd connection"); // if networkd did not initiate the connection - if (srv->pollfd.fd <= 0) { + if (pollfd.fd <= 0) { // gets the service path SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); TEST_IPC_RR (service_path (buf, sname), "cannot get server path"); - TEST_IPC_RETURN_ON_ERROR (usock_connect (&srv->pollfd.fd, buf)); + TEST_IPC_RETURN_ON_ERROR (usock_connect (&pollfd.fd, buf)); } + // Add the server to the listened file descriptors. + TEST_IPC_RR (ipc_add (*ctx, &srv, &pollfd), "cannot add the server in the context"); + IPC_RETURN_NO_ERROR; } @@ -265,20 +269,20 @@ struct ipc_error ipc_write (const struct ipc_connection_info *p, const struct ip // New connection from a client. struct ipc_error -handle_connection (struct ipc_event *event - , struct ipc_ctx *cinfos - , struct ipc_connection_info *cinfo) +ipc_accept_add (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t i) { - T_R ((cinfo == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM); - T_R ((cinfos == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM); + T_R ((ctx == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM); + T_R ((i >= ctx->size), IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX); - struct ipc_connection_info *new_client = NULL; + // Memory reallocation. + ipc_ctx_new_alloc (ctx); - SECURE_BUFFER_HEAP_ALLOCATION_R (new_client, sizeof (struct ipc_connection_info),, - IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC); + 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; - TEST_IPC_RR (ipc_accept (cinfo, new_client), "cannot accept the client during handle_new_connection"); - TEST_IPC_RR (ipc_add (cinfos, new_client), "cannot add the new accepted client"); + 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; @@ -287,7 +291,7 @@ handle_connection (struct ipc_event *event // new message struct ipc_error handle_message ( struct ipc_event *event - , struct ipc_ctx *cinfos + , struct ipc_ctx *ctx , struct ipc_connection_info *pc, struct ipc_switchings *switchdb) { // if the socket is associated to another one for networkd @@ -331,11 +335,11 @@ struct ipc_error handle_message ( delfd = ipc_switching_del (switchdb, talkingfd); if (delfd >= 0) { close (delfd); - ipc_del_fd (cinfos, delfd); + ipc_del_fd (ctx, delfd); } close (talkingfd); - ipc_del_fd (cinfos, talkingfd); + ipc_del_fd (ctx, talkingfd); #if 0 if (delfd >= 0) { @@ -371,15 +375,15 @@ struct ipc_error handle_message ( // if there is a problem, just remove the client TEST_IPC_P (ipc_close (pc), "cannot close a connection in handle_message"); - TEST_IPC_P (ipc_del (cinfos, pc), "cannot delete a connection in handle_message"); + TEST_IPC_P (ipc_del (ctx, pc), "cannot delete a connection in handle_message"); IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc); return rvalue; } - // disconnection: close the client then delete it from cinfos + // 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"); - TEST_IPC_P (ipc_del (cinfos, pc), "cannot delete a connection on closed recipient in handle_message"); + TEST_IPC_P (ipc_del (ctx, pc), "cannot delete a connection on closed recipient in handle_message"); ipc_message_empty (m); free (m); @@ -394,111 +398,75 @@ struct ipc_error handle_message ( IPC_RETURN_NO_ERROR; } +// TODO +struct ipc_error +handle_writing_message (struct ipc_event *events, struct ipc_ctx *ctx, uint32_t i); +struct ipc_error +handle_writing_message (struct ipc_event *events, struct ipc_ctx *ctx, uint32_t i) +{ + IPC_RETURN_NO_ERROR; +} + struct ipc_error ipc_events_loop ( - struct ipc_ctx *cinfos + struct ipc_ctx *ctx , struct ipc_connection_info *cinfo // NULL for clients , struct ipc_event *event , struct ipc_switchings *switchdb , struct ipc_messages *messages_to_send , int *timer /* in ms */) { - T_R ((cinfos == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM); + T_R ((ctx == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM); T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM); IPC_EVENT_CLEAN (event); - // struct ipc_connection_info { - // struct pollfd *pollfd; - // char type; // server, client, arbitrary fd - // char *spath; // max size: PATH_MAX - // }; - - // struct ipc_ctx { - // struct ipc_connection_info **cinfos; - // struct ipc_connection_info *pollfd; - // size_t size; - // }; - - // struct ipc_event { - // enum ipc_event_type type; - // struct ipc_connection_info *origin; - // void *m; // message pointer - // }; - - // enum ipc_event_type { - // IPC_EVENT_TYPE_NOT_SET = 0 - // , IPC_EVENT_TYPE_ERROR = 1 - // , IPC_EVENT_TYPE_EXTRA_SOCKET = 2 // Message coming from a non-IPC fd. - // , IPC_EVENT_TYPE_SWITCH = 3 // Message coming from a switched fd. - // , IPC_EVENT_TYPE_CONNECTION = 4 - // , IPC_EVENT_TYPE_DISCONNECTION = 5 - // , IPC_EVENT_TYPE_MESSAGE = 6 - // , IPC_EVENT_TYPE_LOOKUP = 7 - // , IPC_EVENT_TYPE_TIMER = 8 - // }; - - // struct ipc_messages { - // struct ipc_message **messages; - // size_t size; - // }; - - // struct ipc_message { - // char type; - // char user_type; - // uint32_t length; - // char *payload; - // int fd; // File descriptor concerned about this message. - // }; - - // struct pollfd { - // int fd; /* file descriptor */ - // short events; /* requested events */ - // short revents; /* returned events */ - // }; - // [struct pollfd] - int i, n, listenfd, client_fd, nread; - char buf[MAXLINE]; uid_t uid; // Generate the array of pollfd structure once, then use it each time. - // TODO: ça ailleurs: if ( (cinfos->pollfd = malloc(sizeof(struct pollfd))) == NULL) + // TODO: ça ailleurs: if ( (ctx->pollfd = malloc(sizeof(struct pollfd))) == NULL) // TODO: ça ailleurs: err_sys("malloc error"); // TODO: ça ailleurs: client_add(listenfd, 0); /* we use [0] for listenfd */ - // TODO: ça ailleurs: cinfos->pollfd[0].fd = listenfd; - // TODO: ça ailleurs: cinfos->pollfd[0].events = POLLIN; + // TODO: ça ailleurs: ctx->pollfd[0].fd = listenfd; + // TODO: ça ailleurs: ctx->pollfd[0].events = POLLIN; - if ((n = poll(cinfos->pollfd, cinfos->size, INFTIM)) < 0) + if ((n = poll(ctx->pollfd, ctx->size, *timer)) < 0) { log_sys("select error"); } + + // Timeout. + if (n == 0) { + // TODO: timeout + } - for (i = 0; i <= cinfos->size; i++) { + for (i = 0; i <= ctx->size; i++) { // Something to read or connection. - if (cinfos->pollfd[i].revents & POLLIN) + if (ctx->pollfd[i].revents & POLLIN) { // In case there is something to read for the server socket: new client. - if (cinfo != NULL && i == cinfo->pollfd) { - return handle_connection (event, cinfos, cinfo); + if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SERVER) { + return ipc_accept_add (event, ctx, i); } - if (i == (size_t) cinfos->cinfos[j]->pollfd.fd) { - return handle_message (event, cinfos, cinfos->cinfos[j], switchdb); - } + return handle_message (event, ctx, i, switchdb); } - // if ((client_fd = cinfos->cinfos[i].fd) < 0) - // continue; + if (ctx->pollfd[i].revents & POLLOUT) + { + return handle_writing_message (event, ctx, i); + } - // Timeout. - /** TODO: timeout */ + // TODO: in case there is an error that way?? + //if (ctx->cinfos[i].fd < 0) + // continue; // Disconnection. - if (cinfos->pollfd[i].revents & POLLHUP) + if (ctx->pollfd[i].revents & POLLHUP) goto hungup; - else if (cinfos->pollfd[i].revents & POLLIN) { - return handle_message (event, cinfos, cinfos->cinfos[j], switchdb); + else if (ctx->pollfd[i].revents & POLLIN) { + return handle_disconnection (event, ctx, i, switchdb); /* read argument buffer from client */ if ( (nread = read(client_fd, buf, MAXLINE)) < 0) log_sys("read error on fd %d", client_fd); @@ -506,7 +474,7 @@ ipc_events_loop ( hungup: log_msg("closed: uid %d, fd %d", client[i].uid, client_fd); client_del(client_fd); /* client has closed conn */ - cinfos->pollfd[i].fd = -1; + ctx->pollfd[i].fd = -1; close(client_fd); } else /* process client's rquest */ request(buf, nread, client_fd, client[i].uid); @@ -514,26 +482,27 @@ hungup: } /** for loop: end of the message handling */ - // from 0 to cinfos->size + // from 0 to ctx->size // if something to read // if this is the server // return handle_connection // else - // from 0 to cinfos->size - // if this is the right index in cinfos->cinfos - // return handle_message (event, cinfos, cinfos->cinfos[j], switchdb); + // from 0 to ctx->size + // if this is the right index in ctx->cinfos + // return handle_message (event, ctx, i, switchdb); IPC_RETURN_NO_ERROR; } +#if 0 struct ipc_error ipc_wait_event_networkd ( - struct ipc_ctx *cinfos + struct ipc_ctx *ctx , struct ipc_connection_info *cinfo // NULL for clients , struct ipc_event *event , struct ipc_switchings *switchdb , int *timer) { - T_R ((cinfos == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM); + T_R ((ctx == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM); T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM); IPC_EVENT_CLEAN (event); @@ -549,7 +518,7 @@ struct ipc_error ipc_wait_event_networkd ( /* maximum file descriptor number */ /* keep track of the biggest file descriptor */ - int32_t fdmax = get_max_fd (cinfos); + int32_t fdmax = get_max_fd (ctx); /* listening socket descriptor */ int32_t listener; @@ -564,8 +533,8 @@ struct ipc_error ipc_wait_event_networkd ( fdmax = listener; } - for (i = 0; i < cinfos->size; i++) { - FD_SET (cinfos->cinfos[i]->pollfd.fd, &master); + for (i = 0; i < ctx->size; i++) { + FD_SET (ctx->cinfos[i]->pollfd.fd, &master); } readf = master; @@ -592,11 +561,11 @@ struct ipc_error ipc_wait_event_networkd ( for (i = 0; i <= (size_t) fdmax; i++) { if (FD_ISSET (i, &readf)) { if (cinfo != NULL && i == (size_t) listener) { - return handle_connection (event, cinfos, cinfo); + return handle_connection (event, ctx, cinfo); } else { - for (j = 0; j < cinfos->size; j++) { - if (i == (size_t) cinfos->cinfos[j]->pollfd.fd) { - return handle_message (event, cinfos, cinfos->cinfos[j], switchdb); + for (j = 0; j < ctx->size; j++) { + if (i == (size_t) ctx->cinfos[j]->pollfd.fd) { + return handle_message (event, ctx, ctx->cinfos[j], switchdb); } } } @@ -605,73 +574,60 @@ struct ipc_error ipc_wait_event_networkd ( IPC_RETURN_NO_ERROR; } +#endif struct ipc_error ipc_wait_event ( - struct ipc_ctx *cinfos + struct ipc_ctx *ctx , struct ipc_connection_info *cinfo // NULL for clients , struct ipc_event *event , int *timer) { - return ipc_wait_event_networkd (cinfos, cinfo, event, NULL, timer); + return ipc_wait_event_networkd (ctx, cinfo, event, NULL, timer); } /** - * PERFORMANCE POINT: - * Realloc is performed at each new user. There is plenty of room for improvement, - * for example by managing allocations of thousands of structures at once. - * WARNING: Store and remove only pointers on allocated structures. + * Allocate memory then add a new connection to the context. */ -struct ipc_error ipc_add ( - struct ipc_ctx *cinfos - , struct ipc_connection_info *p) +struct ipc_error +ipc_add ( + struct ipc_ctx *ctx + , struct ipc_connection_info *p + , struct pollfd *pollfd) { - T_R ((cinfos == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS); - T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT); + T_R ((ctx == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS); + T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT); - cinfos->size++; - // In case this is the first allocation. - if (cinfos->size == 1) { - if (cinfos->cinfos == NULL && cinfos->pollfd == NULL) { - SECURE_BUFFER_HEAP_ALLOCATION_R (cinfos->cinfos, sizeof (struct ipc_connection_info),, - IPC_ERROR_ADD__MALLOC); - SECURE_BUFFER_HEAP_ALLOCATION_R (cinfos->pollfd, sizeof (struct pollfd),, - IPC_ERROR_ADD__MALLOC_POLLFD); - } - } else { - cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size); - cinfos->pollfd = realloc (cinfos->pollfd, sizeof (struct pollfd ) * cinfos->size); - } + // Memory reallocation. + ipc_ctx_new_alloc (ctx); - T_R ((cinfos->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST); - - cinfos->cinfos[cinfos->size - 1] = p; - cinfos->pollfd[cinfos->size - 1] = &p->pollfd; + 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 *cinfos + struct ipc_ctx *ctx , struct ipc_connection_info *p) { - T_R ((cinfos == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM); + T_R ((ctx == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM); T_R ((p == NULL), IPC_ERROR_DEL__NO_CLIENT_PARAM); - T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL__EMPTY_LIST); + T_R ((ctx->cinfos == NULL), IPC_ERROR_DEL__EMPTY_LIST); size_t i; - for (i = 0; i < cinfos->size; 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 (cinfos->cinfos[i] == p) { + if (ctx->cinfos[i] == p) { // TODO: possible memory leak if the ipc_connection_info is not deeply free'ed. - cinfos->cinfos[i] = cinfos->cinfos[cinfos->size - 1]; - cinfos->size--; - if (cinfos->size == 0) { - ipc_connections_free (cinfos); + ctx->cinfos[i] = ctx->cinfos[ctx->size - 1]; + ctx->size--; + if (ctx->size == 0) { + ipc_connections_free (ctx); } else { - cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size); + ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size); - if (cinfos->cinfos == NULL) { + if (ctx->cinfos == NULL) { IPC_RETURN_ERROR (IPC_ERROR_DEL__EMPTIED_LIST); } } @@ -683,72 +639,72 @@ struct ipc_error ipc_del ( IPC_RETURN_ERROR (IPC_ERROR_DEL__CANNOT_FIND_CLIENT); } -void ipc_connections_close (struct ipc_ctx *cinfos) +void ipc_connections_close (struct ipc_ctx *ctx) { - if (cinfos->cinfos != NULL) { - for (size_t i = 0; i < cinfos->size; i++) { - ipc_close (cinfos->cinfos[i]); - free (cinfos->cinfos[i]); + if (ctx->cinfos != NULL) { + for (size_t i = 0; i < ctx->size; i++) { + ipc_close (ctx->cinfos[i]); + free (ctx->cinfos[i]); } - free (cinfos->cinfos); - cinfos->cinfos = NULL; + free (ctx->cinfos); + ctx->cinfos = NULL; } - cinfos->size = 0; + ctx->size = 0; } -void ipc_connections_free (struct ipc_ctx *cinfos) +void ipc_connections_free (struct ipc_ctx *ctx) { - if (cinfos->cinfos != NULL) { - for (size_t i = 0; i < cinfos->size; i++) { - free (cinfos->cinfos[i]); + if (ctx->cinfos != NULL) { + for (size_t i = 0; i < ctx->size; i++) { + free (ctx->cinfos[i]); } - free (cinfos->cinfos); - cinfos->cinfos = NULL; + free (ctx->cinfos); + ctx->cinfos = NULL; } - cinfos->size = 0; + ctx->size = 0; } // add an arbitrary file descriptor to read -struct ipc_error ipc_add_fd (struct ipc_ctx *cinfos, int fd) +struct ipc_error ipc_add_fd (struct ipc_ctx *ctx, int fd) { - T_R ((cinfos == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS); + T_R ((ctx == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS); - struct ipc_connection_info *cinfo = NULL; + SECURE_DECLARATION (struct ipc_connection_info, cinfo); + cinfo.type = IPC_CONNECTION_TYPE_EXTERNAL; - SECURE_BUFFER_HEAP_ALLOCATION_R (cinfo, sizeof (struct ipc_connection_info),, - IPC_ERROR_ADD_FD__NOT_ENOUGH_MEMORY); + SECURE_DECLARATION (struct pollfd, pollfd); + pollfd.fd = fd; + pollfd.events = POLLIN; - cinfo->type = IPC_CONNECTION_TYPE_EXTERNAL; - - return ipc_add (cinfos, cinfo); + return ipc_add (ctx, &cinfo, &pollfd); } // remove a connection from its file descriptor -struct ipc_error ipc_del_fd (struct ipc_ctx *cinfos, int fd) +struct ipc_error ipc_del_fd (struct ipc_ctx *ctx, int fd) { - T_R ((cinfos == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS); - T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST); + 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 < cinfos->size; i++) { + for (size_t i = 0; i < ctx->size; i++) { - if (cinfos->cinfos[i]->pollfd.fd == fd) { + if (ctx->cinfos[i]->pollfd.fd == fd) { - cinfos->cinfos[i]->pollfd.fd = -1; - free (cinfos->cinfos[i]); - cinfos->pollfd[i] = NULL; - cinfos->size--; + ctx->cinfos[i]->pollfd.fd = -1; + free (ctx->cinfos[i]); + ctx->pollfd[i] = NULL; + ctx->size--; - if (cinfos->size == 0) { - // free cinfos->cinfos - ipc_connections_free (cinfos); + if (ctx->size == 0) { + // free ctx->cinfos + ipc_connections_free (ctx); } else { - cinfos->cinfos[i] = cinfos->cinfos[cinfos->size]; - cinfos->pollfd[i] = cinfos->pollfd[cinfos->size]; + ctx->cinfos[i] = ctx->cinfos[ctx->size]; + ctx->pollfd[i] = ctx->pollfd[ctx->size]; - cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size); - cinfos->pollfd = realloc (cinfos->pollfd, sizeof (struct pollfd ) * cinfos->size); + ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size); + ctx->pollfd = realloc (ctx->pollfd, sizeof (struct pollfd ) * ctx->size); - if (cinfos->cinfos == NULL || cinfos->pollfd == NULL) { + if (ctx->cinfos == NULL || ctx->pollfd == NULL) { IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__EMPTIED_LIST); } } diff --git a/src/ipc.h b/src/ipc.h index 1ae74a6..1dbdb09 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -196,7 +196,6 @@ struct ipc_error { const char *ipc_errors_get (enum ipc_error_code e); struct ipc_connection_info { - struct pollfd pollfd; char type; // server, client, arbitrary fd char *spath; // max size: PATH_MAX }; @@ -330,7 +329,7 @@ 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); -struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname); +struct ipc_error ipc_contact_networkd (int *pfd, const char *sname); struct ipc_error service_path (char *path, const char *sname); /***