diff --git a/Makefile b/Makefile index 4a29984..9745a5e 100644 --- a/Makefile +++ b/Makefile @@ -45,9 +45,9 @@ man/libipc.7.uninstall: @echo ' RM > $(MANDIR)/man7/libipc.7' $(Q)rm -f '$(DESTDIR)$(MANDIR)/man7/libipc.7' -libipc.so: src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o src/fs.h src/ipc.h src/message.h src/usocket.h src/utils.h +libipc.so: src/communication.o src/context.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/service_path.o src/usocket.o src/utils.o src/fs.h src/ipc.h src/message.h src/usocket.h src/utils.h @echo ' LD > libipc.so' - $(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o + $(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/communication.o src/context.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/service_path.o src/usocket.o src/utils.o libipc.so.install: libipc.so @echo ' IN > $(LIBDIR)/libipc.so.0.6.0' @@ -74,9 +74,9 @@ libipc.so.uninstall: @echo ' RM > $(LIBDIR)/libipc.so' $(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so' -libipc.a: src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o src/fs.h src/ipc.h src/message.h src/usocket.h src/utils.h +libipc.a: src/communication.o src/context.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/service_path.o src/usocket.o src/utils.o src/fs.h src/ipc.h src/message.h src/usocket.h src/utils.h @echo ' LD > libipc.a' - $(Q)$(AR) rc 'libipc.a' src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o + $(Q)$(AR) rc 'libipc.a' src/communication.o src/context.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/service_path.o src/usocket.o src/utils.o libipc.a.install: libipc.a @echo ' IN > $(LIBDIR)/libipc.a' @@ -103,6 +103,18 @@ src/communication.o.clean: src/communication.o.uninstall: +src/context.o: src/context.c src/ipc.h + @echo ' CC > src/context.o' + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/context.c -fPIC -std=c11 -o src/context.o + +src/context.o.install: + +src/context.o.clean: + @echo ' RM > src/context.o' + $(Q)rm -f src/context.o + +src/context.o.uninstall: + src/error.o: src/error.c src/ipc.h @echo ' CC > src/error.o' $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/error.c -fPIC -std=c11 -o src/error.o @@ -163,6 +175,18 @@ src/print.o.clean: src/print.o.uninstall: +src/service_path.o: src/service_path.c src/ipc.h + @echo ' CC > src/service_path.o' + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/service_path.c -fPIC -std=c11 -o src/service_path.o + +src/service_path.o.install: + +src/service_path.o.clean: + @echo ' RM > src/service_path.o' + $(Q)rm -f src/service_path.o + +src/service_path.o.uninstall: + src/usocket.o: src/usocket.c src/usocket.h src/utils.h src/fs.h @echo ' CC > src/usocket.o' $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/usocket.c -fPIC -std=c11 -o src/usocket.o @@ -209,13 +233,13 @@ $(DESTDIR)$(INCLUDEDIR): $(DESTDIR)$(MANDIR): @echo ' DIR > $(MANDIR)' $(Q)mkdir -p $(DESTDIR)$(MANDIR) -install: libipc.install man/libipc.7.install libipc.so.install libipc.a.install src/communication.o.install src/error.o.install src/fs.o.install src/message.o.install src/network.o.install src/print.o.install src/usocket.o.install src/utils.o.install src/communication.o.install src/error.o.install src/fs.o.install src/message.o.install src/network.o.install src/print.o.install src/usocket.o.install src/utils.o.install +install: libipc.install man/libipc.7.install libipc.so.install libipc.a.install src/communication.o.install src/context.o.install src/error.o.install src/fs.o.install src/message.o.install src/network.o.install src/print.o.install src/service_path.o.install src/usocket.o.install src/utils.o.install src/communication.o.install src/context.o.install src/error.o.install src/fs.o.install src/message.o.install src/network.o.install src/print.o.install src/service_path.o.install src/usocket.o.install src/utils.o.install @: -uninstall: libipc.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/communication.o.uninstall src/error.o.uninstall src/fs.o.uninstall src/message.o.uninstall src/network.o.uninstall src/print.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/communication.o.uninstall src/error.o.uninstall src/fs.o.uninstall src/message.o.uninstall src/network.o.uninstall src/print.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall +uninstall: libipc.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/communication.o.uninstall src/context.o.uninstall src/error.o.uninstall src/fs.o.uninstall src/message.o.uninstall src/network.o.uninstall src/print.o.uninstall src/service_path.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/communication.o.uninstall src/context.o.uninstall src/error.o.uninstall src/fs.o.uninstall src/message.o.uninstall src/network.o.uninstall src/print.o.uninstall src/service_path.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall @: -clean: libipc.clean man/libipc.7.clean libipc.so.clean libipc.a.clean src/communication.o.clean src/error.o.clean src/fs.o.clean src/message.o.clean src/network.o.clean src/print.o.clean src/usocket.o.clean src/utils.o.clean src/communication.o.clean src/error.o.clean src/fs.o.clean src/message.o.clean src/network.o.clean src/print.o.clean src/usocket.o.clean src/utils.o.clean +clean: libipc.clean man/libipc.7.clean libipc.so.clean libipc.a.clean src/communication.o.clean src/context.o.clean src/error.o.clean src/fs.o.clean src/message.o.clean src/network.o.clean src/print.o.clean src/service_path.o.clean src/usocket.o.clean src/utils.o.clean src/communication.o.clean src/context.o.clean src/error.o.clean src/fs.o.clean src/message.o.clean src/network.o.clean src/print.o.clean src/service_path.o.clean src/usocket.o.clean src/utils.o.clean distclean: clean dist: dist-gz dist-xz dist-bz2 $(Q)rm -- $(PACKAGE)-$(VERSION) @@ -235,11 +259,13 @@ $(PACKAGE)-$(VERSION).tar.gz: distdir $(PACKAGE)-$(VERSION)/Makefile \ $(PACKAGE)-$(VERSION)/project.zsh \ $(PACKAGE)-$(VERSION)/src/communication.c \ + $(PACKAGE)-$(VERSION)/src/context.c \ $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/fs.c \ $(PACKAGE)-$(VERSION)/src/message.c \ $(PACKAGE)-$(VERSION)/src/network.c \ $(PACKAGE)-$(VERSION)/src/print.c \ + $(PACKAGE)-$(VERSION)/src/service_path.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ $(PACKAGE)-$(VERSION)/src/ipc.h \ @@ -259,11 +285,13 @@ $(PACKAGE)-$(VERSION).tar.xz: distdir $(PACKAGE)-$(VERSION)/Makefile \ $(PACKAGE)-$(VERSION)/project.zsh \ $(PACKAGE)-$(VERSION)/src/communication.c \ + $(PACKAGE)-$(VERSION)/src/context.c \ $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/fs.c \ $(PACKAGE)-$(VERSION)/src/message.c \ $(PACKAGE)-$(VERSION)/src/network.c \ $(PACKAGE)-$(VERSION)/src/print.c \ + $(PACKAGE)-$(VERSION)/src/service_path.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ $(PACKAGE)-$(VERSION)/src/ipc.h \ @@ -283,11 +311,13 @@ $(PACKAGE)-$(VERSION).tar.bz2: distdir $(PACKAGE)-$(VERSION)/Makefile \ $(PACKAGE)-$(VERSION)/project.zsh \ $(PACKAGE)-$(VERSION)/src/communication.c \ + $(PACKAGE)-$(VERSION)/src/context.c \ $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/fs.c \ $(PACKAGE)-$(VERSION)/src/message.c \ $(PACKAGE)-$(VERSION)/src/network.c \ $(PACKAGE)-$(VERSION)/src/print.c \ + $(PACKAGE)-$(VERSION)/src/service_path.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ $(PACKAGE)-$(VERSION)/src/ipc.h \ diff --git a/README.md b/README.md index 1dccfcc..774d0d5 100644 --- a/README.md +++ b/README.md @@ -16,3 +16,32 @@ Logs are in one of the following directories: `$XDG_DATA_HOME/ipc/` or `$HOME/.l The log file can be indicated with the `IPC_LOGFILE` environment variable, too. To remove logs: `make LDFLAGS=-DIPC_WITHOUT_ERRORS` + +# Since 0.7 + +- `libipc` have callbacks to use along with switching capabilities, making easier to implement proxies for different communication protocols + +# Planning for 0.8 + +For performance improvements within `libipc`: + +- `libipc` shouldn't use realloc for each event (new client, new message, etc.) but by batch of a few thousand elements +- `libipc` should use better internal structures, unrequiring the use of loops (over the whole list of messages or connections) for each action + +# Planning for 0.9 + +- `libipc` should use `libevent` for performance improvments +- `libipc` should be thread-safe + +# Planning for 1.0 + +- `libipc` *may* be written in Zig +- `libipc` should have usable bindings in several languages + + +# Implementation design + +## Memory management + +1. Prefer stack over mallocs. +2. Basic functions (such as *usock_*) should not handle memory allocation. diff --git a/examples/pong.c b/examples/pong.c index d39ec74..6b738cc 100644 --- a/examples/pong.c +++ b/examples/pong.c @@ -23,14 +23,14 @@ void chomp (char *str, ssize_t len) } } -struct ipc_connection_info *srv; +struct ipc_ctx *ctx = NULL; -void non_interactive (int verbosity, size_t nb_msg, char *msg_str, char *env[]) +void non_interactive (int verbosity, size_t nb_msg, char *msg_str) { SECURE_DECLARATION (struct ipc_message, m); // init service - TEST_IPC_QUIT_ON_ERROR (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE); + TEST_IPC_QUIT_ON_ERROR (ipc_connection (ctx, SERVICE_NAME), EXIT_FAILURE); if (verbosity > 1) { printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen (MSG) + 1, (int)strlen (MSG), MSG); @@ -38,9 +38,9 @@ void non_interactive (int verbosity, size_t nb_msg, char *msg_str, char *env[]) for (size_t i = 0 ; i < nb_msg ; i++) { TEST_IPC_QUIT_ON_ERROR (ipc_message_format_data (&m, 42, msg_str, (ssize_t) strlen (msg_str) + 1), EXIT_FAILURE); - TEST_IPC_QUIT_ON_ERROR (ipc_write (srv, &m), EXIT_FAILURE); + TEST_IPC_QUIT_ON_ERROR (ipc_write_fd (ctx->pollfd[0].fd, &m), EXIT_FAILURE); ipc_message_empty (&m); - TEST_IPC_QUIT_ON_ERROR (ipc_read (srv, &m), EXIT_FAILURE); + TEST_IPC_QUIT_ON_ERROR (ipc_read (ctx, 0 /* read from the only valid index */, &m), EXIT_FAILURE); if (verbosity > 1) { printf ("msg recv (type: %u): %s\n", m.user_type, m.payload); @@ -48,30 +48,28 @@ void non_interactive (int verbosity, size_t nb_msg, char *msg_str, char *env[]) ipc_message_empty (&m); } - TEST_IPC_QUIT_ON_ERROR (ipc_close (srv), EXIT_FAILURE); + TEST_IPC_QUIT_ON_ERROR (ipc_close_all (ctx), EXIT_FAILURE); } -void interactive (char *env[]) +void interactive () { // init service - TEST_IPC_QUIT_ON_ERROR (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE); + TEST_IPC_QUIT_ON_ERROR (ipc_connection (ctx, SERVICE_NAME), EXIT_FAILURE); SECURE_DECLARATION (struct ipc_error, ret); SECURE_DECLARATION (struct ipc_event, event); - SECURE_DECLARATION (struct ipc_connection_infos, services); - ipc_add (&services, srv); - ipc_add_fd (&services, 0); // add STDIN + ipc_add_fd (ctx, 0); // add STDIN - ipc_connections_print (&services); + ipc_ctx_print (ctx); - long timer = 10; + int timer = 10000; while (1) { printf ("msg to send: "); fflush (stdout); - TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE); + TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (ctx, &event, &timer), EXIT_FAILURE); switch (event.type) { case IPC_EVENT_TYPE_EXTRA_SOCKET: { @@ -80,7 +78,7 @@ void interactive (char *env[]) char buf[4096]; memset (buf, 0, 4096); - len = read (event.origin->fd, buf, 4096); + len = read (event.origin, buf, 4096); buf[len - 1] = '\0'; chomp (buf, len); @@ -93,13 +91,13 @@ void interactive (char *env[]) // in case we want to quit the program if (len == 0 || strncmp (buf, "quit", 4) == 0 || strncmp (buf, "exit", 4) == 0) { - struct ipc_error ret = ipc_close (srv); + struct ipc_error ret = ipc_close_all (ctx); if (ret.error_code != IPC_ERROR_NONE) { fprintf (stderr, "%s", ret.error_message); exit (EXIT_FAILURE); } - ipc_connections_free (&services); + ipc_ctx_free (ctx); exit (EXIT_SUCCESS); } @@ -116,7 +114,7 @@ void interactive (char *env[]) printf ("\n"); printf ("right before sending a message\n"); #endif - ret = ipc_write (srv, m); + ret = ipc_write (ctx, m); if (ret.error_code != IPC_ERROR_NONE) { fprintf (stderr, "%s", ret.error_message); exit (EXIT_FAILURE); @@ -145,24 +143,17 @@ void interactive (char *env[]) } } -int main (int argc, char *argv[], char *env[]) +int main (int argc, char *argv[]) { printf("usage: %s [verbosity #messages message]", argv[0]); - // $0: - argv = argv; // warnings - - 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; + ctx = malloc (sizeof (struct ipc_ctx)); + memset (ctx, 0, sizeof (struct ipc_ctx)); if (argc == 4) - non_interactive (atoi(argv[1]), (size_t) atoi(argv[2]), argv[3], env); + non_interactive (atoi(argv[1]), (size_t) atoi(argv[2]), argv[3]); else - interactive (env); + interactive (); return EXIT_SUCCESS; } diff --git a/examples/pongd.c b/examples/pongd.c index fa80447..6b9e307 100644 --- a/examples/pongd.c +++ b/examples/pongd.c @@ -12,36 +12,47 @@ fprintf(stderr, "error while %s: %s\n", msg, ret.error_message);\ } +/** + * ipc_ctx: + * cinfos: array of ipc_connection_info + * pollfd: array of `pollfd` structure + * Both arrays share the same indices. + */ + +/** + ****************************************************************************** + * Overview of the main loop: + * 1. "ctx" pointer declaration (struct ipc_ctx). + * 1. ipc_server_init (ctx, SERVICE_NAME) + ****************************************************************************** + */ + int cpt = 0; int verbosity = 1; -struct ipc_connection_info *srv = NULL; -struct ipc_connection_infos *clients = NULL; +struct ipc_ctx *ctx = NULL; void main_loop () { - double base_timer = 0; - double timer = base_timer; + int base_timer = 10000; + int timer = base_timer; SECURE_DECLARATION (struct ipc_error, ret); - clients = malloc (sizeof (struct ipc_connection_infos)); - memset (clients, 0, sizeof (struct ipc_connection_infos)); - SECURE_DECLARATION (struct ipc_event, event); event.type = IPC_EVENT_TYPE_NOT_SET; while (1) { - // ipc_service_poll_event provides one event at a time + // 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, &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); } }; break; @@ -49,11 +60,8 @@ 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 - free (event.origin); }; break; case IPC_EVENT_TYPE_MESSAGE: @@ -68,13 +76,10 @@ void main_loop () } } - ret = ipc_write (event.origin, m); + ret = ipc_write (ctx, m); if (ret.error_code != IPC_ERROR_NONE) { PRINTERR (ret, "server write"); } - if (verbosity > 1) { - printf ("message sent\n"); - } }; break; case IPC_EVENT_TYPE_TIMER:{ @@ -86,13 +91,17 @@ void main_loop () case IPC_EVENT_TYPE_ERROR: { cpt--; - fprintf (stderr, "a problem happened with client %d (now disconnected)", (event.origin)->fd); - fprintf (stderr, ", %d clients remaining\n", cpt); - - // free the ipc_client structure - free (event.origin); + fprintf (stderr, "a problem happened with client %d (now disconnected)", event.origin); + fprintf (stderr, ", %d ctx remaining\n", cpt); }; break; + case IPC_EVENT_TYPE_TX: + { + if (verbosity > 1) { + printf ("a message was sent\n"); + } + } + break; default: { fprintf (stderr, "there must be a problem, event not set\n"); @@ -108,70 +117,49 @@ 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]; - if (cli != NULL) { - free (cli); - } - clients->cinfos[i] = NULL; - } - - ipc_connections_free (clients); - free (clients); - // the application will shut down, and close the service - struct ipc_error ret = ipc_server_close (srv); + struct ipc_error ret = ipc_close_all (ctx); if (ret.error_code != IPC_ERROR_NONE) { PRINTERR (ret, "server close"); } - free (srv); + + ipc_ctx_free (ctx); + free (ctx); exit (EXIT_SUCCESS); } /* - * 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 */ -int main (int argc, char *argv[], char **env) +int main (int argc, char *argv[]) { - argc = argc; // warnings - argv = argv; // warnings - if (argc > 1) { verbosity = atoi(argv[1]); } 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; + ctx = malloc (sizeof (struct ipc_ctx)); + memset (ctx, 0, sizeof (struct ipc_ctx)); - struct ipc_error ret = ipc_server_init (env, srv, PONGD_SERVICE_NAME); + struct ipc_error ret = ipc_server_init (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/examples/pongspam.c b/examples/pongspam.c index 64a4595..2f9cb42 100644 --- a/examples/pongspam.c +++ b/examples/pongspam.c @@ -23,52 +23,51 @@ void chomp (char *str, ssize_t len) } } -struct ipc_connection_info *srv; +struct ipc_ctx *ctx = NULL; -void non_interactive (char *env[]) +void non_interactive () { SECURE_DECLARATION (struct ipc_message, m); // init service - TEST_IPC_Q (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE); + TEST_IPC_Q (ipc_connection (ctx, SERVICE_NAME), EXIT_FAILURE); TEST_IPC_Q (ipc_message_format_data (&m, 42, MSG, (ssize_t) strlen (MSG) + 1), EXIT_FAILURE); printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen (MSG) + 1, (int)strlen (MSG), MSG); - TEST_IPC_Q (ipc_write (srv, &m), EXIT_FAILURE); + // ipc_write fd: write a message without fd availability check. + TEST_IPC_Q (ipc_write_fd (ctx->pollfd[0].fd, &m), EXIT_FAILURE); ipc_message_empty (&m); - TEST_IPC_Q (ipc_read (srv, &m), EXIT_FAILURE); + TEST_IPC_Q (ipc_read (ctx, 0 /* only valid index */, &m), EXIT_FAILURE); printf ("msg recv (type: %u): %s\n", m.user_type, m.payload); ipc_message_empty (&m); - TEST_IPC_Q (ipc_close (srv), EXIT_FAILURE); + TEST_IPC_Q (ipc_close_all (ctx), EXIT_FAILURE); } -void interactive (char *env[]) +void interactive () { // init service - TEST_IPC_Q (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE); + TEST_IPC_Q (ipc_connection (ctx, SERVICE_NAME), EXIT_FAILURE); SECURE_DECLARATION (struct ipc_event, event); - SECURE_DECLARATION (struct ipc_connection_infos, services); - ipc_add (&services, srv); - ipc_add_fd (&services, 0); // add STDIN + ipc_add_fd (ctx, 0); // add STDIN - ipc_connections_print (&services); + ipc_ctx_print (ctx); - long timer = 10; + int timer = 10000; while (1) { printf ("msg to send: "); fflush (stdout); - TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE); + TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (ctx, &event, &timer), EXIT_FAILURE); switch (event.type) { case IPC_EVENT_TYPE_TIMER:{ printf ("time up!\n"); - timer = 10; + timer = 10000; }; break; case IPC_EVENT_TYPE_EXTRA_SOCKET: @@ -78,7 +77,7 @@ void interactive (char *env[]) char buf[4096]; memset (buf, 0, 4096); - len = read (event.origin->fd, buf, 4096); + len = read (event.origin, buf, 4096); buf[len - 1] = '\0'; chomp (buf, len); @@ -91,9 +90,9 @@ void interactive (char *env[]) // in case we want to quit the program if (len == 0 || strncmp (buf, "quit", 4) == 0 || strncmp (buf, "exit", 4) == 0) { - TEST_IPC_Q (ipc_close (srv), EXIT_FAILURE); + TEST_IPC_Q (ipc_close_all (ctx), EXIT_FAILURE); - ipc_connections_free (&services); + ipc_ctx_free (ctx); exit (EXIT_SUCCESS); } @@ -107,6 +106,7 @@ void interactive (char *env[]) len = strlen (buf); printf ("message %lu, buffer %.*s\n", i, (int)len, buf); TEST_IPC_Q (ipc_message_format_data (m, 42, buf, len), EXIT_FAILURE); + m->fd = ctx->pollfd[0].fd; printf ("message from structure: %.*s\n", m->length, m->payload); @@ -114,7 +114,7 @@ void interactive (char *env[]) printf ("\n"); printf ("right before sending a message\n"); #endif - TEST_IPC_Q (ipc_write (srv, m), EXIT_FAILURE); + TEST_IPC_Q (ipc_write (ctx, m), EXIT_FAILURE); #if 0 printf ("right after sending a message\n"); #endif @@ -125,6 +125,11 @@ void interactive (char *env[]) free (m); } break; + case IPC_EVENT_TYPE_TX: + { + printf ("a message was sent\n"); + } + break; case IPC_EVENT_TYPE_MESSAGE: { struct ipc_message *m = event.m; @@ -141,22 +146,18 @@ void interactive (char *env[]) } } -int main (int argc, char *argv[], char *env[]) +int main (int argc, char **argv) { - argc = argc; // warnings - argv = argv; // warnings + // Compilers fuckery. + argv = argv; - 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; + ctx = malloc (sizeof (struct ipc_ctx)); + memset (ctx, 0, sizeof (struct ipc_ctx)); if (argc == 1) - non_interactive (env); + non_interactive (); else - interactive (env); + interactive (); return EXIT_SUCCESS; } diff --git a/examples/simple-tcp-client.c b/examples/simple-tcp-client.c index 77dad9e..e39d684 100644 --- a/examples/simple-tcp-client.c +++ b/examples/simple-tcp-client.c @@ -64,7 +64,9 @@ void send_receive (int sockfd) // 2 | 6 | 0 | "coucou" // 1 B | 4 B | 1 | 6 B ipc_message_raw_serialize ((char *)buf, MSG_TYPE_DATA, 42, "coucou", 6); - print_hexa ("WAITING 10 seconds then message to send", buf, 12); + printf("\n"); + print_hexa ("message to send", buf, 12); + printf("\n"); // sleep (1); T_PERROR_Q ((send (sockfd, buf, 12, 0) == -1), "sending a message", EXIT_FAILURE); printf ("message 'coucou' sent\n"); @@ -72,6 +74,7 @@ void send_receive (int sockfd) // receiving a message T_PERROR_Q (((paylen = recv (sockfd, buf, BUFSIZ, 0)) < 0), "receiving a message", EXIT_FAILURE); + printf("\n"); if (paylen == 0) { fprintf (stderr, "error: disconnection from the server\n"); @@ -96,7 +99,7 @@ int main (int argc, char *argv[]) send_receive (sockfd); - printf ("Disconnection\n"); + printf ("\nDisconnection\n"); // close the socket close (sockfd); diff --git a/examples/simple-tcpd.c b/examples/simple-tcpd.c index 9319230..1811021 100644 --- a/examples/simple-tcpd.c +++ b/examples/simple-tcpd.c @@ -42,7 +42,7 @@ void chomp (char *str, size_t len) else connection from the client: 1. client sends service name - 2. networkd establishes a connection to the service + 2. ipcd establishes a connection to the service 3. ack else lolwat shouldn't happen :( @@ -52,26 +52,26 @@ void chomp (char *str, size_t len) #define SERVICE_NAME "simpletcp" -struct networkd *ctx; +struct ipc_ctx *ctx = NULL; void handle_disconnection (int fd) { int delfd; - delfd = ipc_switching_del (ctx->TCP_TO_IPC, fd); + delfd = ipc_switching_del (&ctx->switchdb, fd); if (delfd >= 0) { close (delfd); - ipc_del_fd (ctx->clients, delfd); + ipc_del_fd (ctx, delfd); } close (fd); - ipc_del_fd (ctx->clients, fd); + ipc_del_fd (ctx, fd); - // printf ("TCP_TO_IPC\n"); - ipc_switching_print (ctx->TCP_TO_IPC); + // printf ("ctx.switchdb\n"); + ipc_switching_print (&ctx->switchdb); } -void tcp_connection (char **env, int fd) +void tcp_connection (int fd) { SECURE_BUFFER_DECLARATION (char, buf, BUFSIZ); @@ -89,16 +89,15 @@ void tcp_connection (char **env, int fd) // TODO: tests T_PERROR_Q ((send (fd, "OK", 2, 0) <= 0), "sending a message", EXIT_FAILURE); - SECURE_DECLARATION (struct ipc_connection_info, tcp_to_ipc_ci); - - struct ipc_error ret = ipc_connection (env, &tcp_to_ipc_ci, buf); + printf ("connection to %s\n", buf); + struct ipc_error ret = ipc_connection_switched (ctx, buf); if (ret.error_code != IPC_ERROR_NONE) { fprintf (stderr, "%s\n", ret.error_message); exit (EXIT_FAILURE); } - ipc_switching_add (ctx->TCP_TO_IPC, fd, tcp_to_ipc_ci.fd); - ipc_add_fd (ctx->clients, tcp_to_ipc_ci.fd); + ipc_switching_add (&ctx->switchdb, fd, ctx->pollfd[ctx->size-1].fd); + ipc_ctx_fd_type (ctx, fd, IPC_CONNECTION_TYPE_SWITCHED); } int accept_new_client (int serverfd) @@ -111,13 +110,14 @@ int accept_new_client (int serverfd) accept (serverfd, (struct sockaddr *)&client, &addrlen)) == -1), "accept new client", EXIT_FAILURE); - // adding a client - ipc_add_fd (ctx->clients, sock_fd_client); + // adding a client, for now not switched: + // tcpd should handle the first message (getting the service name) + ipc_add_fd (ctx, sock_fd_client); return sock_fd_client; } -void main_loop (int argc, char **argv, char **env) +void main_loop (int argc, char **argv) { argc = argc; // FIXME: useless int serverfd; @@ -155,80 +155,89 @@ void main_loop (int argc, char **argv, char **env) return; } - SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->clients, sizeof (struct ipc_connection_infos),, EXIT_FAILURE); SECURE_DECLARATION (struct ipc_event, event); - ipc_add_fd (ctx->clients, serverfd); + ipc_add_fd (ctx, serverfd); + int cpt = 0; + + int timer = 10000; while (1) { // ipc_wait_event provides one event at a time // warning: event->m is free'ed if not NULL - long timer = 10; - TEST_IPC_WAIT_EVENT_Q (ipc_wait_event_networkd (ctx->clients, ctx->srv, &event, ctx->TCP_TO_IPC, &timer) - , EXIT_FAILURE); + ipc_ctx_print (ctx); + TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (ctx, &event, &timer), EXIT_FAILURE); switch (event.type) { case IPC_EVENT_TYPE_TIMER:{ printf ("timed out!\n"); - - timer = 10; + timer = 10000; } break; + case IPC_EVENT_TYPE_SWITCH:{ - printf ("switch happened\n"); + printf ("switch happened, from %d\n", event.origin); } break; case IPC_EVENT_TYPE_EXTRA_SOCKET: { // NEW CLIENT - if (event.origin->fd == serverfd) { + if (event.origin == serverfd) { int sock_fd_client = accept_new_client (serverfd); - ctx->cpt++; - printf ("TCP connection: %d clients connected\n", ctx->cpt); + cpt++; + printf ("TCP connection: %d ctx connected\n", cpt); printf ("new TCP client has the fd %d\n", sock_fd_client); } // CLIENT IS TALKING else { - tcp_connection (env, event.origin->fd); + // Test: if the socket already is in the switch, this means we can just switch the packet. + // Is the socket in the switch db? + tcp_connection (event.origin); } } break; case IPC_EVENT_TYPE_CONNECTION: { - ctx->cpt++; - printf ("connection: %d clients connected\n", ctx->cpt); - printf ("new client has the fd %d\n", (event.origin)->fd); + cpt++; + printf ("connection: %d ctx connected\n", cpt); + printf ("new client has the fd %d\n", event.origin); }; break; case IPC_EVENT_TYPE_DISCONNECTION: { - ctx->cpt--; - printf ("disconnection: %d clients remaining\n", ctx->cpt); - - // free the ipc_client structure - // if (event.origin != NULL) - // free (event.origin); + cpt--; + printf ("disconnection: %d ctx remaining\n", cpt); }; break; + case IPC_EVENT_TYPE_MESSAGE: { struct ipc_message *m = event.m; if (m->length > 0) { printf ("message received (type %d): %.*s\n", m->type, m->length, m->payload); } - - TEST_IPC_P (ipc_write (event.origin, m), "server write"); + // m->fd = 3; + TEST_IPC_P (ipc_write (ctx, m), "server write"); }; break; - case IPC_EVENT_TYPE_ERROR: - fprintf (stderr, "a problem happened with client %d\n", (event.origin)->fd); + + case IPC_EVENT_TYPE_TX: + { + printf ("a message was sent\n"); + } break; + + case IPC_EVENT_TYPE_ERROR: + fprintf (stderr, "a problem happened with client %d\n", event.origin); + break; + default: - fprintf (stderr, "there must be a problem, event not set\n"); + fprintf (stderr, "there must be a problem, event not set: %d\n", event.type); + exit(1); } } @@ -240,36 +249,22 @@ void exit_program (int signal) { printf ("Quitting, signal: %d\n", signal); - // free remaining clients - for (size_t i = 0; i < ctx->clients->size; i++) { - struct ipc_connection_info *cli = ctx->clients->cinfos[i]; - if (cli != NULL) { - free (cli); - } - ctx->clients->cinfos[i] = NULL; - } - - ipc_connections_free (ctx->clients); - - // the application will shut down, and close the service - TEST_IPC_P (ipc_server_close (ctx->srv), "server close"); + // Close then free remaining ctx. + ipc_close_all (ctx); + ipc_ctx_free (ctx); // free, free everything! - free (ctx->clients); - free (ctx->srv); - free (ctx->TCP_TO_IPC->collection); - free (ctx->TCP_TO_IPC); free (ctx); exit (EXIT_SUCCESS); } /* - * 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 */ -int main (int argc, char *argv[], char **env) +int main (int argc, char *argv[]) { // check the number of args on command line if (argc != 2) { @@ -279,17 +274,15 @@ int main (int argc, char *argv[], char **env) printf ("pid = %d\n", getpid ()); - SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx, sizeof (struct networkd) ,, EXIT_FAILURE); - SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->TCP_TO_IPC, sizeof (struct ipc_switchings) ,, EXIT_FAILURE); - SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->TCP_TO_IPC->collection, sizeof (struct ipc_switching) ,, EXIT_FAILURE); - SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->srv, sizeof (struct ipc_connection_info),, EXIT_FAILURE); + ctx = malloc (sizeof (struct ipc_ctx)); + memset(ctx, 0, sizeof (struct ipc_ctx)); - struct ipc_error ret = ipc_server_init (env, ctx->srv, SERVICE_NAME); + struct ipc_error ret = ipc_server_init (ctx, SERVICE_NAME); if (ret.error_code != IPC_ERROR_NONE) { fprintf (stderr, "%s\n", ret.error_message); return EXIT_FAILURE; } - printf ("Listening on [%s].\n", ctx->srv->spath); + printf ("Listening on [%s].\n", ctx->cinfos[0].spath); printf ("MAIN: server created\n"); @@ -301,7 +294,7 @@ int main (int argc, char *argv[], char **env) signal (SIGINT , exit_program); // the service will loop until the end of time, or a signal - main_loop (argc, argv, env); + main_loop (argc, argv); // main_loop should not return return EXIT_FAILURE; diff --git a/examples/test-ask-for-fd-to-networkd.c b/examples/test-ask-for-fd-to-networkd.c index b64ff5e..7754cec 100644 --- a/examples/test-ask-for-fd-to-networkd.c +++ b/examples/test-ask-for-fd-to-networkd.c @@ -6,30 +6,27 @@ int main (int argc, char *argv[]) { - (void)argc; - (void)argv; - - SECURE_DECLARATION (struct ipc_error, ret); - SECURE_DECLARATION (struct ipc_connection_info, srv); - if (argc != 2) { fprintf (stderr, "usage: %s service_name\n", argv[0]); exit (1); } + SECURE_DECLARATION (struct ipc_error, ret); + int fd = 0; + char *service_name = argv[1]; - ret = ipc_contact_networkd (&srv, service_name); + ret = ipc_contact_ipcd (&fd, service_name); printf ("ret = %d\n", ret.error_code); - if (ret.error_code == IPC_ERROR_NONE && srv.fd != 0) { + if (ret.error_code == IPC_ERROR_NONE && fd > 0) { printf ("Success\n"); } else { printf ("Ow. :(\n"); } - usock_close (srv.fd); + usock_close (fd); return EXIT_SUCCESS; } diff --git a/examples/test-networkd-provide-fd.c b/examples/test-networkd-provide-fd.c index 5b8a532..077a288 100644 --- a/examples/test-networkd-provide-fd.c +++ b/examples/test-networkd-provide-fd.c @@ -4,35 +4,32 @@ #include "../src/ipc.h" -int main (int argc, char *argv[], char *env[]) +int main (void) { - (void)argc; - (void)argv; - SECURE_DECLARATION (struct ipc_error, ret); - SECURE_DECLARATION (struct ipc_connection_info, srv); - SECURE_DECLARATION (struct ipc_connection_info, client); - SECURE_DECLARATION (struct ipc_connection_info, contacted_service); + SECURE_DECLARATION (struct ipc_ctx, ctx); + SECURE_DECLARATION (struct ipc_event, event); // service start - TEST_IPC_Q (ipc_server_init (env, &srv, "network"), EXIT_FAILURE); + TEST_IPC_Q (ipc_server_init (&ctx, "ipcd"), EXIT_FAILURE); printf ("service initialized, waiting for a client\n"); // accept a new client - TEST_IPC_Q (ipc_accept (&srv, &client), EXIT_FAILURE); + TEST_IPC_Q (ipc_accept_add (&event, &ctx, 0 /* the only valid index right now */), EXIT_FAILURE); + int client_fd = ctx.pollfd[ctx.size-1].fd; // TODO: read a message to know the requested service SECURE_DECLARATION (struct ipc_message, msg); - TEST_IPC_Q (ipc_read (&client, &msg), EXIT_FAILURE); + TEST_IPC_Q (ipc_read (&ctx, 1 /* 1 = our client */, &msg), EXIT_FAILURE); printf ("received message: %s\n", msg.payload); /** TODO: contact the service */ printf ("WARNING: currently this program only ask for pong service %d\n", ret.error_code); - TEST_IPC_Q (ipc_connection (env, &contacted_service, "pong"), EXIT_FAILURE); + TEST_IPC_Q (ipc_connection (&ctx, "pong"), EXIT_FAILURE); - ipc_provide_fd (client.fd, contacted_service.fd); + ipc_provide_fd (client_fd, ctx.pollfd[ctx.size-1].fd); - TEST_IPC_Q (ipc_server_close (&srv), EXIT_FAILURE); + TEST_IPC_Q (ipc_close_all (&ctx), EXIT_FAILURE); return EXIT_SUCCESS; } diff --git a/examples/wsserver.c b/examples/wsserver.c index e50912e..9a2dd0a 100644 --- a/examples/wsserver.c +++ b/examples/wsserver.c @@ -19,12 +19,13 @@ void chomp (char *str, ssize_t len) } } -struct ipc_connection_info *srv; +struct ipc_ctx *ctx; -void interactive (char *env[]) +void interactive () { - long timer = 10; + int timer = 10000; // 10 seconds + SECURE_DECLARATION (struct ipc_event, event); SECURE_BUFFER_DECLARATION (char, service_name, 100); char *sn = getenv ("PATH_TRANSLATED"); @@ -37,21 +38,17 @@ void interactive (char *env[]) } // init service - TEST_IPC_Q (ipc_connection (env, srv, service_name), EXIT_FAILURE); + TEST_IPC_Q (ipc_connection (ctx, service_name), EXIT_FAILURE); - SECURE_DECLARATION (struct ipc_event, event); - SECURE_DECLARATION (struct ipc_connection_infos, services); - - ipc_add (&services, srv); - ipc_add_fd (&services, 0); // add STDIN + ipc_add_fd (ctx, 0); // add STDIN while (1) { - TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE); + TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (ctx, &event, &timer), EXIT_FAILURE); switch (event.type) { case IPC_EVENT_TYPE_TIMER:{ fprintf (stderr, "time up!\n"); - timer = 10; + timer = 10000; }; break; case IPC_EVENT_TYPE_EXTRA_SOCKET: @@ -60,19 +57,19 @@ void interactive (char *env[]) SECURE_BUFFER_DECLARATION (char, buf, 4096); ssize_t len; - len = read (event.origin->fd, buf, 4096); + len = read (event.origin, buf, 4096); // in case we want to quit the program if (len == 0 || strncmp (buf, "quit", 4) == 0 || strncmp (buf, "exit", 4) == 0) { - TEST_IPC_Q (ipc_close (srv), EXIT_FAILURE); + TEST_IPC_Q (ipc_close_all (ctx), EXIT_FAILURE); - ipc_connections_free (&services); + ipc_ctx_free (ctx); exit (EXIT_SUCCESS); } // send the message read on STDIN - ssize_t len_sent = write (srv->fd, buf, len); + ssize_t len_sent = write (ctx->pollfd[0].fd, buf, len); if (len_sent != len) { fprintf (stderr, "cannot send the message %lu-byte message, sent %lu bytes", len, len_sent); @@ -94,6 +91,10 @@ void interactive (char *env[]) fflush (stdout); }; break; + case IPC_EVENT_TYPE_TX: { + printf ("Message sent\n"); + } + break; ERROR_CASE (IPC_EVENT_TYPE_DISCONNECTION, "main loop", "disconnection: should not happen"); ERROR_CASE (IPC_EVENT_TYPE_NOT_SET , "main loop", "not set: should not happen"); ERROR_CASE (IPC_EVENT_TYPE_CONNECTION , "main loop", "connection: should not happen"); @@ -104,19 +105,12 @@ void interactive (char *env[]) } } -int main (int argc, char *argv[], char *env[]) +int main (void) { - argc = argc; // warnings - argv = argv; // warnings + ctx = malloc (sizeof (struct ipc_ctx)); + memset (ctx, 0, sizeof (struct ipc_ctx)); - 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; - - interactive (env); + interactive (); return EXIT_SUCCESS; } diff --git a/man/libipc.7.scd b/man/libipc.7.scd index 7cdb2b6..8cdb726 100644 --- a/man/libipc.7.scd +++ b/man/libipc.7.scd @@ -34,17 +34,17 @@ _enum ipc_errors_ **ipc_accept** (*struct ipc_connection_info* \*srv, *struct ip _enum ipc_errors_ **ipc_read** (*const struct ipc_connection_info* \*, *struct ipc_message* \*m);++ _enum ipc_errors_ **ipc_write** (*const struct ipc_connection_info* \*, *const struct ipc_message* \*m);++ -_enum ipc_errors_ **ipc_wait_event** (*struct ipc_connection_infos* \*clients, *struct ipc_connection_info* \*srv, *struct ipc_event* \*event); +_enum ipc_errors_ **ipc_wait_event** (*struct ipc_ctx* \*clients, *struct ipc_connection_info* \*srv, *struct ipc_event* \*event); // store and remove only pointers on allocated structures -_enum ipc_errors_ **ipc_add** (*struct ipc_connection_infos* \*cinfos, *struct ipc_connection_info* \*cinfo);++ -_enum ipc_errors_ **ipc_del** (*struct ipc_connection_infos* \*cinfos, *struct ipc_connection_info* \*cinfo); +_enum ipc_errors_ **ipc_add** (*struct ipc_ctx* \*cinfos, *struct ipc_connection_info* \*cinfo);++ +_enum ipc_errors_ **ipc_del** (*struct ipc_ctx* \*cinfos, *struct ipc_connection_info* \*cinfo); // add an arbitrary file descriptor to read -_enum ipc_errors_ **ipc_add_fd** (*struct ipc_connection_infos* \*cinfos, *int* fd); +_enum ipc_errors_ **ipc_add_fd** (*struct ipc_ctx* \*cinfos, *int* fd); ## Message functions @@ -75,7 +75,7 @@ _enum ipc_errors_ **ipc_message_empty** (*struct ipc_message* \*m); char *spath; // max size: PATH_MAX, used to store unix socket path }; - struct ipc_connection_infos { + struct ipc_ctx { struct ipc_connection_info ** cinfos; int32_t size; }; @@ -106,7 +106,7 @@ _enum ipc_errors_ **ipc_message_empty** (*struct ipc_message* \*m); Function **ipc_wait_event** returns an *event type* structure.\ The event may be a (dis)connection, received data or an error.\ -It also can be *IPC_EVENT_TYPE_EXTRA_SOCKET* since an arbitrary file descriptor can be added to the *ipc_connection_infos* structure with **ipc_add_fd**. +It also can be *IPC_EVENT_TYPE_EXTRA_SOCKET* since an arbitrary file descriptor can be added to the *ipc_ctx* structure with **ipc_add_fd**. ``` enum ipc_event_type { diff --git a/project.zsh b/project.zsh index ccc3e60..b13c8d1 100644 --- a/project.zsh +++ b/project.zsh @@ -1,6 +1,6 @@ package=libipc # Package name. -version=0.6.0 # Package version. +version=0.7.0 # Package version. # Our targets are the library and its documentation. targets=(libipc man/libipc.7) diff --git a/src/communication.c b/src/communication.c index bd5eeb1..a686e61 100644 --- a/src/communication.c +++ b/src/communication.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -13,86 +14,53 @@ // print structures #include "message.h" -struct ipc_error service_path (char *path, const char *sname, int32_t index, int32_t version) +#include + +int fd_is_valid(int fd) { - T_R ((path == NULL), IPC_ERROR_SERVICE_PATH__NO_PATH); - T_R ((sname == NULL), IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME); - - memset (path, 0, PATH_MAX); - - char *rundir = getenv ("IPC_RUNDIR"); - if (rundir == NULL) - rundir = RUNDIR; - - snprintf (path, PATH_MAX - 1, "%s/%s-%d-%d", rundir, sname, index, version); - - IPC_RETURN_NO_ERROR; + return fcntl(fd, F_GETFD) != -1 || errno != EBADF; } -static int32_t get_max_fd (struct ipc_connection_infos *cinfos) + +struct ipc_error ipc_server_init (struct ipc_ctx *ctx, const char *sname) { - size_t i; - int32_t max = 0; - - for (i = 0; i < cinfos->size; i++) { - if (cinfos->cinfos[i]->fd > max) { - max = cinfos->cinfos[i]->fd; - } - } - - return max; -} - -struct ipc_error ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname) -{ - T_R ((env == NULL), IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM); - T_R ((srv == NULL), IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM); T_R ((sname == NULL), IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM); -#if 0 - // For server init, no need for networkd evaluation + // 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; - // 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 - - // gets the service path + // Get the service path. SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); - TEST_IPC_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path"); - - // gets the service path - if (srv->spath != NULL) { - free (srv->spath); - srv->spath = NULL; - } - + 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 - 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)); - TEST_IPC_RETURN_ON_ERROR (usock_init (&srv->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; } -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) +// when ipcd is not working properly (or do not retrieve the service): srv->fd = 0 +struct ipc_error ipc_contact_ipcd (int *pfd, const char *sname) { - T_R ((srv == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM); - T_R ((sname == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM); + T_R ((pfd == NULL), IPC_ERROR_CONTACT_IPCD__NO_FD_PARAM); + T_R ((sname == NULL), IPC_ERROR_CONTACT_IPCD__NO_SERVICE_NAME_PARAM); - char *networkvar = getenv ("IPC_NETWORK"); - if (networkvar == NULL) { - srv->fd = 0; + char *ipcd_var = getenv ("IPC_NETWORK"); + if (ipcd_var == NULL) { + *pfd = 0; IPC_RETURN_NO_ERROR; } // TODO: is there another, more interesting way to do this? @@ -100,488 +68,524 @@ struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const ch // in order to route requests over any chosen protocol stack // ex: IPC_NETWORK="audio tor://some.example.com/audio ;pong tls://pong.example.com/pong" - // printf ("IPC_NETWORK: %s\n", networkvar); - SECURE_BUFFER_DECLARATION (char, columnthensname, BUFSIZ); columnthensname[0] = ';'; memcpy (columnthensname + 1, sname, strlen (sname)); - if (strncmp (networkvar, sname, strlen (sname)) != 0 && strstr (networkvar, columnthensname) == NULL) { - // printf ("sname %s not found\n", sname); - srv->fd = 0; + if (strncmp (ipcd_var, sname, strlen (sname)) != 0 && strstr (ipcd_var, columnthensname) == NULL) { + *pfd = 0; IPC_RETURN_NO_ERROR; } - // printf ("(;)sname %s found\n", sname); - // gets the service path + // Get the service path. SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); - TEST_IPC_RR (service_path (buf, "network", 0, 0), "cannot get network service path"); + TEST_IPC_RR (service_path (buf, "network"), "cannot get network service path"); - int networkdfd = 0; + int ipcd_fd = 0; - TEST_IPC_RETURN_ON_ERROR (usock_connect (&networkdfd, buf)); + TEST_IPC_RETURN_ON_ERROR (usock_connect (&ipcd_fd, buf)); SECURE_DECLARATION (struct ipc_message, msg); msg.type = MSG_TYPE_NETWORK_LOOKUP; msg.user_type = MSG_TYPE_NETWORK_LOOKUP; SECURE_BUFFER_DECLARATION (char, content, BUFSIZ); - snprintf (content, BUFSIZ, "%s;%s", sname, networkvar); + snprintf (content, BUFSIZ, "%s;%s", sname, ipcd_var); msg.length = strlen (content); msg.payload = content; - TEST_IPC_RR (ipc_write_fd (networkdfd, &msg), "cannot send a message to networkd"); + TEST_IPC_RR (ipc_write_fd (ipcd_fd, &msg), "cannot send a message to networkd"); - struct ipc_error ret = ipc_receive_fd (networkdfd, &srv->fd); + struct ipc_error ret = ipc_receive_fd (ipcd_fd, pfd); if (ret.error_code == IPC_ERROR_NONE) { - usock_close (networkdfd); + usock_close (ipcd_fd); } return ret; } -struct ipc_error ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname) +// Create context, contact ipcd, connects to the service. +struct ipc_error ipc_connection_ (struct ipc_ctx *ctx, const char *sname, enum ipc_connection_type type, int *serverfd) { - T_R ((env == NULL), IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM); - T_R ((srv == NULL), IPC_ERROR_CONNECTION__NO_SERVER); + T_R ((ctx == NULL), IPC_ERROR_CONNECTION__NO_CTX); T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME); - TEST_IPC_P (ipc_contact_networkd (srv, sname), "error during networkd connection"); + SECURE_DECLARATION(struct ipc_connection_info, srv); + srv.type = type; + SECURE_DECLARATION(struct pollfd, pollfd); + pollfd.events = POLLIN; - // if networkd did not initiate the connection - if (srv->fd <= 0) { + TEST_IPC_P (ipc_contact_ipcd (&pollfd.fd, sname), "error during networkd connection"); + + // if ipcd did not initiate the connection + if (pollfd.fd <= 0) { // gets the service path SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); - TEST_IPC_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path"); - TEST_IPC_RETURN_ON_ERROR (usock_connect (&srv->fd, buf)); + TEST_IPC_RR (service_path (buf, sname), "cannot get server path"); + 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"); + + if (serverfd != NULL) { + *serverfd = pollfd.fd; } IPC_RETURN_NO_ERROR; } -struct ipc_error ipc_server_close (struct ipc_connection_info *srv) +int ipc_ctx_fd_type (struct ipc_ctx *ctx, int fd, enum ipc_connection_type type) { - usock_close (srv->fd); - struct ipc_error ret = usock_remove (srv->spath); - if (srv->spath != NULL) { - free (srv->spath); - srv->spath = NULL; + if (ctx == NULL) { + return -1; } + + for (size_t i = 0; i < ctx->size; i++) { + if (ctx->pollfd[i].fd == fd) { + ctx->cinfos[i].type = type; + return 0; + } + } + return -1; +} + +struct ipc_error ipc_connection (struct ipc_ctx *ctx, const char *sname) +{ + // Data received on the socket = messages, not new clients, and not switched (no callbacks). + return ipc_connection_ (ctx, sname, IPC_CONNECTION_TYPE_IPC, NULL); +} + +struct ipc_error ipc_connection_switched (struct ipc_ctx *ctx, const char *sname, int clientfd, int *serverfd) +{ + int sfd = 0; + // Data received are for switched fd (callbacks should be used). + struct ipc_error ret = ipc_connection_ (ctx + , sname + , IPC_CONNECTION_TYPE_SWITCHED + , &sfd); + + if (ret.error_code != IPC_ERROR_NONE) { + return ret; + } + + if (serverfd != NULL) { + *serverfd = sfd; + } + + ipc_add_fd_switched (ctx, clientfd); + // ipc_ctx_fd_type (ctx, clientfd, IPC_CONNECTION_TYPE_SWITCHED); + ipc_ctx_switching_add (ctx, clientfd, sfd); + return ret; } -struct ipc_error ipc_close (struct ipc_connection_info *p) +struct ipc_error ipc_close_all (struct ipc_ctx *ctx) { - return usock_close (p->fd); + T_R ((ctx == NULL), IPC_ERROR_CLOSE_ALL__NO_CTX_PARAM); + + for (size_t i = 0 ; i < ctx->size ; i++) { + TEST_IPC_P (ipc_close (ctx, i), "cannot close a connection in handle_message"); + } + + IPC_RETURN_NO_ERROR; } -struct ipc_error ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p) +struct ipc_error ipc_close (struct ipc_ctx *ctx, uint32_t index) { - T_R ((srv == NULL), IPC_ERROR_ACCEPT__NO_SERVICE_PARAM); - T_R ((p == NULL), IPC_ERROR_ACCEPT__NO_CLIENT_PARAM); + T_R ((ctx == NULL), IPC_ERROR_CLOSE__NO_CTX_PARAM); - TEST_IPC_RR (usock_accept (srv->fd, &p->fd), "cannot accept IPC connection"); - p->type = IPC_CONNECTION_TYPE_IPC; + SECURE_DECLARATION (struct ipc_error, ret); + int fd = ctx->pollfd[index].fd; + +#if 0 + if (fd_is_valid (fd)) { + printf ("ipc_close: fd is valid ==> %d\n", fd); + + if (ctx->cinfos[index].type == IPC_CONNECTION_TYPE_EXTERNAL) { + printf ("=== === === external fd: not closing %d\n", fd); + } + else { + ret = usock_close (fd); + } + } + else { + printf ("!!!!!!!!!!! !! !! !! IPC_CLOSE: fd is not valid!! ==> %d\n", fd); + } +#else + // Closing the file descriptor only if it is not an external connection, + // this should be handled by the libipc user application. + if (ctx->cinfos[index].type != IPC_CONNECTION_TYPE_EXTERNAL) { + ret = usock_close (fd); + } +#endif + + // Verify that the close was OK. + if (ret.error_code != IPC_ERROR_NONE) { + return ret; + } + + if (ctx->cinfos[index].type == IPC_CONNECTION_TYPE_SERVER) { + ret = usock_remove (ctx->cinfos[index].spath); + if (ctx->cinfos[index].spath != NULL) { + free (ctx->cinfos[index].spath); + ctx->cinfos[index].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; + + // Set the event structure. + uint32_t client_index = ctx->size - 1; + IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, client_index, *client_fd, NULL); 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; + SECURE_BUFFER_DECLARATION (char, buf, msize); + char *pbuf = buf; - // on error or closed recipient, the buffer already freed - TEST_IPC_RETURN_ON_ERROR (usock_recv (p->fd, &buf, &msize)); - TEST_IPC_RETURN_ON_ERROR_FREE (ipc_message_format_read (m, buf, msize), buf); - - free (buf); + // On error or closed recipient, the buffer already freed. + TEST_IPC_RETURN_ON_ERROR (usock_recv (ctx->pollfd[index].fd, &pbuf, &msize)); + TEST_IPC_RETURN_ON_ERROR (ipc_message_format_read (m, buf, msize)); IPC_RETURN_NO_ERROR; // propagates ipc_message_format return } struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m) { - T_R ((m == NULL), IPC_ERROR_WRITE__NO_MESSAGE_PARAM); - - char *buf = NULL; size_t msize = 0; - ipc_message_format_write (m, &buf, &msize); + SECURE_BUFFER_DECLARATION (char, buf, IPC_MAX_MESSAGE_SIZE); + char *pbuf = buf; + + ipc_message_format_write (m, &pbuf, &msize); size_t nbytes_sent = 0; - TEST_IPC_RETURN_ON_ERROR_FREE (usock_send (fd, buf, msize, &nbytes_sent), buf); + TEST_IPC_RETURN_ON_ERROR (usock_send (fd, buf, msize, &nbytes_sent)); - if (buf != NULL) { - free (buf); - } // what was sent != what should have been sent - T_R ((nbytes_sent != msize), IPC_ERROR_WRITE__NOT_ENOUGH_DATA); + T_R ((nbytes_sent != msize), IPC_ERROR_WRITE_FD__NOT_ENOUGH_DATA); IPC_RETURN_NO_ERROR; } -struct ipc_error ipc_write (const struct ipc_connection_info *p, const struct ipc_message *m) +// Put the message in the list of messages to send. +struct ipc_error ipc_write (struct ipc_ctx *ctx, const struct ipc_message *m) { - return ipc_write_fd (p->fd, m); -} - -struct ipc_error handle_new_connection (struct ipc_connection_info *cinfo, struct ipc_connection_infos *cinfos - , struct ipc_connection_info **new_client) -{ - T_R ((cinfo == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM); - T_R ((cinfos == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM); - - SECURE_BUFFER_HEAP_ALLOCATION_R (*new_client, sizeof (struct ipc_connection_info),, - IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC); - - 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"); - - IPC_RETURN_NO_ERROR; -} - -// new connection from a client -struct ipc_error handle_connection (struct ipc_event *event, struct ipc_connection_infos *cinfos - , struct ipc_connection_info *cinfo) -{ - // connection - struct ipc_connection_info *new_client = NULL; - - TEST_IPC_RR (handle_new_connection (cinfo, cinfos, &new_client), "cannot add new client"); - - IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client); - IPC_RETURN_NO_ERROR; -} - -// new message -struct ipc_error handle_message (struct ipc_event *event, struct ipc_connection_infos *cinfos - , struct ipc_connection_info *pc, struct ipc_switchings *switchdb) -{ - // if the socket is associated to another one for networkd - // read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch - if (switchdb != NULL) { - int talkingfd = pc->fd; - int correspondingfd = ipc_switching_get (switchdb, talkingfd); - if (correspondingfd != -1) { - char *buf = NULL; - size_t msize = 0; - - TEST_IPC_T_P_I_R ( - /* function to test */ usock_recv (talkingfd, &buf, &msize) - , /* error condition */ ret.error_code != IPC_ERROR_NONE - && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT - , /* to do on error */ if (buf != NULL) free (buf); - IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc) - , /* return function */ return (ret)) ; - - /** TODO: there is a message, send it to the corresponding fd **/ - if (msize > 0) { - size_t nbytes_sent = 0; - TEST_IPC_RETURN_ON_ERROR_FREE (usock_send (correspondingfd, buf, msize, &nbytes_sent), buf); - - if (nbytes_sent != msize) { - // LOG_ERROR ("wrote not enough data from %d to fd %d", talkingfd, correspondingfd); - IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc); - IPC_RETURN_NO_ERROR; // FIXME: return something else, maybe? - } - // LOG_DEBUG ("received a message on fd %d => switch to fd %d", talkingfd, correspondingfd); - - if (buf != NULL) - free (buf); - - // everything is OK: inform networkd of a successful transfer - IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, NULL, pc); - IPC_RETURN_NO_ERROR; - } else if (msize == 0) { - int delfd; - - delfd = ipc_switching_del (switchdb, talkingfd); - if (delfd >= 0) { - close (delfd); - ipc_del_fd (cinfos, delfd); - } - - close (talkingfd); - ipc_del_fd (cinfos, talkingfd); - -#if 0 - if (delfd >= 0) { - LOG_DEBUG ("disconnection of %d (and related fd %d)", talkingfd, delfd); - } else { - LOG_DEBUG ("disconnection of %d", talkingfd); - } -#endif - - IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc); - IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT); - } + int found = 0; + for (size_t i = 0; i < ctx->size; i++) { + if (ctx->pollfd[i].fd == m->fd) { + ctx->pollfd[i].events |= POLLOUT; + found = 1; } } - // no treatment of the socket if external socket - if (pc->type == IPC_CONNECTION_TYPE_EXTERNAL) { - IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, NULL, pc); + + T_R ((found == 0), IPC_ERROR_WRITE__FD_NOT_FOUND); + + // Performs a deep copy of the structure. + return ipc_messages_add (&ctx->tx, m); +} + +/** + * 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); + T_R ((pollfd == NULL), IPC_ERROR_ADD__NO_PARAM_POLLFD); + + // Memory reallocation. + ipc_ctx_new_alloc (ctx); + + T_R ((ctx->size <= 0), IPC_ERROR_ADD__NOT_ENOUGH_MEMORY); + + ctx->cinfos[ctx->size - 1] = *p; + ctx->pollfd[ctx->size - 1] = *pollfd; + + IPC_RETURN_NO_ERROR; +} + +struct ipc_error ipc_del (struct ipc_ctx *ctx, uint32_t index) +{ + T_R ((ctx == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM); + T_R ((ctx->cinfos == NULL || ctx->pollfd == NULL), IPC_ERROR_DEL__EMPTY_LIST); + T_R ((index >= ctx->size), IPC_ERROR_DEL__CANNOT_FIND_CLIENT); + + if (ctx->cinfos[index].spath != NULL) { + free (ctx->cinfos[index].spath); + ctx->cinfos[index].spath = NULL; + } + + ctx->size--; + + if (ctx->size == 0) { + // free ctx->cinfos and ctx->pollfd + ipc_ctx_free (ctx); IPC_RETURN_NO_ERROR; } - // listen to what they have to say (disconnection or message) - // then add a client to `event`, the ipc_event structure - SECURE_DECLARATION (struct ipc_error, ret); - struct ipc_message *m = NULL; + // The last element in the array replaces the removed one. + ctx->cinfos[index] = ctx->cinfos[ctx->size]; + ctx->pollfd[index] = 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__EMPTIED_LIST); + } + + IPC_RETURN_NO_ERROR; +} + +struct ipc_error ipc_add_fd_ (struct ipc_ctx *ctx, int fd, enum ipc_connection_type type) +{ + T_R ((ctx == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS); + + SECURE_DECLARATION (struct ipc_connection_info, cinfo); + cinfo.type = type; + + SECURE_DECLARATION (struct pollfd, pollfd); + pollfd.fd = fd; + pollfd.events = POLLIN; + + return ipc_add (ctx, &cinfo, &pollfd); +} + +// add a switched file descriptor to read +struct ipc_error ipc_add_fd_switched (struct ipc_ctx *ctx, int fd) +{ + return ipc_add_fd_ (ctx, fd, IPC_CONNECTION_TYPE_SWITCHED); +} + +// add an arbitrary file descriptor to read +struct ipc_error ipc_add_fd (struct ipc_ctx *ctx, int fd) +{ + return ipc_add_fd_ (ctx, fd, IPC_CONNECTION_TYPE_EXTERNAL); +} + +// 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 == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST); + + for (size_t i = 0; i < ctx->size; i++) { + if (ctx->pollfd[i].fd == fd) { + return ipc_del (ctx, i); + } + } + + IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT); +} + +struct ipc_error handle_writing_message (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index) +{ + int txfd = ctx->pollfd[index].fd; + int mfd; + struct ipc_message *m; + for (size_t i = 0; ctx->tx.size ; i++) { + m = &ctx->tx.messages[i]; + mfd = m->fd; + if (txfd == mfd) { + TEST_IPC_RR (ipc_write_fd (txfd, m), "cannot send a message to the client"); + + // Freeing the message structure. + ipc_message_empty (m); + // Removing the message from the context. + ipc_messages_del (&ctx->tx, i); // remove the message indexed by i + + break; // The message has been sent + } + } + + IPC_EVENT_SET (event, IPC_EVENT_TYPE_TX, index, ctx->pollfd[index].fd, NULL); + IPC_RETURN_NO_ERROR; +} + +struct ipc_error handle_new_message (struct ipc_event *event, struct ipc_ctx *ctx, int index) +{ + SECURE_DECLARATION (struct ipc_error, ret); + + // Listen to what they have to say (disconnection or message) + // then add a client to `event`, the ipc_event structure. + struct ipc_message *m = NULL; SECURE_BUFFER_HEAP_ALLOCATION_R (m, sizeof (struct ipc_message),, IPC_ERROR_HANDLE_MESSAGE__NOT_ENOUGH_MEMORY); // current talking client - ret = ipc_read (pc, m); + ret = ipc_read (ctx, index, m); if (ret.error_code != IPC_ERROR_NONE && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) { struct ipc_error rvalue = ret; // store the final return value ipc_message_empty (m); free (m); // 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_close (ctx, index), "cannot close a connection in handle_message"); + TEST_IPC_P (ipc_del (ctx, index), "cannot delete a connection in handle_message"); - IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc); + IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, ctx->pollfd[index].fd, NULL); 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"); + + IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, ctx->pollfd[index].fd, NULL); + + TEST_IPC_P (ipc_close (ctx, index), "cannot close a connection on closed recipient in handle_message"); + TEST_IPC_P (ipc_del (ctx, index), "cannot delete a connection on closed recipient in handle_message"); ipc_message_empty (m); free (m); - IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc); - // warning: do not forget to free the ipc_client structure IPC_RETURN_NO_ERROR; } - IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc); + // The message carries the fd it was received on. + m->fd = ctx->pollfd[index].fd; + IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, index, ctx->pollfd[index].fd, m); IPC_RETURN_NO_ERROR; } -struct ipc_error ipc_wait_event_networkd (struct ipc_connection_infos *cinfos - , struct ipc_connection_info *cinfo // NULL for clients - , struct ipc_event *event, struct ipc_switchings *switchdb - , double *timer) +struct ipc_error +handle_writing_switched_message (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index) { - T_R ((cinfos == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM); - T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM); + return fd_switching_write (event, ctx, index); +} + +struct ipc_error +handle_switched_message(struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index) +{ + return fd_switching_read (event, ctx, index); +} + +/* timer is in ms */ +struct ipc_error ipc_wait_event (struct ipc_ctx *ctx, struct ipc_event *event, int *timer) +{ + 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); - size_t i, j; - /* master file descriptor list */ - fd_set master; - fd_set readf; + int32_t n; - /* clear the master and temp sets */ - FD_ZERO (&master); - FD_ZERO (&readf); - - /* maximum file descriptor number */ - /* keep track of the biggest file descriptor */ - int32_t fdmax = get_max_fd (cinfos); - - /* listening socket descriptor */ - int32_t listener; - if (cinfo != NULL) { - listener = cinfo->fd; - - /* add the listener to the master set */ - FD_SET (listener, &master); - - /* if listener is max fd */ - if (fdmax < listener) - fdmax = listener; - } - - for (i = 0; i < cinfos->size; i++) { - FD_SET (cinfos->cinfos[i]->fd, &master); - } - - readf = master; - - struct timeval *ptimeout = NULL; - SECURE_DECLARATION (struct timeval, timeout); - - if (timer != NULL && *timer > 0.0) { - timeout.tv_sec = (long) *timer; - timeout.tv_usec = (long) ((long)((*timer) * 1000000) % 1000000); - ptimeout = &timeout; - } - - T_PERROR_RIPC ((select (fdmax + 1, &readf, NULL, NULL, ptimeout) == -1), "select", IPC_ERROR_WAIT_EVENT__SELECT); - - if (ptimeout != NULL) { - *timer = (double) timeout.tv_sec + (timeout.tv_usec / 1000000.0); - if (*timer == 0) { - IPC_EVENT_SET (event, IPC_EVENT_TYPE_TIMER, NULL, NULL); - IPC_RETURN_NO_ERROR; - } - } - - 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); - } else { - for (j = 0; j < cinfos->size; j++) { - if (i == (size_t) cinfos->cinfos[j]->fd) { - return handle_message (event, cinfos, cinfos->cinfos[j], switchdb); - } - } + for (size_t i = 0; i < ctx->tx.size; i++) { + for (size_t y = 0; y < ctx->size; y++) { + if (ctx->pollfd[y].fd == ctx->tx.messages[i].fd) { + ctx->pollfd[y].events |= POLLOUT; + break; } } } - IPC_RETURN_NO_ERROR; -} + struct timeval tv_1; + memset (&tv_1, 0, sizeof(struct timeval)); -struct ipc_error ipc_wait_event (struct ipc_connection_infos *cinfos - , struct ipc_connection_info *cinfo // NULL for clients - , struct ipc_event *event, double *timer) -{ - return ipc_wait_event_networkd (cinfos, cinfo, event, NULL, timer); -} + struct timeval tv_2; + memset (&tv_2, 0, sizeof(struct timeval)); -// store and remove only pointers on allocated structures -struct ipc_error ipc_add (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p) -{ - T_R ((cinfos == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS); - T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT); + gettimeofday(&tv_1, NULL); - cinfos->size++; - if (cinfos->size == 1 && cinfos->cinfos == NULL) { - // first allocation - SECURE_BUFFER_HEAP_ALLOCATION_R (cinfos->cinfos, sizeof (struct ipc_connection_info),, - IPC_ERROR_ADD__MALLOC); - } else { - cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size); + if ((n = poll(ctx->pollfd, ctx->size, *timer)) < 0) { + IPC_RETURN_ERROR (IPC_ERROR_WAIT_EVENT__POLL); } - T_R ((cinfos->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST); + gettimeofday(&tv_2, NULL); - cinfos->cinfos[cinfos->size - 1] = p; - IPC_RETURN_NO_ERROR; -} + int nb_sec_ms = (tv_2.tv_sec - tv_1.tv_sec) * 1000; + int nb_usec_ms = (tv_2.tv_usec - tv_1.tv_usec) / 1000; + int time_elapsed_ms = (nb_sec_ms + nb_usec_ms); -struct ipc_error ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p) -{ - T_R ((cinfos == 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); + // Handle memory fuckery, 'cause low level programming is fun. + if (time_elapsed_ms >= *timer) { + *timer = 0; + } + else { + *timer -= time_elapsed_ms; + } - size_t i; - for (i = 0; i < cinfos->size; i++) { - if (cinfos->cinfos[i] == p) { - // TODO: possible memory leak if the ipc_connection_info is not free'ed - cinfos->cinfos[i] = cinfos->cinfos[cinfos->size - 1]; - cinfos->size--; - if (cinfos->size == 0) { - ipc_connections_free (cinfos); - } else { - cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size); + // Timeout. + if (n == 0) { + IPC_EVENT_SET (event, IPC_EVENT_TYPE_TIMER, 0, 0, NULL); + IPC_RETURN_NO_ERROR; + } - if (cinfos->cinfos == NULL) { - IPC_RETURN_ERROR (IPC_ERROR_DEL__EMPTIED_LIST); - } + for (size_t i = 0; i <= ctx->size; i++) { + // Something to read or connection. + if (ctx->pollfd[i].revents & POLLIN) { + // In case there is something to read for the server socket: new client. + if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SERVER) { + return ipc_accept_add (event, ctx, i); } - IPC_RETURN_NO_ERROR; + // fd is switched: using callbacks for IO operations. + if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SWITCHED) { +#if 0 + int fd_validity = fd_is_valid (ctx->pollfd[i].fd); + if (! fd_validity) { + printf ("switch happening in C: %d FD IS INVALID:::::::::: IM BROKEN INSIIIIIIIDE\n", ctx->pollfd[i].fd); + } +#endif + + return handle_switched_message (event, ctx, i); + } + + // No treatment of the socket if external socket: the libipc user should handle IO operations. + if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_EXTERNAL) { + IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, i, ctx->pollfd[i].fd, NULL); + IPC_RETURN_NO_ERROR; + } + + return handle_new_message (event, ctx, i); } - } - IPC_RETURN_ERROR (IPC_ERROR_DEL__CANNOT_FIND_CLIENT); -} + // Something can be sent. + if (ctx->pollfd[i].revents & POLLOUT) { + ctx->pollfd[i].events &= ~POLLOUT; -void ipc_connections_close (struct ipc_connection_infos *cinfos) -{ - if (cinfos->cinfos != NULL) { - for (size_t i = 0; i < cinfos->size; i++) { - ipc_close (cinfos->cinfos[i]); - free (cinfos->cinfos[i]); + // fd is switched: using callbacks for IO operations. + if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SWITCHED) { + return handle_writing_switched_message (event, ctx, i); + } + + return handle_writing_message (event, ctx, i); } - free (cinfos->cinfos); - cinfos->cinfos = NULL; - } - cinfos->size = 0; -} -void ipc_connections_free (struct ipc_connection_infos *cinfos) -{ - if (cinfos->cinfos != NULL) { - for (size_t i = 0; i < cinfos->size; i++) { - free (cinfos->cinfos[i]); + // Disconnection. + if (ctx->pollfd[i].revents & POLLHUP) { + /** IPC_EVENT_SET: event, type, index, fd, message */ + IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, i, ctx->pollfd[i].fd, NULL); + return ipc_close (ctx, i); } - free (cinfos->cinfos); - cinfos->cinfos = NULL; - } - cinfos->size = 0; -} -// create the client service structure -struct ipc_error ipc_connection_gen (struct ipc_connection_info *cinfo - , uint32_t index, uint32_t version - , int fd, char type) -{ - T_R ((cinfo == NULL), IPC_ERROR_CONNECTION_GEN__NO_CINFO); - - cinfo->type = type; - cinfo->version = version; - cinfo->index = index; - cinfo->fd = fd; + } /** for loop: end of the message handling */ IPC_RETURN_NO_ERROR; } - -// add an arbitrary file descriptor to read -struct ipc_error ipc_add_fd (struct ipc_connection_infos *cinfos, int fd) -{ - T_R ((cinfos == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS); - - struct ipc_connection_info *cinfo = NULL; - - SECURE_BUFFER_HEAP_ALLOCATION_R (cinfo, sizeof (struct ipc_connection_info),, - IPC_ERROR_ADD_FD__NOT_ENOUGH_MEMORY); - - ipc_connection_gen (cinfo, 0, 0, fd, IPC_CONNECTION_TYPE_EXTERNAL); - - return ipc_add (cinfos, cinfo); -} - -// remove a connection from its file descriptor -struct ipc_error ipc_del_fd (struct ipc_connection_infos *cinfos, int fd) -{ - T_R ((cinfos == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS); - T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST); - - size_t i; - for (i = 0; i < cinfos->size; i++) { - if (cinfos->cinfos[i]->fd == fd) { - cinfos->cinfos[i]->fd = -1; - free (cinfos->cinfos[i]); - cinfos->size--; - if (cinfos->size == 0) { - // free cinfos->cinfos - ipc_connections_free (cinfos); - } else { - cinfos->cinfos[i] = cinfos->cinfos[cinfos->size]; - cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size); - - if (cinfos->cinfos == NULL) { - IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__EMPTIED_LIST); - } - } - - IPC_RETURN_NO_ERROR; - } - } - - IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT); -} diff --git a/src/context.c b/src/context.c new file mode 100644 index 0000000..8e7aa3e --- /dev/null +++ b/src/context.c @@ -0,0 +1,48 @@ +#include "ipc.h" + +/** + * 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_NO_ERROR; +} + +void ipc_ctx_free (struct ipc_ctx *ctx) +{ + if (ctx->cinfos != NULL) { + free (ctx->cinfos); + ctx->cinfos = NULL; + } + if (ctx->pollfd != NULL) { + free (ctx->pollfd); + ctx->pollfd = NULL; + } + ctx->size = 0; + + ipc_switching_free(&ctx->switchdb); + + ipc_messages_free (&ctx->tx); +} diff --git a/src/error.c b/src/error.c index 73b993f..6709f84 100644 --- a/src/error.c +++ b/src/error.c @@ -12,22 +12,15 @@ static struct ipc_errors_verbose ipc_errors_verbose[] = { {IPC_ERROR_NONE, "no error"} , {IPC_ERROR_CLOSED_RECIPIENT, "closed recipient"} - , {IPC_ERROR_SERVER_INIT__NO_DIR_CANNOT_CREATE_IT, - "ipc_server_init: no directory for ipc and cannot to create it"} - , {IPC_ERROR_SERVER_INIT__NON_WRITABLE_DIR, "ipc_server_init: non writable directory for ipc"} - , {IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM, "ipc_server_init: no environment param"} , {IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM , "ipc_server_init: no service param"} , {IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM, "ipc_server_init: no server name param"} , {IPC_ERROR_SERVER_INIT__MALLOC , "ipc_server_init: error on malloc function"} - , {IPC_ERROR_CONNECTION__NO_SERVER, "ipc_connection: no server parameter"} , {IPC_ERROR_CONNECTION__NO_SERVICE_NAME, "ipc_connection: no service name parameter"} , {IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM, "ipc_connection: no environment param"} , {IPC_ERROR_USOCK_CONNECT__CONNECT, "ipc_connection: error on the connect function"} - , {IPC_ERROR_CONNECTION_GEN__NO_CINFO, "ipc_connection_gen: no cinfo"} - , {IPC_ERROR_ACCEPT__NO_SERVICE_PARAM, "ipc_accept: no service param"} , {IPC_ERROR_ACCEPT__NO_CLIENT_PARAM , "ipc_accept: no client param"} @@ -36,7 +29,7 @@ static struct ipc_errors_verbose ipc_errors_verbose[] = { , {IPC_ERROR_PROVIDE_FD__SENDMSG , "ipc_provide_fd: sendmsg function"} , {IPC_ERROR_WRITE__NO_MESSAGE_PARAM, "ipc_write: no message param"} - , {IPC_ERROR_WRITE__NOT_ENOUGH_DATA , "ipc_write: no enough data sent"} + , {IPC_ERROR_WRITE_FD__NOT_ENOUGH_DATA , "ipc_write: no enough data sent"} , {IPC_ERROR_READ__NO_MESSAGE_PARAM , "ipc_read: no message param"} , {IPC_ERROR_HANDLE_MESSAGE__NOT_ENOUGH_MEMORY , "handle_message: not enough memory"} @@ -47,8 +40,8 @@ static struct ipc_errors_verbose ipc_errors_verbose[] = { , {IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM, "ipc_wait_event: no clients param"} , {IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM , "ipc_wait_event: no event param"} - , {IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM, "ipc_contact_networkd: no service name param"} - , {IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM , "ipc_contact_networkd: no server param"} + , {IPC_ERROR_CONTACT_IPCD__NO_SERVICE_NAME_PARAM, "ipc_contact_ipcd: no service name param"} + , {IPC_ERROR_CONTACT_IPCD__NO_SERVER_PARAM , "ipc_contact_ipcd: no server param"} , {IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC, "ipc_handle_new_connection: error on malloc function"} @@ -127,6 +120,29 @@ static struct ipc_errors_verbose ipc_errors_verbose[] = { , {IPC_ERROR_DIR_SETUP__DIRECTORY_NOT_WRITABLE, "directory_setup_: directory not writable"} , {IPC_ERROR_DIRECTORY_SETUP__PATH_PARAM , "directory_setup_: no path param"} + + , {IPC_ERROR_SERVER_INIT__NOT_ENOUGH_MEMORY, "IPC_ERROR_SERVER_INIT__NOT_ENOUGH_MEMORY"} + , {IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY, "IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY"} + , {IPC_ERROR_CTX_INIT__NO_CONTEXT_PARAM, "IPC_ERROR_CTX_INIT__NO_CONTEXT_PARAM"} + , {IPC_ERROR_CTX_INIT__CONTEXT_ALREADY_INIT, "IPC_ERROR_CTX_INIT__CONTEXT_ALREADY_INIT"} + , {IPC_ERROR_ADD__MALLOC_POLLFD, "IPC_ERROR_ADD__MALLOC_POLLFD"} + , {IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST, "IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST"} + , {IPC_ERROR_ADD_MESSAGE_TO_SEND__MALLOC, "IPC_ERROR_ADD_MESSAGE_TO_SEND__MALLOC"} + , {IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGE, "IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGE"} + , {IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGES, "IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGES"} + , {IPC_ERROR_CONNECTION__NO_CTX, "IPC_ERROR_CONNECTION__NO_CTX"} + , {IPC_ERROR_CTX_INIT__MALLOC_CTX, "IPC_ERROR_CTX_INIT__MALLOC_CTX"} + , {IPC_ERROR_CTX_INIT__MALLOC_POLLFD, "IPC_ERROR_CTX_INIT__MALLOC_POLLFD"} + , {IPC_ERROR_CONTACT_IPCD__NO_FD_PARAM, "IPC_ERROR_CONTACT_IPCD__NO_FD_PARAM"} + , {IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX, "IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX"} + , {IPC_ERROR_DEL_MESSAGE_TO_SEND__NO_PARAM_MESSAGES, "IPC_ERROR_DEL_MESSAGE_TO_SEND__NO_PARAM_MESSAGES"} + , {IPC_ERROR_MESSAGE_DEL__INDEX_ERROR, "IPC_ERROR_MESSAGE_DEL__INDEX_ERROR"} + , {IPC_ERROR_MESSAGE_DEL__EMPTY_LIST, "IPC_ERROR_MESSAGE_DEL__EMPTY_LIST"} + , {IPC_ERROR_ADD__NO_PARAM_POLLFD, "IPC_ERROR_ADD__NO_PARAM_POLLFD"} + , {IPC_ERROR_WRITE__FD_NOT_FOUND, "IPC_ERROR_WRITE__FD_NOT_FOUND"} + , {IPC_ERROR_FD_SWITCHING__NO_FD_RECORD, "IPC_ERROR_FD_SWITCHING__NO_FD_RECORD"} + , {IPC_ERROR_CLOSE_ALL__NO_CTX_PARAM, "IPC_ERROR_CLOSE_ALL__NO_CTX_PARAM" } + , {IPC_ERROR_CLOSE__NO_CTX_PARAM, "IPC_ERROR_CLOSE__NO_CTX_PARAM"} }; const char *ipc_errors_get (enum ipc_error_code e) diff --git a/src/ipc.h b/src/ipc.h index a28ac20..898d852 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -9,6 +9,8 @@ #include // error numbers #include +#include + /*** * global defaults **/ @@ -73,13 +75,23 @@ enum msg_types { enum ipc_event_type { IPC_EVENT_TYPE_NOT_SET = 0 , IPC_EVENT_TYPE_ERROR = 1 - , IPC_EVENT_TYPE_EXTRA_SOCKET = 2 - , IPC_EVENT_TYPE_SWITCH = 3 - , 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 + , IPC_EVENT_TYPE_EXTRA_SOCKET = 2 // Message received from a non IPC socket. + , IPC_EVENT_TYPE_SWITCH = 3 // Message to send to a corresponding fd. + , IPC_EVENT_TYPE_CONNECTION = 4 // New user. + , IPC_EVENT_TYPE_DISCONNECTION = 5 // User disconnected. + , IPC_EVENT_TYPE_MESSAGE = 6 // New message. + , IPC_EVENT_TYPE_LOOKUP = 7 // Client asking for a service through ipcd. + , IPC_EVENT_TYPE_TIMER = 8 // Timeout in the poll(2) function. + , IPC_EVENT_TYPE_TX = 9 // Message sent. +}; + +// For IO callbacks (switching). +enum ipccb { + IPC_CB_NO_ERROR = 0 // No error. A message was generated. + , IPC_CB_FD_CLOSING = 1 // The fd is closing. + , IPC_CB_FD_ERROR = 2 // Generic error. + , IPC_CB_PARSING_ERROR = 3 // The message was read but with errors. + , IPC_CB_IGNORE = 4 // The message should be ignored (protocol specific). }; /** @@ -88,8 +100,6 @@ enum ipc_event_type { */ enum ipc_error_code { IPC_ERROR_NONE = 0 - , IPC_ERROR_SERVER_INIT__NON_WRITABLE_DIR = 1 - , IPC_ERROR_SERVER_INIT__NO_DIR_CANNOT_CREATE_IT = 2 , IPC_ERROR_HANDLE_MESSAGE__NOT_ENOUGH_MEMORY = 3 , IPC_ERROR_CLOSED_RECIPIENT = 4 , IPC_ERROR_SERVICE_PATH__NO_PATH = 5 @@ -99,12 +109,10 @@ enum ipc_error_code { , IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM = 9 , IPC_ERROR_SERVER_INIT__MALLOC = 10 , IPC_ERROR_WRITE__NO_MESSAGE_PARAM = 11 - , IPC_ERROR_WRITE__NOT_ENOUGH_DATA = 12 + , IPC_ERROR_WRITE_FD__NOT_ENOUGH_DATA = 12 , IPC_ERROR_READ__NO_MESSAGE_PARAM = 13 - , IPC_ERROR_CONNECTION__NO_SERVER = 14 , IPC_ERROR_CONNECTION__NO_SERVICE_NAME = 15 , IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM = 16 - , IPC_ERROR_CONNECTION_GEN__NO_CINFO = 17 , IPC_ERROR_ACCEPT__NO_SERVICE_PARAM = 18 , IPC_ERROR_ACCEPT__NO_CLIENT_PARAM = 19 , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM = 20 @@ -123,8 +131,8 @@ enum ipc_error_code { , IPC_ERROR_DEL_FD__EMPTIED_LIST = 33 , IPC_ERROR_DEL_FD__EMPTY_LIST = 34 , IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT = 35 - , IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM = 36 - , IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM = 37 + , IPC_ERROR_CONTACT_IPCD__NO_SERVICE_NAME_PARAM = 36 + , IPC_ERROR_CONTACT_IPCD__NO_SERVER_PARAM = 37 , IPC_ERROR_DEL__EMPTY_LIST = 38 , IPC_ERROR_DEL__EMPTIED_LIST = 39 , IPC_ERROR_DEL__CANNOT_FIND_CLIENT = 40 @@ -173,6 +181,31 @@ enum ipc_error_code { , IPC_ERROR_DIR_SETUP__NOT_A_DIRECTORY = 83 , IPC_ERROR_DIR_SETUP__DIRECTORY_NOT_WRITABLE = 84 , IPC_ERROR_DIRECTORY_SETUP__PATH_PARAM = 85 + + , IPC_ERROR_SERVER_INIT__NOT_ENOUGH_MEMORY = 86 + , IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY = 87 + , IPC_ERROR_CTX_INIT__NO_CONTEXT_PARAM = 88 + , IPC_ERROR_CTX_INIT__CONTEXT_ALREADY_INIT = 89 + , IPC_ERROR_ADD__MALLOC_POLLFD = 90 + , IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST = 91 + , IPC_ERROR_ADD_MESSAGE_TO_SEND__MALLOC = 92 + , IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGE = 93 + , IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGES = 94 + , IPC_ERROR_CONNECTION__NO_CTX = 95 + , IPC_ERROR_CTX_INIT__MALLOC_CTX = 96 + , IPC_ERROR_CTX_INIT__MALLOC_POLLFD = 97 + , IPC_ERROR_CONTACT_IPCD__NO_FD_PARAM = 98 + , IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX = 99 + , IPC_ERROR_DEL_MESSAGE_TO_SEND__NO_PARAM_MESSAGES = 100 + , IPC_ERROR_MESSAGE_DEL__INDEX_ERROR = 101 + , IPC_ERROR_MESSAGE_DEL__EMPTY_LIST = 102 + , IPC_ERROR_ADD__NO_PARAM_POLLFD = 103 + , IPC_ERROR_WRITE__FD_NOT_FOUND = 104 + , IPC_ERROR_ADD__NOT_ENOUGH_MEMORY = 105 + , IPC_ERROR_WAIT_EVENT__POLL = 106 + , IPC_ERROR_FD_SWITCHING__NO_FD_RECORD = 107 + , IPC_ERROR_CLOSE_ALL__NO_CTX_PARAM = 108 + , IPC_ERROR_CLOSE__NO_CTX_PARAM = 109 }; struct ipc_error { @@ -186,45 +219,98 @@ struct ipc_error { // with the error_message string in the ipc_error structure. const char *ipc_errors_get (enum ipc_error_code e); + +enum ipc_connection_type { + IPC_CONNECTION_TYPE_IPC = 0 + , IPC_CONNECTION_TYPE_EXTERNAL = 1 + /** Messages received = new connections. */ + , IPC_CONNECTION_TYPE_SERVER = 2 + /** IO operations should go through registered callbacks. */ + , IPC_CONNECTION_TYPE_SWITCHED = 3 +}; + struct ipc_connection_info { - uint32_t version; - uint32_t index; - int32_t fd; - char type; // server, client, arbitrary fd + enum ipc_connection_type type; char *spath; // max size: PATH_MAX }; -struct ipc_connection_infos { - struct ipc_connection_info **cinfos; +struct ipc_message { + char type; // Internal message type. + char user_type; // User-defined message type. + int fd; // File descriptor concerned about this message. + uint32_t length; // Payload length. + char *payload; +}; + +struct ipc_messages { + struct ipc_message *messages; size_t size; }; -struct ipc_message { - char type; - char user_type; - uint32_t length; - char *payload; +struct ipc_switching { + int orig; + int dest; + enum ipccb (*orig_in) (int origin_fd, struct ipc_message *m); + enum ipccb (*orig_out) (int origin_fd, struct ipc_message *m); + enum ipccb (*dest_in) (int origin_fd, struct ipc_message *m); + enum ipccb (*dest_out) (int origin_fd, struct ipc_message *m); +}; + +struct ipc_switchings { + struct ipc_switching *collection; + size_t size; +}; + +void ipc_message_copy (struct ipc_message *m + , uint32_t fd + , uint8_t type + , uint8_t utype + , char *payload + , uint32_t paylen); +struct ipc_error ipc_messages_del (struct ipc_messages *messages, uint32_t index); + +/** + * Context of the whole networking state. + */ +struct ipc_ctx { + /** + * Keep track of connections. + */ + struct ipc_connection_info *cinfos; + /** + * List of "pollfd" structures within cinfos, so we can pass it to poll(2). + */ + struct pollfd *pollfd; + /** + * Size of the connection list. + */ + size_t size; + /** + * List of messages to send, once the fd are available. + */ + struct ipc_messages tx; + /** + * Relations between fd. + */ + struct ipc_switchings switchdb; }; struct ipc_event { enum ipc_event_type type; - struct ipc_connection_info *origin; - void *m; // message pointer + uint32_t index; + int origin; + void *m; // message pointer }; /*** * ipc event macros **/ -#define IPC_EVENT_SET(pevent,type_,message_,origin_) {\ +#define IPC_EVENT_SET(pevent,type_,index_, origin_fd_,message_) {\ pevent->type = type_; \ + pevent->index = index_; \ + pevent->origin = origin_fd_; \ pevent->m = message_; \ - pevent->origin = origin_; \ -}; - -enum ipc_connection_types { - IPC_CONNECTION_TYPE_IPC = 0 - , IPC_CONNECTION_TYPE_EXTERNAL = 1 }; #define IPC_EVENT_CLEAN(pevent) {\ @@ -240,35 +326,32 @@ enum ipc_connection_types { * main public functions **/ -struct ipc_error ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname); -struct ipc_error ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname); +struct ipc_error ipc_wait_event (struct ipc_ctx *, struct ipc_event *, int *timer); -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_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_connection_switched (struct ipc_ctx *ctx, const char *sname, int clientfd, int *serverfd); -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_close (struct ipc_ctx *ctx, uint32_t index); +struct ipc_error ipc_close_all (struct ipc_ctx *ctx); -struct ipc_error ipc_wait_event (struct ipc_connection_infos *clients - , struct ipc_connection_info *srv - , struct ipc_event *event, double *timer); +void ipc_ctx_free (struct ipc_ctx *ctx); + +struct ipc_error ipc_read (const struct ipc_ctx *, uint32_t index, struct ipc_message *m); +struct ipc_error ipc_write (struct ipc_ctx *, const struct ipc_message *m); + +struct ipc_error fd_switching_read (struct ipc_event *event, struct ipc_ctx *ctx, int index); +struct ipc_error fd_switching_write (struct ipc_event *event, struct ipc_ctx *ctx, int index); // store and remove only pointers on allocated structures -struct ipc_error ipc_add (struct ipc_connection_infos *, struct ipc_connection_info *); -struct ipc_error ipc_del (struct ipc_connection_infos *, struct ipc_connection_info *); +struct ipc_error ipc_add (struct ipc_ctx *, struct ipc_connection_info *, struct pollfd *); +struct ipc_error ipc_del (struct ipc_ctx *, uint32_t index); // add an arbitrary file descriptor to read -struct ipc_error ipc_add_fd (struct ipc_connection_infos *cinfos, int fd); -struct ipc_error ipc_del_fd (struct ipc_connection_infos *cinfos, int fd); - -void ipc_connections_free (struct ipc_connection_infos *); - -// create the client service structure -struct ipc_error ipc_connection_gen (struct ipc_connection_info *cinfo - , uint32_t index, uint32_t version - , int fd, char type); - -void ipc_connections_close (struct ipc_connection_infos *cinfos); +struct ipc_error ipc_add_fd (struct ipc_ctx *ctx, int fd); +// add a switched file descriptor to read +struct ipc_error ipc_add_fd_switched (struct ipc_ctx *ctx, int fd); +struct ipc_error ipc_del_fd (struct ipc_ctx *ctx, int fd); /*** * message functions @@ -286,6 +369,9 @@ struct ipc_error ipc_message_format_data (struct ipc_message *m, char utype, con struct ipc_error ipc_message_format_server_close (struct ipc_message *m); struct ipc_error ipc_message_empty (struct ipc_message *m); +struct ipc_error ipc_messages_add (struct ipc_messages *, const struct ipc_message *); +void ipc_messages_free (struct ipc_messages *); + // Switch cases macros // print on error #define ERROR_CASE(e,f,m) case e : { fprintf (stderr, "function %s: %s", f, m); } break; @@ -294,42 +380,37 @@ struct ipc_error ipc_message_empty (struct ipc_message *m); * non public functions **/ -void ipc_connection_print (struct ipc_connection_info *cinfo); -void ipc_connections_print (struct ipc_connection_infos *cinfos); +struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m); +struct ipc_error ipc_ctx_init (struct ipc_ctx **); +struct ipc_error ipc_ctx_new_alloc (struct ipc_ctx *ctx); +struct ipc_error service_path (char *path, const char *sname); +struct ipc_error handle_writing_message (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index); -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 service_path (char *path, const char *sname, int32_t index, int32_t version); +void ipc_ctx_print (struct ipc_ctx *ctx); + +// 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_ipcd (int *pfd, const char *sname); +struct ipc_error service_path (char *path, const char *sname); /*** - * networkd enumerations, structures and functions + * ipcd enumerations, structures and functions **/ -struct ipc_switching { - int orig; - int dest; -}; - -struct ipc_switchings { - struct ipc_switching *collection; - size_t size; -}; - -struct networkd { - int cpt; - struct ipc_connection_info *srv; - struct ipc_connection_infos *clients; - struct ipc_switchings *TCP_TO_IPC; -}; - -struct ipc_error ipc_wait_event_networkd (struct ipc_connection_infos *cinfos - , struct ipc_connection_info *cinfo // cinfo is NULL for clients - , struct ipc_event *event, struct ipc_switchings *switchdb, double *timer); - +void ipc_ctx_switching_add (struct ipc_ctx *ctx, int orig, int dest); void ipc_switching_add (struct ipc_switchings *is, int orig, int dest); int ipc_switching_del (struct ipc_switchings *is, int fd); int ipc_switching_get (struct ipc_switchings *is, int fd); void ipc_switching_free (struct ipc_switchings *is); +void ipc_switching_callbacks_ (struct ipc_ctx *ctx, int fd + , enum ipccb (*cb_in )(int fd, struct ipc_message *m)); +void ipc_switching_callbacks ( + struct ipc_ctx *ctx + , int fd + , enum ipccb (*cb_in )(int fd, struct ipc_message *m) + , enum ipccb (*cb_out)(int fd, struct ipc_message *m)); + +int ipc_ctx_fd_type (struct ipc_ctx *ctx, int fd, enum ipc_connection_type type); void ipc_switching_print (struct ipc_switchings *is); diff --git a/src/message.c b/src/message.c index 07d7ea3..a4a1add 100644 --- a/src/message.c +++ b/src/message.c @@ -145,3 +145,87 @@ struct ipc_error ipc_message_empty (struct ipc_message *m) IPC_RETURN_NO_ERROR; } + +// store and remove only pointers on allocated structures +struct ipc_error ipc_messages_add (struct ipc_messages *messages, const struct ipc_message *message) +{ + T_R ((messages == NULL), IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGES); + T_R ((message == NULL), IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGE); + + messages->size++; + if (messages->size == 1 && messages->messages == NULL) { + // first allocation + SECURE_BUFFER_HEAP_ALLOCATION_R (messages->messages, sizeof (struct ipc_message),, + IPC_ERROR_ADD_MESSAGE_TO_SEND__MALLOC); + } else { + messages->messages = realloc (messages->messages, sizeof (struct ipc_message) * messages->size); + } + + T_R ((messages->messages == NULL), IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST); + + // DEEP COPY. + messages->messages[messages->size -1] = *message; + if (message->length > 0 && message->payload != NULL) { + messages->messages[messages->size -1].payload = malloc(message->length * sizeof (char)); + strncpy(messages->messages[messages->size -1].payload, message->payload, message->length); + } + else { + messages->messages[messages->size -1].payload = NULL; + } + + IPC_RETURN_NO_ERROR; +} + +// Remove only pointers on allocated structures. +struct ipc_error ipc_messages_del (struct ipc_messages *messages, uint32_t index) +{ + T_R ((messages == NULL), IPC_ERROR_DEL_MESSAGE_TO_SEND__NO_PARAM_MESSAGES); + T_R ((messages->size == 0 || index >= messages->size), IPC_ERROR_MESSAGE_DEL__INDEX_ERROR); + + // NOT A DEEP COPY. + messages->size--; + if (messages->size == 0) { + free (messages->messages); + messages->messages = NULL; + } + else { + messages->messages[index] = messages->messages[messages->size]; + messages->messages = realloc (messages->messages, sizeof (struct ipc_message) * messages->size); + T_R ((messages->messages == NULL), IPC_ERROR_MESSAGE_DEL__EMPTY_LIST); + } + + IPC_RETURN_NO_ERROR; +} + +void ipc_message_copy (struct ipc_message *m + , uint32_t fd + , uint8_t type + , uint8_t utype + , char *payload + , uint32_t paylen) +{ + // printf("starting the message copy\n"); + m->fd = fd; + m->type = type; + m->user_type = utype; + m->length = paylen; + if (m->payload != NULL) { + free(m->payload); + } + // printf("BEFORE THE PAYLOAD COPY\n"); + m->payload = malloc(sizeof(char) * paylen); + memcpy(m->payload, payload, paylen); + // printf("PAYLOAD COPY DONE\n"); +} + +void ipc_messages_free (struct ipc_messages *messages) +{ + if (messages != NULL) + { + if (messages->messages != NULL) + { + free(messages->messages); + messages->messages = 0; + } + } +} diff --git a/src/network.c b/src/network.c index a54a290..273b527 100644 --- a/src/network.c +++ b/src/network.c @@ -20,12 +20,12 @@ /** * TODO: - * describe a protocol to get this working into networkd - * asking networkd for a fd with an URI + * describe a protocol to get this working into ipcd + * asking ipcd for a fd with an URI * URI should contain: who (the service name), where (destination), how (protocol) - * networkd initiates a communication with the requested service - * networkd sends the fd - * get a networkd working with this + * ipcd initiates a communication with the requested service + * ipcd sends the fd + * get a ipcd working with this */ struct ipc_error ipc_receive_fd (int sock, int *fd) @@ -81,9 +81,25 @@ struct ipc_error ipc_provide_fd (int sock, int fd) IPC_RETURN_NO_ERROR; } +void ipc_ctx_switching_add (struct ipc_ctx *ctx, int orig, int dest) +{ + ipc_switching_add (&ctx->switchdb, orig, dest); +} + void ipc_switching_add (struct ipc_switchings *is, int orig, int dest) { - is->collection = realloc (is->collection, sizeof (struct ipc_switching) * (is->size + 1)); + // printf ("ipc_switching_add START: switchdb has %ld entries\n", is->size); + + if (is->collection == NULL) { + // printf ("switchdb collection is null\n"); + is->collection = malloc (sizeof (struct ipc_switching) * (is->size + 1)); + } + else { + // printf ("switchdb collection isn't null\n"); + is->collection = realloc (is->collection, sizeof (struct ipc_switching) * (is->size + 1)); + } + + /** TODO: less brutal approach */ if (is->collection == NULL) { fprintf (stderr, __FILE__ " error realloc line %d", __LINE__); exit (EXIT_FAILURE); @@ -93,6 +109,13 @@ void ipc_switching_add (struct ipc_switchings *is, int orig, int dest) is->collection[is->size - 1].orig = orig; is->collection[is->size - 1].dest = dest; + + is->collection[is->size - 1].orig_in = NULL; + is->collection[is->size - 1].dest_in = NULL; + is->collection[is->size - 1].orig_out = NULL; + is->collection[is->size - 1].dest_out = NULL; + + // printf ("ipc_switching_add END: switchdb has %ld entries\n", is->size); } int ipc_switching_del (struct ipc_switchings *is, int fd) @@ -110,13 +133,12 @@ int ipc_switching_del (struct ipc_switchings *is, int fd) is->collection[i].orig = is->collection[is->size - 1].orig; is->collection[i].dest = is->collection[is->size - 1].dest; - size_t s = (is->size - 1) > 0 ? (is->size - 1) : 1; - - is->collection = realloc (is->collection, sizeof (struct ipc_switching) * s); - if (is->collection == NULL) { - /** TODO: not sure we want this behavior */ - fprintf (stderr, __FILE__ " error realloc line %d", __LINE__); - exit (EXIT_FAILURE); + if (is->size == 1) { + free(is->collection); + is->collection = NULL; + } + else { + is->collection = realloc (is->collection, sizeof (struct ipc_switching) * (is->size-1)); } is->size--; @@ -127,6 +149,28 @@ int ipc_switching_del (struct ipc_switchings *is, int fd) return -1; } +/** + * 0 = fd is origin + * 1 = fd is dest + * -1 = not found + */ +int ipc_switching_get_ (const struct ipc_switchings *is + , int fd + , struct ipc_switching **s) +{ + for (size_t i = 0; i < is->size; i++) { + if (is->collection[i].orig == fd) { + *s = &is->collection[i]; + return 0; + } else if (is->collection[i].dest == fd) { + *s = &is->collection[i]; + return 1; + } + } + + return -1; +} + int ipc_switching_get (struct ipc_switchings *is, int fd) { for (size_t i = 0; i < is->size; i++) { @@ -151,3 +195,268 @@ void ipc_switching_free (struct ipc_switchings *is) } is->size = 0; } + +enum ipccb +default_cb_in(int fd, struct ipc_message *m) +{ + // TODO: fix buffer size for switching messages + size_t msize = 4096; + char buf[msize]; + char *pbuf = buf; + + // By default, usock_read (a wrapper around read(2)) is used. + + { /** Some macros use "ret" as a variable name, so this is to be sure. */ + struct ipc_error ret = usock_recv (fd, &pbuf, &msize); + if (ret.error_code != IPC_ERROR_NONE) { + if (ret.error_code == IPC_ERROR_CLOSED_RECIPIENT) { + return IPC_CB_FD_CLOSING; + } + return IPC_CB_FD_ERROR; + } + } + + /** There is a message, send it to the corresponding fd **/ + if (msize > 0) { + struct ipc_error ret = ipc_message_format_read (m, buf, msize); + if (ret.error_code != IPC_ERROR_NONE) { + return IPC_CB_PARSING_ERROR; + } + return IPC_CB_NO_ERROR; + } + + // By default, if msize <= 0 the fd should be closed. + return IPC_CB_FD_CLOSING; +} + +enum ipccb +default_cb_out(int fd, struct ipc_message *m) +{ + size_t msize = 0; + SECURE_DECLARATION (struct ipc_error, ret); + SECURE_BUFFER_DECLARATION (char, buf, IPC_MAX_MESSAGE_SIZE); + char *pbuf = buf; + + ipc_message_format_write (m, &pbuf, &msize); + + size_t nbytes_sent = 0; + ret = usock_send (fd, buf, msize, &nbytes_sent); + + // On error or if what was sent != what should have been sent. + if (ret.error_code != IPC_ERROR_NONE || nbytes_sent != msize) { + return IPC_CB_FD_ERROR; + } + + return IPC_CB_NO_ERROR; +} + +void ipc_switching_callbacks_ (struct ipc_ctx *ctx, int fd + , enum ipccb (*cb_in )(int fd, struct ipc_message *m)) +{ + ipc_switching_callbacks (ctx, fd, cb_in, NULL); +} + +void ipc_switching_callbacks ( + struct ipc_ctx *ctx + , int fd + , enum ipccb (*cb_in )(int fd, struct ipc_message *m) + , enum ipccb (*cb_out)(int fd, struct ipc_message *m)) +{ + struct ipc_switching *sw = NULL; + int is_valid = ipc_switching_get_ (&ctx->switchdb, fd, &sw); + if (is_valid == -1) { + return; + } + + if (sw->orig == fd) { + sw->orig_in = cb_in; + sw->orig_out = cb_out; + } + else { + sw->dest_in = cb_in; + sw->dest_out = cb_out; + } +} + +/** + * fd_switching_read allows to read a message from a switched fd. + */ +struct ipc_error fd_switching_read (struct ipc_event *event, struct ipc_ctx *ctx, int index) +{ + // printf ("fd_switching_read\n"); + + // If the socket is associated to another one for ipcd: + // read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch. + T_R ((ctx->switchdb.size == 0), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD); + + int talkingfd = ctx->pollfd[index].fd; + int dest_fd = -1; + struct ipc_switching *sw = NULL; + struct ipc_message m; + memset(&m, 0, sizeof (struct ipc_message)); + + enum ipccb r; + int is_valid = 0; + + is_valid = ipc_switching_get_ (&ctx->switchdb, talkingfd, &sw); + + T_R ((is_valid == -1), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD); + + if (sw->orig == talkingfd) { + dest_fd = sw->dest; + if (sw->orig_in == NULL) { + r = default_cb_in (talkingfd, &m); + } + else { + r = (*sw->orig_in)(talkingfd, &m); + } + } + else { + dest_fd = sw->orig; + if (sw->dest_in == NULL) { + r = default_cb_in (talkingfd, &m); + } + else { + r = (*sw->dest_in)(talkingfd, &m); + } + } + + // Message reception OK: reading the message and put it in the list of messages to send. + if (r == IPC_CB_NO_ERROR) { + // In case of message reception: + // 1. put the message in the list to be sent + m.fd = dest_fd; + ipc_write (ctx, &m); + // 2. delete the message (a deep copy has been made) + ipc_message_empty (&m); + // 3. set event IPC_EVENT_TYPE_SWITCH, inform ipcd of a successful reception. + IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, index, ctx->pollfd[index].fd, NULL); + // 4. IPC_RETURN_NO_ERROR + IPC_RETURN_NO_ERROR; + } + + // Message reception OK: no message to transfer. + // This is applied to protocol-specific messages, for example when the client + // has to communicate with the proxy, not the service. + if (r == IPC_CB_IGNORE) { + printf ("IGNORING REQUEST\n"); + // In case of message reception: + // 1. set event IPC_EVENT_TYPE_SWITCH, inform ipcd of a successful reception. + IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, index, ctx->pollfd[index].fd, NULL); + // 2. IPC_RETURN_NO_ERROR + IPC_RETURN_NO_ERROR; + } + + /** + * NOTE: In any other case, the fd is, or should be closed. + */ + + // 1. close and remove both fd from switchdb + close (sw->dest); + ipc_del_fd (ctx, sw->dest); + // Should not close the client: it's the job of the libipc user application. + // XXX: this may be normal, but should be documented. + // close (talkingfd); + ipc_del_fd (ctx, talkingfd); + ipc_switching_del (&ctx->switchdb, talkingfd); + + // 2. set event (either error or disconnection) + if (r == IPC_CB_FD_CLOSING) { + IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, talkingfd, NULL); + } + else { + IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, talkingfd, NULL); + } + + // 3. return IPC_ERROR_CLOSED_RECIPIENT + IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT); +} + +/** + * fd_switching_write allows to read a message from a switched fd. + */ +struct ipc_error fd_switching_write (struct ipc_event *event, struct ipc_ctx *ctx, int index) +{ + // printf ("fd_switching_write\n"); + + // If the socket is associated to another one for ipcd: + // read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch. + T_R ((ctx->switchdb.size == 0), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD); + + int output_fd = ctx->pollfd[index].fd; + struct ipc_switching *sw = NULL; + struct ipc_message *m = NULL; + size_t i; + + // search for the next message to send for output_fd fd. + for (i = 0; ctx->tx.size ; i++) { + if (ctx->tx.messages[i].fd == output_fd) { + m = &ctx->tx.messages[i]; + break; + } + } + + // In case there is no message for the fd: the error will be catched. + + enum ipccb r; + int is_valid = 0; + + is_valid = ipc_switching_get_ (&ctx->switchdb, output_fd, &sw); + + T_R ((is_valid == -1), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD); + + if (sw->orig == output_fd) { + if (sw->orig_in == NULL) { + r = default_cb_out (output_fd, m); + } + else { + r = (*sw->orig_out)(output_fd, m); + } + } + else { + if (sw->dest_in == NULL) { + r = default_cb_out (output_fd, m); + } + else { + r = (*sw->dest_out)(output_fd, m); + } + } + + // Whether or not the message has been sent, it should be removed. + // Freeing the message structure. + ipc_message_empty (m); + // Removing the message from the context. + ipc_messages_del (&ctx->tx, i); // remove the message indexed by i + + // Message reception OK: reading the message and put it in the list of messages to send. + if (r == IPC_CB_NO_ERROR) { + // 1. set event IPC_EVENT_TYPE_SWITCH, inform ipcd of a successful reception. + IPC_EVENT_SET (event, IPC_EVENT_TYPE_TX, index, output_fd, NULL); + // 2. IPC_RETURN_NO_ERROR + IPC_RETURN_NO_ERROR; + } + + /** + * NOTE: In any other case, the fd is, or should be closed. + */ + + // 1. close and remove both fd from switchdb + int delfd = ipc_switching_del (&ctx->switchdb, output_fd); + if (delfd >= 0) { + close (delfd); + ipc_del_fd (ctx, delfd); + } + close (output_fd); + ipc_del_fd (ctx, output_fd); + + // 2. set event (either error or disconnection) + if (r == IPC_CB_FD_CLOSING) { + IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, output_fd, NULL); + } + else { + IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, output_fd, NULL); + } + + // 3. return IPC_ERROR_CLOSED_RECIPIENT + IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT); +} diff --git a/src/print.c b/src/print.c index fe9c702..68dc534 100644 --- a/src/print.c +++ b/src/print.c @@ -1,20 +1,51 @@ #include "ipc.h" -void ipc_connection_print (struct ipc_connection_info *cinfo) +void ipc_ctx_print (struct ipc_ctx *ctx) { - T_R_NOTHING ((cinfo == NULL)); + printf ("Context contains:\n"); + for (size_t i = 0; i < ctx->size; i++) { + printf ("- fd %d\t", ctx->pollfd[i].fd); -#if 0 - LOG_DEBUG ("fd %d: index %d, version %d, type %c, path %s" - , cinfo->fd , cinfo->index, cinfo->version, cinfo->type - , (cinfo->spath == NULL) ? "-" : cinfo->spath); -#endif -} + switch (ctx->cinfos[i].type) { + case IPC_CONNECTION_TYPE_IPC: { + printf ("- ipc\n"); + break; + } + case IPC_CONNECTION_TYPE_EXTERNAL: { + printf ("- external\n"); + break; + } + case IPC_CONNECTION_TYPE_SERVER: { + printf ("- external\n"); + break; + } + case IPC_CONNECTION_TYPE_SWITCHED: { + printf ("- switched\n"); + break; + } + } + } -void ipc_connections_print (struct ipc_connection_infos *cinfos) -{ - for (size_t i = 0; i < cinfos->size; i++) { - ipc_connection_print (cinfos->cinfos[i]); + if (ctx->switchdb.size > 0) { + printf ("Context.switchdb contains:\n"); + for (size_t i = 0; i < ctx->switchdb.size; i++) { + printf ("- %d <-> %d\n" + , ctx->switchdb.collection[i].orig + , ctx->switchdb.collection[i].dest); + } + } + else { + printf ("Context.switchdb is empty\n"); + } + + if (ctx->tx.size > 0) { + printf ("Context.tx contains:\n"); + for (size_t i = 0; i < ctx->tx.size; i++) { + printf ("- message to %d\n", ctx->tx.messages[i].fd); + } + } + else { + printf ("Context.tx is empty\n"); } } diff --git a/src/service_path.c b/src/service_path.c new file mode 100644 index 0000000..7004a05 --- /dev/null +++ b/src/service_path.c @@ -0,0 +1,19 @@ +#include "ipc.h" + +struct ipc_error +service_path (char *path, const char *sname) +{ + T_R ((path == NULL), IPC_ERROR_SERVICE_PATH__NO_PATH); + T_R ((sname == NULL), IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME); + + memset (path, 0, PATH_MAX); + + char *rundir = getenv ("IPC_RUNDIR"); + if (rundir == NULL) + rundir = RUNDIR; + + snprintf (path, PATH_MAX - 1, "%s/%s", rundir, sname); + + IPC_RETURN_NO_ERROR; +} + diff --git a/src/usocket.c b/src/usocket.c index e462ec8..51e39fe 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -40,15 +40,6 @@ struct ipc_error usock_recv (const int32_t fd, char **buf, size_t * len) if (*len == 0) *len = IPC_MAX_MESSAGE_SIZE; - if (*buf == NULL) { - // do not allocate too much memory - if (*len > IPC_MAX_MESSAGE_SIZE) { - *len = IPC_MAX_MESSAGE_SIZE; - } - SECURE_BUFFER_HEAP_ALLOCATION (*buf, *len + IPC_HEADER_SIZE,, - IPC_RETURN_ERROR (IPC_ERROR_USOCK_RECV__HEAP_ALLOCATION)); - } - uint32_t msize = 0; uint32_t msize_read = 0; @@ -76,10 +67,6 @@ struct ipc_error usock_recv (const int32_t fd, char **buf, size_t * len) T_R ((msize > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_USOCK_RECV__MESSAGE_SIZE); msize_read += ret_recv - IPC_HEADER_SIZE; } else if (ret_recv < 0) { - if (*buf != NULL) { - free (*buf); - *buf = NULL; - } *len = 0; switch (errno) { @@ -130,10 +117,6 @@ struct ipc_error usock_recv (const int32_t fd, char **buf, size_t * len) // 1 on none byte received, indicates a closed recipient if (ret_recv == 0) { - if (*buf != NULL) { - free (*buf); - *buf = NULL; - } *len = 0; IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT); } diff --git a/tests/func_01_connection_establishment.c b/tests/func_01_connection_establishment.c index dbaafb0..8875987 100644 --- a/tests/func_01_connection_establishment.c +++ b/tests/func_01_connection_establishment.c @@ -6,28 +6,30 @@ #define SERVICE_NAME "pong" -int main(int argc, char * argv[], char **env) +int main(int argc, char * argv[]) { argc = (int) argc; argv = (char **) argv; SECURE_DECLARATION(struct ipc_error, ret); - SECURE_DECLARATION(struct ipc_connection_info,service); + SECURE_DECLARATION(struct ipc_ctx, ctx); SECURE_DECLARATION(struct ipc_event, event); - - ret = ipc_connection (env, &service, SERVICE_NAME); + + ret = ipc_connection (&ctx, SERVICE_NAME); if (ret.error_code != IPC_ERROR_NONE) { + printf ("error: %s\n", ipc_errors_get(ret.error_code)); return EXIT_FAILURE; } - // long timer = 10; + // int timer = 10000; // 10 seconds // ret = ipc_wait_event (services, struct ipc_event *event, &timer); // if (ret.error_code != IPC_ERROR_NONE) { // return EXIT_FAILURE; // } - ret = ipc_close (&service); + ret = ipc_close_all (&ctx); if (ret.error_code != IPC_ERROR_NONE) { + printf ("error: %s\n", ipc_errors_get(ret.error_code)); return EXIT_FAILURE; } diff --git a/tests/func_01_connection_establishmentd.c b/tests/func_01_connection_establishmentd.c index ad8b4f7..3ad7ff1 100644 --- a/tests/func_01_connection_establishmentd.c +++ b/tests/func_01_connection_establishmentd.c @@ -6,31 +6,30 @@ #define SERVICE_NAME "pong" -int main(int argc, char * argv[], char **env) +int main(int argc, char * argv[]) { argc = (int) argc; argv = (char **) argv; - SECURE_DECLARATION(struct ipc_connection_info,srv); - long timer = 10; + SECURE_DECLARATION(struct ipc_ctx, ctx); + int timer = 10000; // 10 seconds timer printf ("func 01 - server init...\n"); - TEST_IPC_Q(ipc_server_init (env, &srv, SERVICE_NAME), EXIT_FAILURE); - + TEST_IPC_Q(ipc_server_init (&ctx, SERVICE_NAME), EXIT_FAILURE); + printf ("func 01 - server init ok\n"); - SECURE_DECLARATION(struct ipc_connection_infos, clients); - SECURE_DECLARATION(struct ipc_event,event); + SECURE_DECLARATION(struct ipc_event, event); printf ("func 01 - service polling...\n"); // listen only for a single client - TEST_IPC_Q(ipc_wait_event (&clients, &srv, &event, &timer), EXIT_FAILURE); + TEST_IPC_Q(ipc_wait_event (&ctx, &event, &timer), EXIT_FAILURE); switch (event.type) { case IPC_EVENT_TYPE_TIMER : { fprintf(stderr, "time up!\n"); - timer = 10; + timer = 10000; }; break; case IPC_EVENT_TYPE_CONNECTION : @@ -49,11 +48,11 @@ int main(int argc, char * argv[], char **env) break; } - printf ("func 01 - closing clients...\n"); - ipc_connections_free (&clients); - printf ("func 01 - closing server...\n"); - TEST_IPC_Q(ipc_server_close(&srv), EXIT_FAILURE); + TEST_IPC_Q(ipc_close_all(&ctx), EXIT_FAILURE); + + printf ("func 01 - closing ctx...\n"); + ipc_ctx_free (&ctx); return EXIT_SUCCESS; } diff --git a/tests/func_02_pong.c b/tests/func_02_pong.c index af66365..98c80af 100644 --- a/tests/func_02_pong.c +++ b/tests/func_02_pong.c @@ -13,48 +13,50 @@ fprintf(stderr, "error while %s: %s\n", msg, err);\ } -void non_interactive (char *env[]) +void non_interactive () { - struct ipc_message m; - memset (&m, 0, sizeof (struct ipc_message)); - SECURE_DECLARATION(struct ipc_connection_info, srv); + SECURE_DECLARATION(struct ipc_message, m); + SECURE_DECLARATION(struct ipc_ctx, ctx); // init service - TEST_IPC_Q(ipc_connection (env, &srv, SERVICE_NAME), EXIT_FAILURE); + TEST_IPC_Q(ipc_connection (&ctx, SERVICE_NAME), EXIT_FAILURE); - printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen(MSG) +1, (int) strlen(MSG), MSG); + int server_fd = ctx.pollfd[0].fd; + + printf ("msg for fd %d to send (%ld): %.*s\n" + , server_fd + , (ssize_t) strlen(MSG) +1, (int) strlen(MSG), MSG); TEST_IPC_Q(ipc_message_format_data (&m, /* type */ 'a', MSG, (ssize_t) strlen(MSG) +1), EXIT_FAILURE); - TEST_IPC_Q(ipc_write (&srv, &m), EXIT_FAILURE); - TEST_IPC_Q(ipc_read (&srv, &m), EXIT_FAILURE); + + m.fd = server_fd; + TEST_IPC_Q(ipc_write_fd (server_fd, &m), EXIT_FAILURE); + TEST_IPC_Q(ipc_read (&ctx, 0 /* only one option */, &m), EXIT_FAILURE); printf ("msg recv: %s\n", m.payload); ipc_message_empty (&m); - TEST_IPC_Q(ipc_close (&srv), EXIT_FAILURE); + TEST_IPC_Q(ipc_close_all (&ctx), EXIT_FAILURE); + ipc_ctx_free (&ctx); } -void interactive (char *env[]) +#if 0 +void interactive () { - SECURE_DECLARATION(struct ipc_connection_info, srv); - - // index and version should be filled - srv.index = 0; - srv.version = 0; + SECURE_DECLARATION(struct ipc_ctx, ctx); // init service - TEST_IPC_Q(ipc_connection (env, &srv, SERVICE_NAME), EXIT_FAILURE); + TEST_IPC_Q(ipc_connection (&ctx, SERVICE_NAME), EXIT_FAILURE); + + int server_fd = ctx.pollfd[0].fd; SECURE_DECLARATION(struct ipc_event, event); - SECURE_DECLARATION(struct ipc_connection_infos, services); - - TEST_IPC_Q(ipc_add (&services, &srv), EXIT_FAILURE); long timer = 10; while (1) { printf ("msg to send: "); fflush (stdout); - TEST_IPC_Q(ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE); + TEST_IPC_Q(ipc_wait_event (&ctx, &event, &timer), EXIT_FAILURE); switch (event.type) { case IPC_EVENT_TYPE_TIMER: { @@ -71,14 +73,16 @@ void interactive (char *env[]) ipc_message_empty (m); free (m); - ipc_connections_free (&services); + TEST_IPC_Q(ipc_close_all (&ctx), EXIT_FAILURE); - TEST_IPC_Q(ipc_close (&srv), EXIT_FAILURE); + ipc_ctx_free (&ctx); exit (EXIT_SUCCESS); } - TEST_IPC_Q(ipc_write (&srv, m), EXIT_FAILURE); + m->fd = server_fd; + + TEST_IPC_Q(ipc_write (&ctx, m), EXIT_FAILURE); } break; case IPC_EVENT_TYPE_MESSAGE: @@ -96,16 +100,19 @@ void interactive (char *env[]) } } } +#endif -int main (int argc, char *argv[], char *env[]) +//int main (int argc, char *argv[]) +int main (void) { - argc = argc; // warnings - argv = argv; // warnings + non_interactive (); +#if 0 if (argc == 1) - non_interactive (env); + non_interactive (); else - interactive (env); + interactive (); +#endif return EXIT_SUCCESS; } diff --git a/tests/func_02_pongd.c b/tests/func_02_pongd.c index cdeb9a2..5349082 100644 --- a/tests/func_02_pongd.c +++ b/tests/func_02_pongd.c @@ -14,71 +14,67 @@ int cpt = 0; -struct ipc_connection_info *srv = 0; -struct ipc_connection_infos *clients; +struct ipc_ctx *ctx; void main_loop () { SECURE_DECLARATION(struct ipc_error, ret); + SECURE_DECLARATION(struct ipc_event, event); - clients = malloc (sizeof (struct ipc_connection_infos)); - memset(clients, 0, sizeof(struct ipc_connection_infos)); - - SECURE_DECLARATION(struct ipc_event,event); - - long timer = 10; + int timer = 10000; while(1) { // ipc_wait_event provides one event at a time // warning: event->m is free'ed if not NULL - ret = ipc_wait_event (clients, srv, &event, &timer); + ret = ipc_wait_event (ctx, &event, &timer); if (ret.error_code != IPC_ERROR_NONE && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) { PRINTERR(ret,"service poll event"); // the application will shut down, and close the service - TEST_IPC_Q(ipc_server_close (srv), EXIT_FAILURE); + TEST_IPC_Q(ipc_close_all (ctx), EXIT_FAILURE); exit (EXIT_FAILURE); } switch (event.type) { case IPC_EVENT_TYPE_TIMER: { fprintf(stderr, "time up!\n"); - timer = 10; + timer = 10000; }; break; case IPC_EVENT_TYPE_CONNECTION: { cpt++; - printf ("connection: %d clients connected\n", cpt); - printf ("new client has the fd %d\n", ((struct ipc_connection_info*) event.origin)->fd); + // printf ("new connection (fd %d): %d ctx connected\n", event.origin, cpt); }; break; case IPC_EVENT_TYPE_DISCONNECTION: { cpt--; - printf ("disconnection: %d clients remaining\n", cpt); - - // free the ipc_connection_info structure - free (event.origin); + // printf ("disconnection (fd %d): %d clients remaining\n", event.origin, cpt); }; break; case IPC_EVENT_TYPE_MESSAGE: { struct ipc_message *m = event.m; if (m->length > 0) { - printf ("message received (type %d): %.*s\n", m->type, m->length, m->payload); + // printf ("message received (type %d): %.*s\n", m->type, m->length, m->payload); } - ret = ipc_write (event.origin, m); + m->fd = event.origin; + ret = ipc_write (ctx, m); if (ret.error_code != IPC_ERROR_NONE) { PRINTERR(ret,"server write"); } }; break; + case IPC_EVENT_TYPE_TX: + { + // printf ("a message was sent\n"); + } + break; case IPC_EVENT_TYPE_ERROR: { - fprintf (stderr, "a problem happened with client %d\n" - , ((struct ipc_connection_info*) event.origin)->fd); + fprintf (stderr, "a problem happened with client %d\n", event.origin); }; break; default : @@ -97,48 +93,34 @@ 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]; - if (cli != NULL) { - free (cli); - } - clients->cinfos[i] = NULL; - } - - ipc_connections_free (clients); - free (clients); - - // the application will shut down, and close the service - TEST_IPC_Q(ipc_server_close (srv), EXIT_FAILURE); - free (srv); + TEST_IPC_Q(ipc_close_all (ctx), EXIT_FAILURE); + + // free remaining ctx + ipc_ctx_free (ctx); + free (ctx); exit(EXIT_SUCCESS); } /* - * 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 */ -int main(int argc, char * argv[], char **env) +int main(void) { - argc = argc; // warnings - argv = argv; // warnings - printf ("pid = %d\n", getpid ()); - srv = malloc (sizeof (struct ipc_connection_info)); - if (srv == NULL) { + ctx = malloc (sizeof (struct ipc_ctx)); + if (ctx == NULL) { exit (1); } - memset (srv, 0, sizeof (struct ipc_connection_info)); - srv->index = 0; - srv->version = 0; + memset (ctx, 0, sizeof (struct ipc_ctx)); - TEST_IPC_Q(ipc_server_init (env, srv, PONGD_SERVICE_NAME), EXIT_FAILURE); + TEST_IPC_Q(ipc_server_init (ctx, PONGD_SERVICE_NAME), EXIT_FAILURE); + struct ipc_connection_info * srv = &ctx->cinfos[0]; printf ("Listening on %s.\n", srv->spath); printf("MAIN: server created\n" ); diff --git a/tests/func_03_multiple-communications-client.c b/tests/func_03_multiple-communications-client.c index a8f8745..c659acf 100644 --- a/tests/func_03_multiple-communications-client.c +++ b/tests/func_03_multiple-communications-client.c @@ -9,7 +9,7 @@ // test the behavior of the server when the client never read its messages -void send_message (struct ipc_connection_info *ci) +void send_message (struct ipc_ctx *ctx) { SECURE_DECLARATION (struct ipc_message, m); SECURE_MALLOC (m.payload, 5, exit(EXIT_FAILURE)); @@ -18,23 +18,24 @@ void send_message (struct ipc_connection_info *ci) m.user_type = 42; m.length = 5; - ipc_write (ci, &m); + ipc_write_fd (ctx->pollfd[0].fd /* only one connection */, &m); ipc_message_empty (&m); } -void read_message (struct ipc_connection_info *ci) +void read_message (struct ipc_ctx *ctx) { #if 0 SECURE_DECLARATION(struct ipc_event, event); - SECURE_DECLARATION(struct ipc_connection_infos, clients); + SECURE_DECLARATION (struct ipc_message, m); - long timer = 10; + int timer = 10000; - TEST_IPC_Q(ipc_read (ci, &m), EXIT_FAILURE); + // ctx, index, message + TEST_IPC_Q(ipc_read (ctx, 0 /* only one server here */, &m), EXIT_FAILURE); - ipc_wait_event (&clients, NULL, &event, &timer); + ipc_wait_event (ctx, &event, &timer); switch (event.type) { case IPC_EVENT_TYPE_MESSAGE : { @@ -52,37 +53,34 @@ void read_message (struct ipc_connection_info *ci) break; } - ipc_connections_free (&clients); + ipc_ctx_free (ctx); #else SECURE_DECLARATION (struct ipc_message, m); - TEST_IPC_Q(ipc_read (ci, &m), EXIT_FAILURE); + TEST_IPC_Q(ipc_read (ctx, 0 /* only one server here */, &m), EXIT_FAILURE); printf ("received message: %*.s\n", m.length, m.payload); free (m.payload); #endif } -int main(int argc, char * argv[], char **env) +int main(void) { - argc = argc; - argv = argv; - - SECURE_DECLARATION(struct ipc_connection_info,srv1); - SECURE_DECLARATION(struct ipc_connection_info,srv2); + SECURE_DECLARATION(struct ipc_ctx, ctx1); + SECURE_DECLARATION(struct ipc_ctx, ctx2); SECURE_DECLARATION(struct ipc_event, event); - TEST_IPC_Q (ipc_connection (env, &srv1, SERVICE_NAME), EXIT_FAILURE); - TEST_IPC_Q (ipc_connection (env, &srv2, SERVICE_NAME), EXIT_FAILURE); + TEST_IPC_Q (ipc_connection (&ctx1, SERVICE_NAME), EXIT_FAILURE); + TEST_IPC_Q (ipc_connection (&ctx2, SERVICE_NAME), EXIT_FAILURE); - send_message (&srv1); - read_message (&srv1); + send_message (&ctx1); + read_message (&ctx1); - TEST_IPC_Q (ipc_close (&srv1), EXIT_FAILURE); + TEST_IPC_Q (ipc_close_all (&ctx1), EXIT_FAILURE); - send_message (&srv2); - read_message (&srv2); + send_message (&ctx2); + read_message (&ctx2); - TEST_IPC_Q (ipc_close (&srv2), EXIT_FAILURE); + TEST_IPC_Q (ipc_close_all (&ctx2), EXIT_FAILURE); return EXIT_SUCCESS; } diff --git a/tests/func_03_multiple-communications-server.c b/tests/func_03_multiple-communications-server.c index cfbe8f4..688d839 100644 --- a/tests/func_03_multiple-communications-server.c +++ b/tests/func_03_multiple-communications-server.c @@ -7,43 +7,46 @@ #define SERVICE_NAME "pong" -int main_loop(int argc, char * argv[], char **env) +int main_loop(int argc, char * argv[]) { argc = argc; argv = argv; - SECURE_DECLARATION (struct ipc_connection_info, srv); - long timer = 10; + SECURE_DECLARATION (struct ipc_ctx, ctx); + int timer = 10000; // in ms printf ("func 03 - server init...\n"); - TEST_IPC_Q (ipc_server_init (env, &srv, SERVICE_NAME), EXIT_FAILURE); + TEST_IPC_Q (ipc_server_init (&ctx, SERVICE_NAME), EXIT_FAILURE); printf ("func 03 - server init ok\n"); - SECURE_DECLARATION (struct ipc_connection_infos, clients); SECURE_DECLARATION (struct ipc_event, event); printf ("func 01 - service polling...\n"); // listen only for a single client while (1) { - TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&clients, &srv, &event, &timer), EXIT_FAILURE); + TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&ctx, &event, &timer), EXIT_FAILURE); switch (event.type) { case IPC_EVENT_TYPE_TIMER : { - fprintf (stderr, "time up!"); - timer = 10; + fprintf (stderr, "time up!\n"); + timer = 10000; } break; case IPC_EVENT_TYPE_CONNECTION : { - printf ("connection establishment: %d \n", event.origin->fd); + printf ("connection establishment: %d \n", event.origin); } break; case IPC_EVENT_TYPE_DISCONNECTION : { - printf ("client %d disconnecting\n", event.origin->fd); + printf ("client %d disconnecting\n", event.origin); }; break; case IPC_EVENT_TYPE_MESSAGE : { printf ("received message: %s\n", ((struct ipc_message*) event.m)->payload); - ipc_write (event.origin, (struct ipc_message*) event.m); + ipc_write (&ctx, (struct ipc_message*) event.m); + } + break; + case IPC_EVENT_TYPE_TX : { + printf ("message sent to fd %d\n", event.origin); } break; case IPC_EVENT_TYPE_NOT_SET : @@ -56,10 +59,11 @@ int main_loop(int argc, char * argv[], char **env) } } - printf ("func 03 - closing clients...\n"); - ipc_connections_free (&clients); printf ("func 03 - closing server...\n"); - TEST_IPC_Q (ipc_server_close(&srv), EXIT_FAILURE); + TEST_IPC_Q (ipc_close_all(&ctx), EXIT_FAILURE); + + printf ("func 03 - freeing the context\n"); + ipc_ctx_free (&ctx); return 0; } @@ -71,7 +75,7 @@ void exit_program(int signal) } -int main(int argc, char * argv[], char **env) +int main(int argc, char * argv[]) { signal (SIGHUP, exit_program); signal (SIGALRM, exit_program); @@ -79,6 +83,6 @@ int main(int argc, char * argv[], char **env) signal (SIGUSR2, exit_program); signal (SIGTERM, exit_program); signal (SIGINT, exit_program); - main_loop (argc, argv, env); + main_loop (argc, argv); return EXIT_SUCCESS; } diff --git a/tests/func_04_empty_message.c b/tests/func_04_empty_message.c index a1b2b48..d096ed8 100644 --- a/tests/func_04_empty_message.c +++ b/tests/func_04_empty_message.c @@ -9,7 +9,7 @@ // test the behavior of the server when the client never read its messages -void send_message (struct ipc_connection_info *ci) +void send_message (struct ipc_ctx *ctx) { SECURE_DECLARATION (struct ipc_message, m); SECURE_MALLOC (m.payload, 1, exit(EXIT_FAILURE)); @@ -17,18 +17,20 @@ void send_message (struct ipc_connection_info *ci) m.type = MSG_TYPE_DATA; m.user_type = 42; m.length = 0; + m.fd = ctx->pollfd[0].fd; - ipc_write (ci, &m); + // ipc_write_fd = write now, without waiting the fd to become available + ipc_write_fd (ctx->pollfd[0].fd, &m); ipc_message_empty (&m); } -void read_message (struct ipc_connection_info *ci) +void read_message (struct ipc_ctx *ctx) { SECURE_DECLARATION (struct ipc_message, m); - ipc_read (ci, &m); + ipc_read (ctx, 0 /* there is only one valid index */, &m); if (m.length > 0) { printf ("received message: %*.s\n", m.length, m.payload); } @@ -41,19 +43,16 @@ void read_message (struct ipc_connection_info *ci) free (m.payload); } -int main(int argc, char * argv[], char **env) +int main(void) { - argc = argc; - argv = argv; + SECURE_DECLARATION(struct ipc_ctx, ctx); - SECURE_DECLARATION(struct ipc_connection_info,srv1); + TEST_IPC_Q(ipc_connection (&ctx, SERVICE_NAME), EXIT_FAILURE); - TEST_IPC_Q(ipc_connection (env, &srv1, SERVICE_NAME), EXIT_FAILURE); + send_message (&ctx); + read_message (&ctx); - send_message (&srv1); - read_message (&srv1); - - TEST_IPC_Q(ipc_close (&srv1), EXIT_FAILURE); + TEST_IPC_Q(ipc_close_all (&ctx), EXIT_FAILURE); return EXIT_SUCCESS; } diff --git a/tests/func_05_read-write-loop.c b/tests/func_05_read-write-loop.c index 77b9f26..787c933 100644 --- a/tests/func_05_read-write-loop.c +++ b/tests/func_05_read-write-loop.c @@ -1,4 +1,5 @@ -#define _BSD_SOURCE +// #define _BSD_SOURCE +#define _DEFAULT_SOURCE #include "../src/ipc.h" @@ -12,9 +13,9 @@ #define DEFAULT_MSG "coucou" -int main(int argc, char * argv[], char **env) +int main(int argc, char * argv[]) { - SECURE_DECLARATION(struct ipc_connection_info,srv); + SECURE_DECLARATION(struct ipc_ctx, ctx); SECURE_DECLARATION(struct ipc_event, event); SECURE_DECLARATION (struct ipc_message, write_m); @@ -46,20 +47,21 @@ int main(int argc, char * argv[], char **env) memcpy(message_str, DEFAULT_MSG, strlen(DEFAULT_MSG)); } - TEST_IPC_Q (ipc_connection (env, &srv, SERVICE_NAME), EXIT_FAILURE); + TEST_IPC_Q (ipc_connection (&ctx, SERVICE_NAME), EXIT_FAILURE); SECURE_MALLOC (write_m.payload, strlen(message_str), exit(EXIT_FAILURE)); memcpy (write_m.payload, message_str, strlen(message_str)); write_m.type = MSG_TYPE_DATA; write_m.user_type = 42; + write_m.fd = ctx.pollfd[0].fd; write_m.length = strlen(message_str); gettimeofday(&tval_before, NULL); for (size_t i = 0 ; i < nb_rounds ; i++) { - ipc_write (&srv, &write_m); + ipc_write_fd (ctx.pollfd[0].fd, &write_m); // reading - TEST_IPC_Q(ipc_read (&srv, &read_m), EXIT_FAILURE); + TEST_IPC_Q(ipc_read (&ctx, 0 /* only valid index */, &read_m), EXIT_FAILURE); // printf ("received message (%d bytes): %*s\n", read_m.length, read_m.length, read_m.payload); // ipc_message_empty (&read_m); @@ -71,7 +73,7 @@ int main(int argc, char * argv[], char **env) printf("Time elapsed: %ld.%06ld\n", (long int)tval_result.tv_sec, (long int)tval_result.tv_usec); // disconnection - TEST_IPC_Q (ipc_close (&srv), EXIT_FAILURE); + TEST_IPC_Q (ipc_close_all (&ctx), EXIT_FAILURE); return EXIT_SUCCESS; } diff --git a/tests/unit_01_service-path.c b/tests/unit_01_service-path.c index cf2d531..2ac6ac9 100644 --- a/tests/unit_01_service-path.c +++ b/tests/unit_01_service-path.c @@ -5,27 +5,21 @@ #include #define SERVICE_NAME "example" -#define VERSION 0 -#define INDEX 0 int main(int argc, char * argv[]) { char path[PATH_MAX]; char * sname = SERVICE_NAME; - int32_t index = INDEX; - int32_t version = VERSION; - if (argc == 4) { + if (argc == 2) { sname = argv[1]; - index = atoi(argv[2]); - version = atoi(argv[3]); } else if (argc != 1) { fprintf (stderr, "usage: %s [service-name index version]\n", argv[0]); return EXIT_FAILURE; } - service_path (path, sname, index, version); + service_path (path, sname); // printf ("servicename: %s, index: %d, version: %d\n", sname, index, version); printf ("%s\n", path);