diff --git a/Makefile b/Makefile index 567fa5c..980ca4e 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ MANDIR := $(SHAREDIR)/man CC := cc AR := ar RANLIB := ranlib -CFLAGS := -g +CFLAGS := -Wall -Wextra -g LDFLAGS := Q := @ @@ -19,7 +19,7 @@ Q := @ all: libipc src/ipc.h man/libipc.7 @: -libipc: libipc.so libipc.a +libipc: libipc.so libipc.a @: libipc.install: libipc.so.install libipc.a.install @@ -27,7 +27,7 @@ libipc.clean: libipc.so.clean libipc.a.clean libipc.uninstall: libipc.so.uninstall libipc.a.uninstall -src/ipc.h.install: src/ipc.h +src/ipc.h.install: src/ipc.h src @echo ' IN > $(INCLUDEDIR)/ipc.h' $(Q)mkdir -p '$(DESTDIR)$(INCLUDEDIR)' $(Q)install -m0644 src/ipc.h $(DESTDIR)$(INCLUDEDIR)/ipc.h @@ -39,7 +39,7 @@ src/ipc.h.uninstall: @echo ' RM > $(INCLUDEDIR)/ipc.h' $(Q)rm -f '$(DESTDIR)$(INCLUDEDIR)/ipc.h' -man/libipc.7: man/libipc.7.md +man/libipc.7: man/libipc.7.md man @echo ' MAN > man/libipc.7' $(Q)pandoc -s --from markdown --to man 'man/libipc.7.md' -o 'man/libipc.7' @@ -57,9 +57,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/logger.o src/message.o src/usocket.o src/utils.o +libipc.so: src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o @echo ' LD > libipc.so' - $(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/communication.o src/error.o src/logger.o src/message.o src/usocket.o src/utils.o + $(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o libipc.so.install: libipc.so @echo ' IN > $(LIBDIR)/libipc.so.0.1.0' @@ -86,9 +86,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/logger.o src/message.o src/usocket.o src/utils.o +libipc.a: src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o @echo ' LD > libipc.a' - $(Q)$(AR) rc 'libipc.a' src/communication.o src/error.o src/logger.o src/message.o src/usocket.o src/utils.o + $(Q)$(AR) rc 'libipc.a' src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o libipc.a.install: libipc.a @echo ' IN > $(LIBDIR)/libipc.a' @@ -103,9 +103,9 @@ libipc.a.uninstall: @echo ' RM > $(LIBDIR)/libipc.a' $(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.a' -src/communication.o: src/communication.c src/ipc.h src/utils.h src/message.h +src/communication.o: src/communication.c src/ipc.h src/utils.h src/message.h @echo ' CC > src/communication.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/communication.c -fPIC -o src/communication.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/communication.c -fPIC -std=c11 -o src/communication.o src/communication.o.install: @@ -115,9 +115,9 @@ src/communication.o.clean: src/communication.o.uninstall: -src/error.o: src/error.c src/ipc.h +src/error.o: src/error.c src/ipc.h @echo ' CC > src/error.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/error.c -fPIC -o src/error.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/error.c -fPIC -std=c11 -o src/error.o src/error.o.install: @@ -127,9 +127,9 @@ src/error.o.clean: src/error.o.uninstall: -src/logger.o: src/logger.c src/logger.h +src/logger.o: src/logger.c src/logger.h @echo ' CC > src/logger.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/logger.c -fPIC -o src/logger.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/logger.c -fPIC -std=c11 -o src/logger.o src/logger.o.install: @@ -139,9 +139,9 @@ src/logger.o.clean: src/logger.o.uninstall: -src/message.o: src/message.c src/message.h src/usocket.h +src/message.o: src/message.c src/message.h src/usocket.h @echo ' CC > src/message.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/message.c -fPIC -o src/message.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/message.c -fPIC -std=c11 -o src/message.o src/message.o.install: @@ -151,9 +151,21 @@ src/message.o.clean: src/message.o.uninstall: -src/usocket.o: src/usocket.c src/usocket.h src/utils.h +src/network.o: src/network.c src/ipc.h + @echo ' CC > src/network.o' + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/network.c -fPIC -std=c11 -o src/network.o + +src/network.o.install: + +src/network.o.clean: + @echo ' RM > src/network.o' + $(Q)rm -f src/network.o + +src/network.o.uninstall: + +src/usocket.o: src/usocket.c src/usocket.h src/utils.h @echo ' CC > src/usocket.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/usocket.c -fPIC -o src/usocket.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/usocket.c -fPIC -std=c11 -o src/usocket.o src/usocket.o.install: @@ -163,9 +175,9 @@ src/usocket.o.clean: src/usocket.o.uninstall: -src/utils.o: src/utils.c src/utils.h +src/utils.o: src/utils.c src/utils.h src/ipc.h @echo ' CC > src/utils.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/utils.c -fPIC -o src/utils.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/utils.c -fPIC -std=c11 -o src/utils.o src/utils.o.install: @@ -175,6 +187,10 @@ src/utils.o.clean: src/utils.o.uninstall: +src: + $(Q)mkdir -p src +man: + $(Q)mkdir -p man $(DESTDIR)$(PREFIX): @echo ' DIR > $(PREFIX)' $(Q)mkdir -p $(DESTDIR)$(PREFIX) @@ -193,12 +209,12 @@ $(DESTDIR)$(INCLUDEDIR): $(DESTDIR)$(MANDIR): @echo ' DIR > $(MANDIR)' $(Q)mkdir -p $(DESTDIR)$(MANDIR) -install: subdirs.install libipc.install src/ipc.h.install man/libipc.7.install libipc.so.install libipc.a.install src/communication.o.install src/error.o.install src/logger.o.install src/message.o.install src/usocket.o.install src/utils.o.install src/communication.o.install src/error.o.install src/logger.o.install src/message.o.install src/usocket.o.install src/utils.o.install +install: subdirs.install libipc.install src/ipc.h.install man/libipc.7.install libipc.so.install libipc.a.install src/communication.o.install src/error.o.install src/logger.o.install src/message.o.install src/network.o.install src/usocket.o.install src/utils.o.install src/communication.o.install src/error.o.install src/logger.o.install src/message.o.install src/network.o.install src/usocket.o.install src/utils.o.install @: subdirs.install: -uninstall: subdirs.uninstall libipc.uninstall src/ipc.h.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/communication.o.uninstall src/error.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/communication.o.uninstall src/error.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall +uninstall: subdirs.uninstall libipc.uninstall src/ipc.h.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/communication.o.uninstall src/error.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/network.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/communication.o.uninstall src/error.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/network.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall @: subdirs.uninstall: @@ -208,7 +224,7 @@ test: all subdirs subdirs.test subdirs.test: -clean: libipc.clean src/ipc.h.clean man/libipc.7.clean libipc.so.clean libipc.a.clean src/communication.o.clean src/error.o.clean src/logger.o.clean src/message.o.clean src/usocket.o.clean src/utils.o.clean src/communication.o.clean src/error.o.clean src/logger.o.clean src/message.o.clean src/usocket.o.clean src/utils.o.clean +clean: libipc.clean src/ipc.h.clean man/libipc.7.clean libipc.so.clean libipc.a.clean src/communication.o.clean src/error.o.clean src/logger.o.clean src/message.o.clean src/network.o.clean src/usocket.o.clean src/utils.o.clean src/communication.o.clean src/error.o.clean src/logger.o.clean src/message.o.clean src/network.o.clean src/usocket.o.clean src/utils.o.clean distclean: clean @@ -231,6 +247,7 @@ $(PACKAGE)-$(VERSION).tar.gz: distdir $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/logger.c \ $(PACKAGE)-$(VERSION)/src/message.c \ + $(PACKAGE)-$(VERSION)/src/network.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ $(PACKAGE)-$(VERSION)/src/logger.h \ @@ -250,6 +267,7 @@ $(PACKAGE)-$(VERSION).tar.xz: distdir $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/logger.c \ $(PACKAGE)-$(VERSION)/src/message.c \ + $(PACKAGE)-$(VERSION)/src/network.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ $(PACKAGE)-$(VERSION)/src/logger.h \ @@ -269,6 +287,7 @@ $(PACKAGE)-$(VERSION).tar.bz2: distdir $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/logger.c \ $(PACKAGE)-$(VERSION)/src/message.c \ + $(PACKAGE)-$(VERSION)/src/network.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ $(PACKAGE)-$(VERSION)/src/logger.h \ diff --git a/README.md b/README.md index cb7d402..1dccfcc 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,14 @@ libipc - Simple, easy-to-use IPC library See the introductory [man page](man/libipc.7.md). +# Compilation + +`make` + + +# logging system + +Logs are in one of the following directories: `$XDG_DATA_HOME/ipc/` or `$HOME/.local/share/ipc/`. +The log file can be indicated with the `IPC_LOGFILE` environment variable, too. + +To remove logs: `make LDFLAGS=-DIPC_WITHOUT_ERRORS` diff --git a/drop/build.sh b/drop/build.sh new file mode 100755 index 0000000..a77e6d2 --- /dev/null +++ b/drop/build.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +nontapmsg() { + echo $* +} + +if [ $# -eq 0 ] ; then + SRC="*.c" +else + SRC="$*" +fi + +for i in $SRC +do + BIN=$(echo ${i} | sed "s/.c$/.bin/") + if [ ! -f ${BIN} ] || [ $(stat -c "%X" ${BIN}) -lt $(stat -c "%X" ${i}) ] + then + nontapmsg "compiling ${BIN}" + # gcc $BIN.c ./lib/*.o -o $BIN -I../src -I ./lib/ -L../ -L./lib/ -lipc -Wall -g -Wextra + gcc -Wall -g -Wextra "${i}" -o "${BIN}" -I../src -L../ ../src/ipc.h -lipc + touch "${BIN}" + fi +done diff --git a/drop/print-bytes.c b/drop/print-bytes.c new file mode 100644 index 0000000..4dcda06 --- /dev/null +++ b/drop/print-bytes.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include + +#include "../src/ipc.h" + +int main(int argc, char * argv[]) +{ + SECURE_BUFFER_DECLARATION (char, buffer, 4096); + uint32_t msize = 0; + char *message = "coucou"; + + if (argc == 2) { + message = argv[1]; + } + + msize = ipc_message_raw_serialize (buffer, 2, 42, message, strlen(message)); + write (1, buffer, msize); + fflush (stdout); + + // to wait for a response + sleep (1); + + return EXIT_SUCCESS; +} diff --git a/drop/to-pascal.pl b/drop/to-pascal.pl new file mode 100644 index 0000000..61a18da --- /dev/null +++ b/drop/to-pascal.pl @@ -0,0 +1,9 @@ +#!/usr/bin/perl -w +use v5.14; + +while(<>) { + chomp; + my @wl = split "_\+"; + my @wl2 = map { ucfirst lc } @wl; + say join "", @wl2; +} diff --git a/examples/build.sh b/examples/build.sh index 8c14e3e..a77e6d2 100755 --- a/examples/build.sh +++ b/examples/build.sh @@ -4,10 +4,20 @@ nontapmsg() { echo $* } -for i in *.c +if [ $# -eq 0 ] ; then + SRC="*.c" +else + SRC="$*" +fi + +for i in $SRC do - f=`echo $i | sed "s/.c$//"` - nontapmsg "compiling $f" - # gcc $f.c ./lib/*.o -o $f -I../src -I ./lib/ -L../ -L./lib/ -lipc -Wall -g -Wextra - gcc -Wall -g -Wextra $f.c -o $f -I../src -L../ ../src/ipc.h -lipc + BIN=$(echo ${i} | sed "s/.c$/.bin/") + if [ ! -f ${BIN} ] || [ $(stat -c "%X" ${BIN}) -lt $(stat -c "%X" ${i}) ] + then + nontapmsg "compiling ${BIN}" + # gcc $BIN.c ./lib/*.o -o $BIN -I../src -I ./lib/ -L../ -L./lib/ -lipc -Wall -g -Wextra + gcc -Wall -g -Wextra "${i}" -o "${BIN}" -I../src -L../ ../src/ipc.h -lipc + touch "${BIN}" + fi done diff --git a/examples/fd-exchange-providing.c b/examples/fd-exchange-providing.c new file mode 100644 index 0000000..799a1d1 --- /dev/null +++ b/examples/fd-exchange-providing.c @@ -0,0 +1,31 @@ +#include +#include +#include + +#include +#include +#include + +#include "../src/ipc.h" +#include "../src/usocket.h" + +// This program opens a file then provide it to another running program. +// see examples/fd-exchange-receiving.c + +int main(int argc, char * argv[]) +{ + if (argc != 2) { + fprintf (stderr, "usage: %s file", argv[0]); + exit (EXIT_FAILURE); + } + + int sock = 0; + int fd = 0; + + T_PERROR_R (((fd = open (argv[1], O_CREAT | O_RDWR)) < 0), "cannot open the file", EXIT_FAILURE); + + TIPC_P_Q (usock_connect (&sock, "SOCKET_FD_EXCHANGE_TEST"), "trying to connect to the unix socket", EXIT_FAILURE); + TIPC_P_Q (ipc_provide_fd (sock, fd), "cannot send the file descriptor", EXIT_FAILURE); + + return EXIT_SUCCESS; +} diff --git a/examples/fd-exchange-receiving.c b/examples/fd-exchange-receiving.c new file mode 100644 index 0000000..1436651 --- /dev/null +++ b/examples/fd-exchange-receiving.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include "../src/ipc.h" +#include "../src/usocket.h" + +// This program receives an open file descriptor from another running program. +// see examples/fd-exchange-providing.c + +int main(int argc, char * argv[]) +{ + if (argc != 1) { + fprintf (stderr, "usage: %s", argv[0]); + exit (EXIT_FAILURE); + } + + int usock = 0; + int usockclient = 0; + int fd = 0; + + TIPC_P_Q (usock_init (&usock, "SOCKET_FD_EXCHANGE_TEST"), "trying to connect to the unix socket", EXIT_FAILURE); + TIPC_P_Q (usock_accept (usock, &usockclient), "cannot accept a client from the unix socket", EXIT_FAILURE); + TIPC_P_Q (ipc_receive_fd (usockclient, &fd), "cannot receive the file descriptor", EXIT_FAILURE); + + T_PERROR_R ((write (fd, "coucou\n", 7) < 0), "cannot write a message in the file", EXIT_FAILURE); + T_PERROR_R ((close (fd) < 0), "cannot close the file descriptor", EXIT_FAILURE); + + TIPC_P_Q (usock_close (usock), "cannot close the unix socket", EXIT_FAILURE); + + return EXIT_SUCCESS; +} diff --git a/examples/pong.c b/examples/pong.c index eea4b60..f15e565 100644 --- a/examples/pong.c +++ b/examples/pong.c @@ -13,115 +13,79 @@ fprintf(stderr, "error while %s: %s\n", msg, err);\ } +void chomp (char *str, ssize_t len) { + if (str[len -1] == '\n') { + str[len -1] = '\0'; + } + if (str[len -2] == '\n') { + str[len -2] = '\0'; + } +} + struct ipc_connection_info *srv; void non_interactive (char *env[]) { - struct ipc_message m; - memset (&m, 0, sizeof (struct ipc_message)); - - enum ipc_errors ret; + SECURE_DECLARATION (struct ipc_message, m); // init service - ret = ipc_connection (env, srv, SERVICE_NAME); - if (ret != IPC_ERROR_NONE) { - handle_err("main", "ipc_application_connection < 0"); - PRINTERR(ret, "application connection"); - exit (EXIT_FAILURE); - } + TIPC_P_Q (ipc_connection (env, srv, SERVICE_NAME), "application connection", EXIT_FAILURE); + TIPC_P_Q (ipc_message_format_data (&m, 42, MSG, (ssize_t) strlen(MSG) +1), "message format data", EXIT_FAILURE); printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen(MSG) +1, (int) strlen(MSG), MSG); - ret = ipc_message_format_data (&m, 42, MSG, (ssize_t) strlen(MSG) +1); - if (ret != IPC_ERROR_NONE) { - PRINTERR(ret, "message format data"); - exit (EXIT_FAILURE); - } - - // printf ("msg to send in the client: "); - // ipc_message_print (&m); - ret = ipc_write (srv, &m); - if (ret != IPC_ERROR_NONE) { - handle_err("main", "application_write"); - PRINTERR(ret, "application write"); - exit (EXIT_FAILURE); - } + TIPC_P_Q (ipc_write (srv, &m), "application write", EXIT_FAILURE); ipc_message_empty (&m); - - ret = ipc_read (srv, &m); - if (ret != IPC_ERROR_NONE) { - handle_err("main", "application_read"); - PRINTERR(ret, "application read"); - exit (EXIT_FAILURE); - } + TIPC_P_Q (ipc_read (srv, &m), "application read", EXIT_FAILURE); printf ("msg recv (type: %u): %s\n", m.user_type, m.payload); ipc_message_empty (&m); - ret = ipc_close (srv); - if (ret != IPC_ERROR_NONE) { - handle_err("main", "application_close"); - PRINTERR(ret, "application close"); - exit (EXIT_FAILURE); - } + TIPC_P_Q (ipc_close (srv), "application close", EXIT_FAILURE); } void interactive (char *env[]) { - enum ipc_errors ret; - // init service - ret = ipc_connection (env, srv, SERVICE_NAME); - if (ret != IPC_ERROR_NONE) { - handle_err ("main", "ipc_application_connection < 0"); - PRINTERR(ret, "application connection"); - exit (EXIT_FAILURE); - } + TIPC_P_Q (ipc_connection (env, srv, SERVICE_NAME), "application connection", EXIT_FAILURE); - struct ipc_event event; - memset (&event, 0, sizeof (struct ipc_event)); + SECURE_DECLARATION (struct ipc_event, event); + SECURE_DECLARATION (struct ipc_connection_infos, services); - struct ipc_connection_infos services; - memset (&services, 0, sizeof (struct ipc_connection_infos)); ipc_add (&services, srv); - ipc_add_fd (&services, 0); // add STDIN - ipc_connections_print(&services); + ipc_connections_print (&services); while (1) { printf ("msg to send: "); fflush (stdout); - ret = ipc_wait_event (&services, NULL, &event); - if (ret != IPC_ERROR_NONE) { - PRINTERR(ret, "wait event"); - exit (EXIT_FAILURE); - } + TIPC_P_Q (ipc_wait_event (&services, NULL, &event), "wait event", EXIT_FAILURE); switch (event.type) { case IPC_EVENT_TYPE_EXTRA_SOCKET: { // structure not read, should read the message here - ssize_t len; char buf[4096]; memset(buf, 0, 4096); len = read (event.origin->fd, buf, 4096); - buf[100] = '\0'; + buf[len -1] = '\0'; + chomp (buf, len); + +#if 0 + printf ("\n"); + printf ("message to send: %.*s\n", (int) len, buf); +#endif // in case we want to quit the program if ( len == 0 || strncmp (buf, "quit", 4) == 0 || strncmp (buf, "exit", 4) == 0) { - ret = ipc_close (srv); - if (ret != IPC_ERROR_NONE) { - handle_err("main", "ipc_close"); - PRINTERR(ret, "application close"); - exit (EXIT_FAILURE); - } + TIPC_P_Q (ipc_close (srv), "application close", EXIT_FAILURE); ipc_connections_free (&services); @@ -130,15 +94,18 @@ void interactive (char *env[]) // send the message read on STDIN struct ipc_message *m = NULL; - m = malloc (sizeof (struct ipc_message)); - memset (m, 0, sizeof (struct ipc_message)); + SECURE_BUFFER_HEAP_ALLOCATION_R (m, sizeof (struct ipc_message), , ); - ret = ipc_write (srv, m); - if (ret != IPC_ERROR_NONE) { - handle_err("main", "ipc_write"); - PRINTERR(ret, "ipc_write"); - exit (EXIT_FAILURE); - } + TIPC_P_Q (ipc_message_format_data (m, 42, buf, len), "message format", EXIT_FAILURE); + +#if 0 + printf ("\n"); + printf ("right before sending a message\n"); +#endif + TIPC_P_Q (ipc_write (srv, m), "ipc_write", EXIT_FAILURE); +#if 0 + printf ("right after sending a message\n"); +#endif ipc_message_empty (m); free (m); @@ -147,7 +114,7 @@ void interactive (char *env[]) case IPC_EVENT_TYPE_MESSAGE: { struct ipc_message *m = event.m; - printf ("msg recv: %.*s", m->length, m->payload); + printf ("\rmsg recv: %.*s\n", m->length, m->payload); }; break; case IPC_EVENT_TYPE_DISCONNECTION: diff --git a/examples/pongd.c b/examples/pongd.c index eba67fb..1fe47b6 100644 --- a/examples/pongd.c +++ b/examples/pongd.c @@ -71,16 +71,20 @@ void main_loop () case IPC_EVENT_TYPE_MESSAGE: { struct ipc_message *m = event.m; - if (m->length > 0) { #ifdef PONGD_VERBOSE - printf ("message received (type %d): %.*s\n", m->type, m->length, m->payload); -#endif + if (m->length > 0) { + printf ("message received (type %d, user type %d, size %u bytes): %.*s\n", m->type, m->user_type, m->length, m->length, m->payload); } + else { + printf ("message with a 0-byte size :(\n"); + } +#endif ret = ipc_write (event.origin, m); if (ret != IPC_ERROR_NONE) { PRINTERR(ret,"server write"); } + printf ("message sent\n"); }; break; case IPC_EVENT_TYPE_ERROR: @@ -110,7 +114,7 @@ void exit_program(int signal) printf("Quitting, signal: %d\n", signal); // free remaining clients - for (int i = 0; i < clients->size ; i++) { + for (size_t i = 0; i < clients->size ; i++) { struct ipc_connection_info *cli = clients->cinfos[i]; if (cli != NULL) { free (cli); diff --git a/examples/simple-tcp-client.c b/examples/simple-tcp-client.c index 1cf0693..f017d84 100644 --- a/examples/simple-tcp-client.c +++ b/examples/simple-tcp-client.c @@ -23,18 +23,14 @@ */ -int connection(int port) +int connection(char *ipstr, int port) { int sockfd; - struct sockaddr_in server; + SECURE_DECLARATION (struct sockaddr_in, server); socklen_t addrlen; // socket factory - if((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) - { - perror("socket"); - exit(EXIT_FAILURE); - } + T_PERROR_Q (((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1), "socket creation", EXIT_FAILURE); // init remote addr structure and other params server.sin_family = AF_INET; @@ -42,19 +38,11 @@ int connection(int port) addrlen = sizeof(struct sockaddr_in); // get addr from command line and convert it - if(inet_pton(AF_INET, "127.0.0.1", &server.sin_addr) <= 0) - { - perror("inet_pton"); - close(sockfd); - exit(EXIT_FAILURE); - } + T_PERROR_Q ((inet_pton(AF_INET, ipstr, &server.sin_addr) <= 0), "inet_pton", EXIT_FAILURE); printf("Trying to connect to the remote host\n"); - if(connect(sockfd, (struct sockaddr *) &server, addrlen) == -1) - { - perror("connect"); - exit(EXIT_FAILURE); - } + + T_PERROR_Q ((connect(sockfd, (struct sockaddr *) &server, addrlen) == -1), "connection", EXIT_FAILURE); printf("Connection OK\n"); @@ -63,70 +51,37 @@ int connection(int port) void send_receive (int sockfd) { - unsigned char buf[BUFSIZ]; - memset (buf, 0, BUFSIZ); + SECURE_BUFFER_DECLARATION (unsigned char, buf, BUFSIZ); + int paylen; // first, send service name "pong" // send string - if(send(sockfd, "pong", 4, 0) == -1) { - perror("send pong"); - close(sockfd); - exit(EXIT_FAILURE); - } + T_PERROR_Q ((send(sockfd, "pong", 4, 0) == -1), "sending a message", EXIT_FAILURE); printf ("message 'pong' sent\n"); + T_PERROR_Q (((paylen = recv(sockfd, buf, BUFSIZ, 0)) <= 0), "cannot connect to networkd", EXIT_FAILURE); + print_hexa ("should be 'OK'", buf, paylen); memset (buf, 0, BUFSIZ); - int paylen; - paylen = recv(sockfd, buf, BUFSIZ, 0); - if (paylen <= 0) { - printf ("cannot connect to networkd\n"); - exit (EXIT_FAILURE); - } - printf ("should receive 'OK': %*.s\n", paylen, buf); - - memset (buf, 0, BUFSIZ); - - buf[0] = MSG_TYPE_DATA; - - // uint32_t v = htonl(6); - // memcpy (buf+1, &v, sizeof (uint32_t)); - - uint32_t v = 6; - uint32_t net_paylen = htonl (v); - memcpy (buf+1, &net_paylen, sizeof (uint32_t)); - - buf[5] = 0; - memcpy (buf+6, "coucou", 6); - - print_hexa ("SENT MESSAGE", buf, 12); - // 2 | 6 | 0 | "coucou" // 1 B | 4 B | 1 | 6 B - - if(send(sockfd, buf, 12, 0) == -1) { - perror("send coucou"); - close(sockfd); - exit(EXIT_FAILURE); - } + ipc_message_raw_serialize ((char *) buf, MSG_TYPE_DATA, 42, "coucou", 6); + print_hexa ("WAITING 10 seconds then message to send", buf, 12); + // sleep (1); + T_PERROR_Q ((send(sockfd, buf, 12, 0) == -1), "sending a message", EXIT_FAILURE); printf ("message 'coucou' sent\n"); - memset (buf, 0, BUFSIZ); - paylen = recv (sockfd, buf, BUFSIZ, 0); - if(paylen < 0) { - perror("recv a message"); - close(sockfd); - exit(EXIT_FAILURE); - } - if (paylen > 0) { - print_hexa ("RECEIVED MESSAGE", buf, paylen); - } - else { + // receiving a message + T_PERROR_Q ( ((paylen = recv (sockfd, buf, BUFSIZ, 0)) < 0), "receiving a message", EXIT_FAILURE); + + if (paylen == 0) { fprintf (stderr, "error: disconnection from the server\n"); exit (EXIT_FAILURE); } + print_hexa ("RECEIVED MESSAGE", buf, paylen); + #if 0 // send string if(sendto(sockfd, , ), 0) == -1) @@ -141,12 +96,17 @@ void send_receive (int sockfd) { int main(int argc, char * argv[]) { + char *ipstr = "127.0.0.1"; int port = 9000; - if (argc > 1) { + if (argc == 2) { port = atoi (argv[1]); } + else if (argc == 3) { + ipstr = argv[1]; + port = atoi (argv[2]); + } - int sockfd = connection (port); + int sockfd = connection (ipstr, port); send_receive (sockfd); diff --git a/examples/simple-tcpd.c b/examples/simple-tcpd.c index 691f36e..317facd 100644 --- a/examples/simple-tcpd.c +++ b/examples/simple-tcpd.c @@ -7,12 +7,16 @@ #include #include -#define NTAB(t) ((int) (sizeof (t) / sizeof (t)[0])) -#define SECURE_BUFFER_DECLARATION(type,name,size) type name[size]; memset(&name, 0, sizeof(type) * size); -// print error string -#define PRINT_ERR_STR(code) const char *estr = ipc_errors_get (code); fprintf (stderr, "%s", estr); -// Test Print Quit -#define T_P_Q(f,err,q) { ret = f; if (ret != IPC_ERROR_NONE) { fprintf (stderr, err); PRINT_ERR_STR(ret); exit (q); } } +#define CLOG_DEBUG(a, ...) LOG_DEBUG (""); LOG_DEBUG("\033[36m" a "\033[00m", #__VA_ARGS__); LOG_DEBUG ("") + +void chomp (char *str, size_t len) { + if (str[len -1] == '\n') { + str[len -1] = '\0'; + } + if (str[len -2] == '\n') { + str[len -2] = '\0'; + } +} /* * @@ -30,8 +34,14 @@ if reading on sock_tcp sock_client = accept ipc_add_fd sock_client - elif reading on sock_client - TODO (first draft): print messages + elif + if socket bind to another (client to service or service to client) + reading on fd ; writing on related fd + else + connection from the client: + 1. client sends service name + 2. networkd establishes a connection to the service + 3. ack else lolwat shouldn't happen :( elif reading on usual socket @@ -40,223 +50,89 @@ #define SERVICE_NAME "simpletcp" -#define PRINTERR(ret,msg) {\ - const char * err = ipc_errors_get (ret);\ - fprintf(stderr, "error while %s: %s\n", msg, err);\ -} - -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_switchings * IPC_TO_TCP; -}; - struct networkd * ctx; - -void ipc_switching_add (struct ipc_switchings *is, int orig, int dest) +void handle_disconnection (int fd) { - is->collection = realloc(is->collection, sizeof(struct ipc_switching) * (is->size+1)); - if (is->collection == NULL) { - printf ("error realloc\n"); - exit (EXIT_FAILURE); + // disconnection + LOG_DEBUG ("CLOSE CONNECTION %d", fd); + + int delfd; + + delfd = ipc_switching_del (ctx->TCP_TO_IPC, fd); + if (delfd >= 0) { + LOG_DEBUG ("CLOSE RELATED CONNECTION %d", delfd); + close (delfd); + ipc_del_fd (ctx->clients, delfd); } - is->size++; + close (fd); + ipc_del_fd (ctx->clients, fd); - is->collection[is->size-1].orig = orig; - is->collection[is->size-1].dest = dest; + printf ("\n\n"); + // printf ("TCP_TO_IPC\n"); + ipc_switching_print (ctx->TCP_TO_IPC); + + printf ("\n\n"); } -int ipc_switching_del (struct ipc_switchings *is, int orig) +void tcp_connection (char **env, int fd) { - for (size_t i = 0; i < is->size; i++) { - if (is->collection[i].orig == orig) { - is->collection[i].orig = is->collection[is->size-1].orig; - int ret = is->collection[i].dest; - is->collection[i].dest = is->collection[is->size-1].dest; + SECURE_BUFFER_DECLARATION(char, buf, BUFSIZ); - 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) { - printf ("error realloc\n"); - exit (EXIT_FAILURE); - } - - is->size--; - return ret; - } + ssize_t len = recv (fd, buf, BUFSIZ, 0); + if (len <= 0) { + handle_disconnection (fd); + return ; } - return -1; -} - -int ipc_switching_get (struct ipc_switchings *is, int orig) { - for (size_t i = 0; i < is->size; i++) { - if (is->collection[i].orig == orig) { - return is->collection[i].dest; - } - } - - return -1; -} - -void ipc_switching_print (struct ipc_switchings *is) { - printf ("print!\n"); - for (size_t i = 0; i < is->size; i++) - { - printf ("client %d - %d\n", is->collection[i].orig, is->collection[i].dest); - } -} - -void tcp_connection (char **env, int fd, char * buf, int len) -{ - printf ("tcp client %d is not already connected to a service\n", fd); buf[len] = '\0'; - // for testing purposes - size_t last_char = strlen ((const char*)buf) -1; - if (buf[last_char] == '\n') { - buf[last_char] = '\0'; - } - - printf ("read something: where to connect %s\n", buf); - printf ("sending ok\n"); + // XXX: for testing purposes + chomp (buf, len); + LOG_DEBUG ("SHOULD CONNECT TO %s", buf); // TODO: tests - if (send (fd, "OK", 2, 0) <= 0) { - fprintf (stderr, "error: cannot send message\n"); - perror("send"); - exit (EXIT_FAILURE); - } - + T_PERROR_Q ( (send (fd, "OK", 2, 0) <= 0), "sending a message", EXIT_FAILURE); SECURE_DECLARATION (struct ipc_connection_info, tcp_to_ipc_ci); - enum ipc_errors ret = 0; - T_P_Q (ipc_connection (env, &tcp_to_ipc_ci, buf), "cannot connect to the service\n", EXIT_FAILURE); + TIPC_F_Q (ipc_connection (env, &tcp_to_ipc_ci, buf), ("cannot connect to the service [%s]", buf), EXIT_FAILURE); ipc_switching_add (ctx->TCP_TO_IPC, fd, tcp_to_ipc_ci.fd); - ipc_switching_add (ctx->IPC_TO_TCP, tcp_to_ipc_ci.fd, fd); ipc_add_fd (ctx->clients, tcp_to_ipc_ci.fd); + + LOG_DEBUG ("CONNECTION TO SERVICE client %d -> %d", fd, tcp_to_ipc_ci.fd); } -void handle_extra_socket (struct ipc_event event, int sockfd, char **env) +int accept_new_client (int serverfd) { SECURE_DECLARATION (struct sockaddr_in, client); socklen_t addrlen = 0; - printf ("something comes from somewhere: fd %d\n", event.origin->fd); + int sock_fd_client; + T_PERROR_Q (((sock_fd_client = accept(serverfd, (struct sockaddr *) &client, &addrlen)) == -1), "accept new client", EXIT_FAILURE); - // NEW CLIENT - if (event.origin->fd == sockfd) { - int sock_fd_client; - if((sock_fd_client = accept(sockfd, (struct sockaddr *) &client, &addrlen)) == -1) { - perror("accept"); - close(sockfd); - exit(EXIT_FAILURE); - } - printf ("after accept\n"); - // adding a client - ipc_add_fd (ctx->clients, sock_fd_client); - printf ("after ipc_add_fd, TCP client: %d\n", sock_fd_client); - } - // CLIENT IS TALKING - else { - SECURE_BUFFER_DECLARATION(char, buf, 4096); + // adding a client + ipc_add_fd (ctx->clients, sock_fd_client); - ssize_t len = recv (event.origin->fd, buf, 4096, 0); - if (len > 0) { - - print_hexa ("RECEIVED", (unsigned char*) buf, len); - - // TODO: check if the message comes from an external IPC - int fd = ipc_switching_get (ctx->IPC_TO_TCP, event.origin->fd); - - if (fd >= 0) { - printf ("SWITCH: ipc service %d sent a message for %d\n", event.origin->fd, fd); - int sent_len = send (fd, buf, len, 0); - if (sent_len < 0) { - perror ("write to ipc"); - } - else if (sent_len != len) { - fprintf (stderr, "write NOT ENOUGH to tcp client\n"); - } - } - else { - fd = ipc_switching_get (ctx->TCP_TO_IPC, event.origin->fd); - if (fd >= 0) { - printf ("SWITCH: client %d sent a message for %d\n", event.origin->fd, fd); - int sent_len = send (fd, buf, len, 0); - if (sent_len < 0) { - perror ("write to ipc"); - } - else if (sent_len != len) { - fprintf (stderr, "write NOT ENOUGH to ipc\n"); - } - } - else { - tcp_connection (env, event.origin->fd, buf, len); - } - } - } - else if (len == 0) { - // disconnection - printf ("close connection\n"); - - int delfd = ipc_switching_del (ctx->TCP_TO_IPC, event.origin->fd); - if (delfd >= 0) { - close (delfd); - ipc_del_fd (ctx->clients, delfd); - } - - delfd = ipc_switching_del (ctx->IPC_TO_TCP, event.origin->fd); - if (delfd >= 0) { - close (delfd); - ipc_del_fd (ctx->clients, delfd); - } - - close (event.origin->fd); - ipc_del_fd (ctx->clients, event.origin->fd); - } - } + return sock_fd_client; } - void main_loop (int argc, char **argv, char **env) { argc = argc; // FIXME: useless - int sockfd; + int serverfd; - struct sockaddr_in my_addr; + SECURE_DECLARATION (struct sockaddr_in, my_addr); socklen_t addrlen; // socket factory - if((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) - { - perror("socket"); - exit(EXIT_FAILURE); - } + T_PERROR_R (((serverfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1), "socket", ); int yes = 1; - if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { - perror ("setsockopt"); - } - + T_PERROR_R ((setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1), "setsockopt", ); // init local addr structure and other params my_addr.sin_family = AF_INET; @@ -265,57 +141,51 @@ void main_loop (int argc, char **argv, char **env) addrlen = sizeof(struct sockaddr_in); // bind addr structure with socket - if(bind(sockfd, (struct sockaddr *) &my_addr, addrlen) == -1) - { - perror("bind"); - close(sockfd); - exit(EXIT_FAILURE); - } + T_PERROR_R ((bind(serverfd, (struct sockaddr *) &my_addr, addrlen) == -1), "bind", ); // set the socket in passive mode (only used for accept()) // and set the list size for pending connection - if(listen(sockfd, 5) == -1) - { - perror("listen"); - close(sockfd); - exit(EXIT_FAILURE); - } + T_PERROR_R ((listen(serverfd, 5) == -1), "listen", ); printf("Waiting for incomming connection\n"); + SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->clients, sizeof (struct ipc_connection_infos), , EXIT_FAILURE); + SECURE_DECLARATION (struct ipc_event, event); - enum ipc_errors ret = 0; - - ctx->clients = malloc (sizeof (struct ipc_connection_infos)); - memset(ctx->clients, 0, sizeof(struct ipc_connection_infos)); - - struct ipc_event event; - memset(&event, 0, sizeof (struct ipc_event)); - printf ("adding sockfd to ctx->clients\n"); - ipc_add_fd (ctx->clients, sockfd); + printf ("adding serverfd to ctx->clients\n"); + ipc_add_fd (ctx->clients, serverfd); 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 - // printf ("before wait event\n"); // TODO remove - ret = ipc_wait_event (ctx->clients, ctx->srv, &event); - // printf ("after wait event\n"); // TODO remove - if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) { - PRINTERR(ret,"wait event"); - - // the application will shut down, and close the service - ret = ipc_server_close (ctx->srv); - if (ret != IPC_ERROR_NONE) { - PRINTERR(ret,"server close"); - } - exit (EXIT_FAILURE); - } + TIPC_T_P_I_R ( + /* function to test */ ipc_wait_event_networkd (ctx->clients, ctx->srv, &event, ctx->TCP_TO_IPC) + , /* error condition */ ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT + , /* to say on error */ "wait event" + , /* to do on error */ LOG_ERROR ("\033[31m error happened\033[00m"); TIPC_P (ipc_server_close (ctx->srv), "server close") + , /* return function */ return ); switch (event.type) { + case IPC_EVENT_TYPE_SWITCH: + { + printf ("switch happened\n"); + } + break; + case IPC_EVENT_TYPE_EXTRA_SOCKET: { - handle_extra_socket (event, sockfd, env); + // NEW CLIENT + if (event.origin->fd == serverfd) { + int sock_fd_client = accept_new_client (serverfd); + ctx->cpt++; + printf ("TCP connection: %d clients connected\n", ctx->cpt); + printf ("new TCP client has the fd %d\n", sock_fd_client); + } + // CLIENT IS TALKING + else { + tcp_connection (env, event.origin->fd); + } } break; @@ -326,13 +196,15 @@ void main_loop (int argc, char **argv, char **env) printf ("new client has the fd %d\n", (event.origin)->fd); }; break; + case IPC_EVENT_TYPE_DISCONNECTION: { ctx->cpt--; printf ("disconnection: %d clients remaining\n", ctx->cpt); // free the ipc_client structure - free (event.origin); + // if (event.origin != NULL) + // free (event.origin); }; break; case IPC_EVENT_TYPE_MESSAGE: @@ -342,24 +214,14 @@ void main_loop (int argc, char **argv, char **env) printf ("message received (type %d): %.*s\n", m->type, m->length, m->payload); } - ret = ipc_write (event.origin, m); - - if (ret != IPC_ERROR_NONE) { - handle_err( "handle_new_msg", "server_write < 0"); - PRINTERR(ret,"server write"); - } + TIPC_P (ipc_write (event.origin, m), "server write"); }; break; case IPC_EVENT_TYPE_ERROR: - { - fprintf (stderr, "a problem happened with client %d\n" - , (event.origin)->fd); - }; + fprintf (stderr, "a problem happened with client %d\n", (event.origin)->fd); break; default : - { - fprintf (stderr, "there must be a problem, event not set\n"); - }; + fprintf (stderr, "there must be a problem, event not set\n"); } } @@ -373,7 +235,7 @@ void exit_program(int signal) printf("Quitting, signal: %d\n", signal); // free remaining clients - for (int i = 0; i < ctx->clients->size ; i++) { + for (size_t i = 0; i < ctx->clients->size ; i++) { struct ipc_connection_info *cli = ctx->clients->cinfos[i]; if (cli != NULL) { free (cli); @@ -382,20 +244,15 @@ void exit_program(int signal) } ipc_connections_free (ctx->clients); - free (ctx->clients); - // the application will shut down, and close the service - enum ipc_errors ret = ipc_server_close (ctx->srv); - if (ret != IPC_ERROR_NONE) { - PRINTERR(ret,"server close"); - } - free (ctx->srv); + TIPC_P (ipc_server_close (ctx->srv), "server close"); + // free, free everything! + free (ctx->clients); + free (ctx->srv); free (ctx->TCP_TO_IPC->collection); free (ctx->TCP_TO_IPC); - free (ctx->IPC_TO_TCP->collection); - free (ctx->IPC_TO_TCP); free (ctx); exit(EXIT_SUCCESS); @@ -412,39 +269,18 @@ int main(int argc, char * argv[], char **env) if(argc != 2) { printf("USAGE: %s port_num\n", argv[0]); - exit(-1); + exit(EXIT_FAILURE); } printf ("pid = %d\n", getpid ()); - ctx = malloc (sizeof (struct networkd)); - memset (ctx, 0, sizeof (struct networkd)); + 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->TCP_TO_IPC = malloc(sizeof(struct ipc_switchings)); - memset (ctx->TCP_TO_IPC, 0, sizeof(struct ipc_switchings)); - ctx->TCP_TO_IPC->collection = malloc(sizeof(struct ipc_switching)); - ctx->IPC_TO_TCP = malloc(sizeof(struct ipc_switchings)); - memset (ctx->IPC_TO_TCP, 0, sizeof(struct ipc_switchings)); - ctx->IPC_TO_TCP->collection = malloc(sizeof(struct ipc_switching)); - - ctx->srv = malloc (sizeof (struct ipc_connection_info)); - if (ctx->srv == NULL) { - exit (EXIT_FAILURE); - } - memset (ctx->srv, 0, sizeof (struct ipc_connection_info)); - ctx->srv->type = '\0'; - ctx->srv->index = 0; - ctx->srv->version = 0; - ctx->srv->fd = 0; - ctx->srv->spath = NULL; - - enum ipc_errors ret = ipc_server_init (env, ctx->srv, SERVICE_NAME); - if (ret != IPC_ERROR_NONE) { - PRINTERR(ret,"server init"); - return EXIT_FAILURE; - } - printf ("Listening on %s.\n", ctx->srv->spath); + TIPC_P_R (ipc_server_init (env, ctx->srv, SERVICE_NAME), "server init", EXIT_FAILURE); + printf ("Listening on [%s].\n", ctx->srv->spath); printf("MAIN: server created\n" ); diff --git a/examples/test-ask-for-fd-to-networkd.c b/examples/test-ask-for-fd-to-networkd.c new file mode 100644 index 0000000..80fd9ad --- /dev/null +++ b/examples/test-ask-for-fd-to-networkd.c @@ -0,0 +1,46 @@ +#include +#include +#include + +#include "../src/ipc.h" + +#define DEFAULT_IPC_NETWORK "IPC_NETWORK=\"pong local:lolwat\"" + +int main(int argc, char * argv[]) +{ + + (void) argc; + (void) argv; + + enum ipc_errors ret; + SECURE_DECLARATION (struct ipc_connection_info, srv); + + if (argc != 2) { + fprintf (stderr, "usage: %s service_name\n", argv[0]); + exit (1); + } + + char *service_name = argv[1]; + + // ask for a local service "pong" + // inform the network service that it's now named "lolwat" + char *ipc_network = getenv("IPC_NETWORK"); + if (ipc_network == NULL) { + ipc_network = DEFAULT_IPC_NETWORK; + } + + ret = ipc_contact_networkd (&srv, service_name, ipc_network); + + printf ("ret = %d\n", ret); + + if (ret == 0 && srv.fd != 0) { + printf ("Success\n"); + } + else { + printf ("Ow. :(\n"); + } + + usock_close (srv.fd); + + return EXIT_SUCCESS; +} diff --git a/examples/test-networkd-provide-fd.c b/examples/test-networkd-provide-fd.c new file mode 100644 index 0000000..6074d30 --- /dev/null +++ b/examples/test-networkd-provide-fd.c @@ -0,0 +1,41 @@ +#include +#include +#include + +#include "../src/ipc.h" + + +int main(int argc, char * argv[], char *env[]) +{ + + (void) argc; + (void) argv; + + enum ipc_errors ret; + SECURE_DECLARATION (struct ipc_connection_info, srv); + SECURE_DECLARATION (struct ipc_connection_info, client); + SECURE_DECLARATION (struct ipc_connection_info, contacted_service); + + + // service start + TIPC_P_RR (ipc_server_init (env, &srv, "network"), "Networkd cannot be initialized"); + + printf ("service initialized, waiting for a client\n"); + + // accept a new client + TIPC_P_RR (ipc_accept (&srv, &client), "cannot accept the client during handle_new_connection"); + + // TODO: read a message to know the requested service + SECURE_DECLARATION (struct ipc_message, msg); + ret = ipc_read (&client, &msg); + printf ("received message: %s\n", msg.payload); + + /** TODO: contact the service */ + printf ("WARNING: currently this program only ask for pong service %d\n", ret); + TIPC_P_RR (ipc_connection (env, &contacted_service, "pong"), "cannot connect to the requested service"); + + ipc_provide_fd (client.fd, contacted_service.fd); + + TIPC_P_RR (ipc_server_close (&srv), "Networkd cannot be stopped!!"); + return EXIT_SUCCESS; +} diff --git a/examples/tests-logs.c b/examples/tests-logs.c new file mode 100644 index 0000000..3a57c04 --- /dev/null +++ b/examples/tests-logs.c @@ -0,0 +1,16 @@ +#include +#include +#include + +#include "../src/ipc.h" + +int main(void) +{ + SECURE_BUFFER_DECLARATION (char, buffer, BUFSIZ); + + log_get_logfile_name (buffer, BUFSIZ); + + printf ("log: %s\n", buffer); + + return EXIT_SUCCESS; +} diff --git a/examples/wsserver.c b/examples/wsserver.c new file mode 100644 index 0000000..7e9c343 --- /dev/null +++ b/examples/wsserver.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include + +#include "../src/ipc.h" +#include "../src/utils.h" + +#define WEBSOCKETD_BULLSHIT + +void chomp (char *str, ssize_t len) { + if (str[len -1] == '\n') { + str[len -1] = '\0'; + } + if (str[len -2] == '\n') { + str[len -2] = '\0'; + } +} + +struct ipc_connection_info *srv; + +void interactive (char *env[]) +{ + SECURE_BUFFER_DECLARATION (char, service_name, 100); + + char *sn = getenv("PATH_TRANSLATED"); + + if (sn != NULL) { + memcpy (service_name, sn, strlen(sn)); + } + else { + fprintf (stderr, "cannot see PATH_TRANSLATED variable\n"); + exit (EXIT_FAILURE); + } + + // init service + TIPC_P_Q (ipc_connection (env, srv, service_name), "application connection", 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 + + while (1) { + TIPC_P_Q (ipc_wait_event (&services, NULL, &event), "wait event", EXIT_FAILURE); + + switch (event.type) { + case IPC_EVENT_TYPE_EXTRA_SOCKET: + { + // structure not read, should read the message here + SECURE_BUFFER_DECLARATION (char, buf, 4096); + ssize_t len; + + len = read (event.origin->fd, buf, 4096); + + // in case we want to quit the program + if ( len == 0 + || strncmp (buf, "quit", 4) == 0 + || strncmp (buf, "exit", 4) == 0) { + + TIPC_P_Q (ipc_close (srv), "application close", EXIT_FAILURE); + + ipc_connections_free (&services); + + exit (EXIT_SUCCESS); + } + + // send the message read on STDIN + ssize_t len_sent = write (srv->fd, buf, len); + if (len_sent != len) { + fprintf (stderr, "cannot send the message %lu-byte message, sent %lu bytes" + , len, len_sent); + exit (EXIT_FAILURE); + } + } + break; + case IPC_EVENT_TYPE_MESSAGE: + { + struct ipc_message *m = event.m; + SECURE_BUFFER_DECLARATION (char, buf, 4096); + uint32_t size; + size = ipc_message_raw_serialize (buf, m->type, m->user_type, m->payload, m->length); + + write (1, buf, size); +#ifdef WEBSOCKETD_BULLSHIT + printf ("\n"); +#endif + fflush (stdout); + }; + 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"); + // ERROR_CASE (IPC_EVENT_TYPE_ERROR , "main loop", "error"); + default : + fprintf (stderr, "event type error: should not happen, event type %d\n", event.type); + } + } +} + +int main (int argc, char *argv[], char *env[]) +{ + argc = argc; // warnings + 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; + + interactive (env); + + return EXIT_SUCCESS; +} diff --git a/man/libipc.7.md b/man/libipc.7.md index 136c8eb..6114e57 100644 --- a/man/libipc.7.md +++ b/man/libipc.7.md @@ -47,17 +47,11 @@ It provides both client and server code. ## Message functions -// create msg structure with a certain payload length (0 for no payload memory allocation)\ -*enum ipc_errors* **ipc_message_new** (*struct ipc_message* \*\*m, *ssize_t* paylen);\ // create msg structure from buffer\ *enum ipc_errors* **ipc_message_format_read** (*struct ipc_message* \*m, *const char* \*buf, *ssize_t* msize);\ // create buffer from msg structure\ *enum ipc_errors* **ipc_message_format_write** (*const struct ipc_message* \*m, *char* \*\*buf, *ssize_t* \*msize);\ -// read a structure msg from fd\ -*enum ipc_errors* **ipc_message_read** (*int32_t* fd, *struct ipc_message* \*m);\ -// write a structure msg to fd\ -*enum ipc_errors* **ipc_message_write** (*int32_t* fd, *const struct ipc_message* \*m);\ *enum ipc_errors* **ipc_message_format** (*struct ipc_message* \*m, *char* type, *const char* \*payload, *ssize_t* length);\ *enum ipc_errors* **ipc_message_format_data** (*struct ipc_message* \*m, *const char* \*payload, *ssize_t* length);\ *enum ipc_errors* **ipc_message_format_server_close** (*struct ipc_message* \*m);\ diff --git a/project.zsh b/project.zsh index ac69258..918d376 100644 --- a/project.zsh +++ b/project.zsh @@ -2,10 +2,13 @@ package=ipc version=0.1.0 +CFLAGS="-Wall -Wextra -g" + targets=(libipc src/ipc.h man/libipc.7) type[libipc]=library sources[libipc]="$(ls src/*.c)" +cflags[libipc]="-std=c11" type[src/ipc.h]=header diff --git a/src/communication.c b/src/communication.c index 78c58ef..0206d61 100644 --- a/src/communication.c +++ b/src/communication.c @@ -1,40 +1,41 @@ -#include "ipc.h" - -#include "utils.h" +#include #include -#include #include #include // error numbers #include #include +#include "ipc.h" +#include "utils.h" + +// FOR THE PURPOSE OF SOME EXPERIMENT +#include +#include + // print structures #include "message.h" - -#define IPC_CONNECTION_TYPE_IPC 'i' -#define IPC_CONNECTION_TYPE_EXTERNAL 'a' - -void service_path (char *path, const char *sname, int32_t index, int32_t version) +enum ipc_errors service_path (char *path, const char *sname, int32_t index, int32_t version) { - assert (path != NULL); - assert (sname != NULL); + 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; + char * rundir = getenv ("IPC_RUNDIR"); + if (rundir == NULL) + rundir = RUNDIR; snprintf (path, PATH_MAX-1, "%s/%s-%d-%d", rundir, sname, index, version); + + return IPC_ERROR_NONE; } -/*calculer le max filedescriptor*/ static int32_t get_max_fd (struct ipc_connection_infos *cinfos) { - int32_t i; + size_t i; int32_t max = 0; for (i = 0; i < cinfos->size; i++ ) { @@ -48,93 +49,133 @@ static int32_t get_max_fd (struct ipc_connection_infos *cinfos) enum ipc_errors ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname) { - if (env == NULL) - return IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM; + 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 (srv == NULL) - return IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM; - if (sname == NULL) - return IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM; +#if 0 + // For server init, no need for networkd evaluation - // TODO: loop over environment variables - // any IPC_NETWORK_* should be shared with the network service - // in order to route requests over any chosen protocol stack - // ex: IPC_NETWORK_AUDIO="tor://some.example.com/" - env = env; + // 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 - char buf [PATH_MAX]; - memset (buf, 0, PATH_MAX); - service_path (buf, sname, srv->index, srv->version); + SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); + TIPC_P_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; + if (srv->spath != NULL) { + free (srv->spath); + srv->spath = NULL; + } + + size_t s = strlen (buf); + + SECURE_BUFFER_HEAP_ALLOCATION_R (srv->spath, s+1, , IPC_ERROR_SERVER_INIT__MALLOC); + memcpy (srv->spath, buf, s); + srv->spath[s] = '\0'; // to be sure + + TIPC_F_RR (usock_init (&srv->fd, srv->spath), ("cannot init server %s", srv->spath) ); + + return IPC_ERROR_NONE; +} + +enum ipc_errors 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 +enum ipc_errors ipc_contact_networkd (struct ipc_connection_info *srv, 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); + + char *networkvar = getenv("IPC_NETWORK"); + if (networkvar == NULL) { + srv->fd = 0; + return IPC_ERROR_NONE; } - size_t s = strlen (buf); - srv->spath = malloc (s+1); - if (srv->spath == NULL) { - return IPC_ERROR_SERVER_INIT__MALLOC; - } - memcpy (srv->spath, buf, s); - srv->spath[s] = '\0'; // to be sure + // TODO: is there another, more interesting way to do this? + // currently, IPC_NETWORK is shared with the network service + // 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" - enum ipc_errors ret = usock_init (&srv->fd, srv->spath); - if (ret != IPC_ERROR_NONE) { - handle_err ("ipc_server_init", "usock_init"); - return ret; + // 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; + return IPC_ERROR_NONE; + } + // printf ("(;)sname %s found\n", sname); + + // gets the service path + SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); + TIPC_P_RR (service_path (buf, "network", 0, 0), "cannot get network service path"); + + int networkdfd = 0; + + TIPC_F_R (usock_connect (&networkdfd, buf), ("cannot initiates a connection [%s]", buf) + , IPC_ERROR_CONTACT_NETWORKD__NETWORKD); + + 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); + + msg.length = strlen (content); + msg.payload = content; + + TIPC_P_RR (ipc_write_fd (networkdfd, &msg), "cannot send a message to networkd"); + + enum ipc_errors ret = ipc_receive_fd (networkdfd, &srv->fd); + if (ret == IPC_ERROR_NONE) { + usock_close (networkdfd); } - return IPC_ERROR_NONE; + return ret; } enum ipc_errors ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname) { - // 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/" - env = env; - if (env == NULL) - return IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM; + T_R ((env == NULL), IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM); + T_R ((srv == NULL), IPC_ERROR_CONNECTION__NO_SERVER); + T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME); - assert (srv != NULL); - assert (sname != NULL); + TIPC_P (ipc_contact_networkd (srv, sname), "error during networkd connection"); - if (srv == NULL) { - return IPC_ERROR_CONNECTION__NO_SERVER; + // if networkd did not initiate the connection + if (srv->fd <= 0) { + // gets the service path + SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); + TIPC_P_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path"); + TIPC_F_RR (usock_connect (&srv->fd, buf), ("cannot initiates a connection [%s]", buf)); } - if (sname == NULL) { - return IPC_ERROR_CONNECTION__NO_SERVICE_NAME; - } - - // gets the service path - char buf [PATH_MAX]; - memset (buf, 0, PATH_MAX); - service_path (buf, sname, srv->index, srv->version); - - enum ipc_errors ret = usock_connect (&srv->fd, buf); - if (ret != IPC_ERROR_NONE) { - handle_err ("ipc_connection", "usock_connect ret"); - return ret; - } - return IPC_ERROR_NONE; } enum ipc_errors ipc_server_close (struct ipc_connection_info *srv) { - usock_close (srv->fd); - enum ipc_errors ret = usock_remove (srv->spath); - if (srv->spath != NULL) { - free (srv->spath); - srv->spath = NULL; - } - return ret; + usock_close (srv->fd); + enum ipc_errors ret = usock_remove (srv->spath); + if (srv->spath != NULL) { + free (srv->spath); + srv->spath = NULL; + } + return ret; } enum ipc_errors ipc_close (struct ipc_connection_info *p) @@ -144,86 +185,210 @@ enum ipc_errors ipc_close (struct ipc_connection_info *p) enum ipc_errors ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p) { - assert (srv != NULL); - assert (p != NULL); + T_R ((srv == NULL), IPC_ERROR_ACCEPT__NO_SERVICE_PARAM); + T_R ((p == NULL), IPC_ERROR_ACCEPT__NO_CLIENT_PARAM); - if (srv == NULL) { - return IPC_ERROR_ACCEPT__NO_SERVICE_PARAM; - } - - if (p == NULL) { - return IPC_ERROR_ACCEPT__NO_CLIENT_PARAM; - } - - enum ipc_errors ret = usock_accept (srv->fd, &p->fd); - if (ret != IPC_ERROR_NONE) { - handle_err ("ipc_accept", "usock_accept"); - return IPC_ERROR_ACCEPT; - } - - p->type = IPC_CONNECTION_TYPE_IPC; + TIPC_P_R (usock_accept (srv->fd, &p->fd), "cannot accept fd", IPC_ERROR_ACCEPT); + p->type = IPC_CONNECTION_TYPE_IPC; return IPC_ERROR_NONE; } +// receive then format in an ipc_message structure enum ipc_errors ipc_read (const struct ipc_connection_info *p, struct ipc_message *m) { - return ipc_message_read (p->fd, m); + T_R ((m == NULL), IPC_ERROR_READ__NO_MESSAGE_PARAM); + + char *buf = NULL; + size_t msize = IPC_MAX_MESSAGE_SIZE; + + // on error or closed recipient, the buffer already freed + TIPC_NP_RR (usock_recv (p->fd, &buf, &msize)); + TIPC_I_RR (ipc_message_format_read (m, buf, msize), if (buf != NULL) free (buf)); + + free (buf); + + return IPC_ERROR_NONE; // propagates ipc_message_format return +} + +enum ipc_errors 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); + + size_t nbytes_sent = 0; + TIPC_I_RR (usock_send (fd, buf, msize, &nbytes_sent), if (buf != NULL) free (buf)); + + if (buf != NULL) { + free (buf); + } + + // what was sent != what should have been sent + T_R ((nbytes_sent != msize), IPC_ERROR_WRITE__NOT_ENOUGH_DATA); + + return IPC_ERROR_NONE; } enum ipc_errors ipc_write (const struct ipc_connection_info *p, const struct ipc_message *m) { - return ipc_message_write (p->fd, m); + return ipc_write_fd (p->fd, m); } enum ipc_errors handle_new_connection (struct ipc_connection_info *cinfo - , struct ipc_connection_infos *cinfos - , struct ipc_connection_info **new_client) + , struct ipc_connection_infos *cinfos + , struct ipc_connection_info **new_client) { - if (cinfo == NULL) { - return IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM; - } + T_R ((cinfo == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM); + T_R ((cinfos == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM); - if (cinfos == NULL) { - return 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); - *new_client = malloc (sizeof(struct ipc_connection_info)); - if (*new_client == NULL) { - return IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC; - } - memset(*new_client, 0, sizeof(struct ipc_connection_info)); + TIPC_P_RR (ipc_accept (cinfo, *new_client), "cannot accept the client during handle_new_connection"); + TIPC_P_RR (ipc_add (cinfos, *new_client), "cannot add the new accepted client"); - enum ipc_errors ret = ipc_accept (cinfo, *new_client); - if (ret != IPC_ERROR_NONE) { - return ret; - } - - ret = ipc_add (cinfos, *new_client); - if (ret != IPC_ERROR_NONE) { - return ret; - } - - return IPC_ERROR_NONE; + return IPC_ERROR_NONE; } -enum ipc_errors ipc_wait_event (struct ipc_connection_infos *cinfos - , struct ipc_connection_info *cinfo // NULL for clients - , struct ipc_event *event) +// new connection from a client +enum ipc_errors handle_connection (struct ipc_event *event, struct ipc_connection_infos *cinfos, struct ipc_connection_info *cinfo) { - assert (cinfos != NULL); + // connection + struct ipc_connection_info *new_client = NULL; - if (cinfos == NULL) { - return IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM; + TIPC_P_RR (handle_new_connection (cinfo, cinfos, &new_client), "cannot add new client"); + + IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client); + return IPC_ERROR_NONE; +} + +// new message +enum ipc_errors 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; + + TIPC_T_P_I_R ( + /* function to test */ usock_recv (talkingfd, &buf, &msize) + , /* error condition */ ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT + , /* to say on error */ "error while receiving message from client" + , /* 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; + TIPC_I_RR (usock_send (correspondingfd, buf, msize, &nbytes_sent), if (buf != NULL) free (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); + return IPC_ERROR_NONE; // 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); + return IPC_ERROR_NONE; + } + 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 (delfd >= 0) { + LOG_DEBUG ("disconnection of %d (and related fd %d)", talkingfd, delfd); + } + else { + LOG_DEBUG ("disconnection of %d", talkingfd); + } + + IPC_EVENT_SET(event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc); + return IPC_ERROR_CLOSED_RECIPIENT; + } + } } - if (event == NULL) { - return IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM; + // 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); + return IPC_ERROR_NONE; } - IPC_EVENT_CLEAN(event); + // listen to what they have to say (disconnection or message) + // then add a client to `event`, the ipc_event structure + enum ipc_errors ret; + struct ipc_message *m = NULL; - int32_t i, j; + SECURE_BUFFER_HEAP_ALLOCATION_R (m, sizeof(struct ipc_message), , IPC_ERROR_NOT_ENOUGH_MEMORY); + + // current talking client + ret = ipc_read (pc, m); + if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) { + enum ipc_errors rvalue = ret; // store the final return value + ipc_message_empty (m); + free (m); + + // if there is a problem, just remove the client + TIPC_P (ipc_close (pc), "cannot close a connection in handle_message"); + TIPC_P (ipc_del (cinfos, pc), "cannot delete a connection in handle_message"); + + IPC_EVENT_SET(event, IPC_EVENT_TYPE_ERROR, NULL, pc); + return rvalue; + } + + // disconnection: close the client then delete it from cinfos + if (ret == IPC_ERROR_CLOSED_RECIPIENT) { + TIPC_P (ipc_close (pc), "cannot close a connection on closed recipient in handle_message"); + TIPC_P (ipc_del (cinfos, pc), "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 + return IPC_ERROR_NONE; + } + + IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc); + return IPC_ERROR_NONE; +} + +enum ipc_errors 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) +{ + T_R ((cinfos == 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; @@ -238,141 +403,64 @@ enum ipc_errors ipc_wait_event (struct ipc_connection_infos *cinfos /* listening socket descriptor */ int32_t listener; - if (cinfo != NULL) { - listener = cinfo->fd; + if (cinfo != NULL) { + listener = cinfo->fd; - /* add the listener to the master set */ - FD_SET(listener, &master); + /* add the listener to the master set */ + FD_SET(listener, &master); - // if listener is max fd - if (fdmax < listener) - fdmax = listener; - } + // 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; - if(select(fdmax+1, &readf, NULL, NULL, NULL) == -1) { - perror("select"); - return IPC_ERROR_WAIT_EVENT__SELECT; - } + readf = master; + T_PERROR_R ((select(fdmax+1, &readf, NULL, NULL, NULL) == -1), "select", IPC_ERROR_WAIT_EVENT__SELECT); - for (i = 0; i <= fdmax; i++) { - if (FD_ISSET(i, &readf)) { - if (cinfo != NULL && i == listener) { - // connection - struct ipc_connection_info *new_client = NULL; - enum ipc_errors ret = handle_new_connection (cinfo, cinfos, &new_client); - if (ret != IPC_ERROR_NONE) { - // TODO: quit the program - return ret; - } - IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client); - return IPC_ERROR_NONE; - } else { - for(j = 0; j < cinfos->size; j++) { - if(i == cinfos->cinfos[j]->fd ) { + 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); + } + } + } + } + } - struct ipc_connection_info *pc = cinfos->cinfos[j]; + return IPC_ERROR_NONE; +} - // 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); - return IPC_ERROR_NONE; - } - - // listen to what they have to say (disconnection or message) - // then add a client to `event`, the ipc_event structure - enum ipc_errors ret; - struct ipc_message *m = NULL; - m = malloc (sizeof(struct ipc_message)); - if (m == NULL) { - return IPC_ERROR_NOT_ENOUGH_MEMORY; - } - memset (m, 0, sizeof (struct ipc_message)); - - // current talking client - ret = ipc_read (pc, m); - if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) { - handle_err ("ipc_wait_event", "ipc_read"); - ipc_message_empty (m); - free (m); - - // if there is a problem, just remove the client - ret = ipc_close (pc); - if (ret != IPC_ERROR_NONE) { - handle_err( "ipc_wait_event", "ipc_close"); - } - - ret = ipc_del (cinfos, pc); - if (ret != IPC_ERROR_NONE) { - handle_err( "ipc_wait_event", "ipc_del"); - } - - IPC_EVENT_SET(event, IPC_EVENT_TYPE_ERROR, NULL, pc); - return ret; - } - - // disconnection: close the client then delete it from cinfos - if (ret == IPC_ERROR_CLOSED_RECIPIENT) { - ret = ipc_close (pc); - if (ret != IPC_ERROR_NONE) { - handle_err( "ipc_wait_event", "ipc_close"); - } - - ret = ipc_del (cinfos, pc); - if (ret != IPC_ERROR_NONE) { - handle_err( "ipc_wait_event", "ipc_del"); - } - 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 - return IPC_ERROR_NONE; - } - - IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc); - return IPC_ERROR_NONE; - } - } - } - } - } - - return IPC_ERROR_NONE; +enum ipc_errors ipc_wait_event (struct ipc_connection_infos *cinfos + , struct ipc_connection_info *cinfo // NULL for clients + , struct ipc_event *event) +{ + return ipc_wait_event_networkd (cinfos, cinfo, event, NULL); } // store and remove only pointers on allocated structures enum ipc_errors ipc_add (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p) { - assert(cinfos != NULL); - assert(p != NULL); - - if (cinfos == NULL) { - return IPC_ERROR_ADD__NO_PARAM_CLIENTS; - } - - if (p == NULL) { - return IPC_ERROR_ADD__NO_PARAM_CLIENT; - } + T_R ((cinfos == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS); + T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT); cinfos->size++; - if (cinfos->size == 1 && cinfos->cinfos == NULL) { - // first allocation - cinfos->cinfos = malloc (sizeof(struct ipc_connection_info)); - } - else { - cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * cinfos->size); - } - - - if (cinfos->cinfos == NULL) { - return IPC_ERROR_ADD__EMPTY_LIST; + 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); + } + + T_R ((cinfos->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST); cinfos->cinfos[cinfos->size - 1] = p; return IPC_ERROR_NONE; @@ -380,25 +468,14 @@ enum ipc_errors ipc_add (struct ipc_connection_infos *cinfos, struct ipc_connect enum ipc_errors ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p) { - assert(cinfos != NULL); - assert(p != NULL); + 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); - if (cinfos == NULL) { - return IPC_ERROR_DEL__NO_CLIENTS_PARAM; - } - - if (p == NULL) { - return IPC_ERROR_DEL__NO_CLIENT_PARAM; - } - - if (cinfos->cinfos == NULL) { - return IPC_ERROR_DEL__EMPTY_LIST; - } - - int32_t i; + 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 + // 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) { @@ -419,12 +496,25 @@ enum ipc_errors ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connect return IPC_ERROR_DEL__CANNOT_FIND_CLIENT; } +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]); + } + 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]); - } + for (size_t i = 0; i < cinfos->size ; i++) { + free (cinfos->cinfos[i]); + } free (cinfos->cinfos); cinfos->cinfos = NULL; } @@ -433,15 +523,11 @@ void ipc_connections_free (struct ipc_connection_infos *cinfos) struct ipc_connection_info * ipc_connection_copy (const struct ipc_connection_info *p) { - if (p == NULL) - return NULL; + T_R ((p == NULL), NULL); - struct ipc_connection_info * copy = malloc (sizeof(struct ipc_connection_info)); - - if (copy == NULL) - return NULL; - - memset (copy, 0, sizeof (struct ipc_connection_info)); + struct ipc_connection_info * copy = NULL; + + SECURE_BUFFER_HEAP_ALLOCATION_R (copy, sizeof(struct ipc_connection_info), , NULL); memcpy (copy, p, sizeof (struct ipc_connection_info)); return copy; @@ -454,64 +540,49 @@ int8_t ipc_connection_eq (const struct ipc_connection_info *p1, const struct ipc // create the client service structure enum ipc_errors ipc_connection_gen (struct ipc_connection_info *cinfo - , uint32_t index, uint32_t version, int fd, char type) + , uint32_t index, uint32_t version, int fd, char type) { - if (cinfo == NULL) { - return IPC_ERROR_CONNECTION_GEN__NO_CINFO; - } + T_R ((cinfo == NULL), IPC_ERROR_CONNECTION_GEN__NO_CINFO); - cinfo->type = type; + cinfo->type = type; cinfo->version = version; cinfo->index = index; - cinfo->fd = fd; + cinfo->fd = fd; - return IPC_ERROR_NONE; + return IPC_ERROR_NONE; } // add an arbitrary file descriptor to read enum ipc_errors ipc_add_fd (struct ipc_connection_infos *cinfos, int fd) { - if (cinfos == NULL) { - return IPC_ERROR_ADD_FD__NO_PARAM_CINFOS; - } + T_R ((cinfos == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS); - struct ipc_connection_info *cinfo = NULL; + struct ipc_connection_info *cinfo = NULL; - cinfo = malloc (sizeof(struct ipc_connection_info)); - if (cinfo == NULL) { - return IPC_ERROR_NOT_ENOUGH_MEMORY; - } - memset (cinfo, 0, sizeof(struct ipc_connection_info)); + SECURE_BUFFER_HEAP_ALLOCATION_R (cinfo, sizeof(struct ipc_connection_info), , IPC_ERROR_NOT_ENOUGH_MEMORY); - enum ipc_errors ret; - ipc_connection_gen (cinfo, 0, 0, fd, IPC_CONNECTION_TYPE_EXTERNAL); + ipc_connection_gen (cinfo, 0, 0, fd, IPC_CONNECTION_TYPE_EXTERNAL); - return ipc_add (cinfos, cinfo); + return ipc_add (cinfos, cinfo); } // remove a connection from its file descriptor enum ipc_errors ipc_del_fd (struct ipc_connection_infos *cinfos, int fd) { - assert(cinfos != NULL); - if (cinfos == NULL) { - return IPC_ERROR_DEL_FD__NO_PARAM_CINFOS; - } + T_R ((cinfos == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS); + T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST); - if (cinfos->cinfos == NULL) { - return IPC_ERROR_DEL_FD__EMPTY_LIST; - } - - int32_t i; + size_t i; for (i = 0; i < cinfos->size; i++) { if (cinfos->cinfos[i]->fd == fd) { - free (cinfos->cinfos[i]); + free (cinfos->cinfos[i]); cinfos->size--; if (cinfos->size == 0) { - // free cinfos->cinfos + // free cinfos->cinfos ipc_connections_free (cinfos); } else { - cinfos->cinfos[i] = cinfos->cinfos[cinfos->size]; + cinfos->cinfos[i] = cinfos->cinfos[cinfos->size]; cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * cinfos->size); if (cinfos->cinfos == NULL) { @@ -528,26 +599,16 @@ enum ipc_errors ipc_del_fd (struct ipc_connection_infos *cinfos, int fd) void ipc_connection_print (struct ipc_connection_info *cinfo) { - if (cinfo == NULL) { - return; - } + T_R ((cinfo == NULL), ); - printf ("fd %d: index %d, version %d, type %c" - , cinfo->fd, cinfo->index, cinfo->version, cinfo->type); - - if (cinfo->spath != NULL) { - printf (", path %s\n", cinfo->spath); - } - else { - printf ("\n"); - } + 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); } void ipc_connections_print (struct ipc_connection_infos *cinfos) { - int32_t i; - for (i = 0; i < cinfos->size; i++) { - printf("[%d] : ", i); + for (size_t i = 0; i < cinfos->size; i++) { ipc_connection_print(cinfos->cinfos[i]); } } diff --git a/src/error.c b/src/error.c index 553ea97..5a4d14e 100644 --- a/src/error.c +++ b/src/error.c @@ -10,102 +10,113 @@ struct ipc_errors_verbose { static struct ipc_errors_verbose ipc_errors_verbose [] = { /* general errors */ - IPC_ERROR_NONE, "no error" - , IPC_ERROR_NOT_ENOUGH_MEMORY, "not enough memory" - , IPC_ERROR_CLOSED_RECIPIENT, "closed recipient" + { IPC_ERROR_NONE, "no error" } + , { IPC_ERROR_NOT_ENOUGH_MEMORY, "not enough memory" } + , { IPC_ERROR_CLOSED_RECIPIENT, "closed recipient" } - , 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_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__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_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" - , IPC_ERROR_ACCEPT, "ipc_accept: error on accept function" + , { IPC_ERROR_ACCEPT__NO_SERVICE_PARAM, "ipc_accept: no service param" } + , { IPC_ERROR_ACCEPT__NO_CLIENT_PARAM, "ipc_accept: no client param" } + , { IPC_ERROR_ACCEPT, "ipc_accept: error on accept function" } - , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM, "ipc_handle_new_connection: no cinfo param" - , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM, "ipc_handle_new_connection: no cinfos param" + , { IPC_ERROR_RECEIVE_FD__RECVMSG, "ipc_receive_fd: recvmsg function" } + , { IPC_ERROR_RECEIVE_FD__NO_PARAM_FD, "ipc_receive_fd: no fd param" } + , { IPC_ERROR_PROVIDE_FD__SENDMSG, "ipc_provide_fd: sendmsg function" } - , IPC_ERROR_WAIT_EVENT__SELECT, "ipc_wait_event: error on the select function" - , 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_WRITE__NO_MESSAGE_PARAM, "ipc_write: no message param" } + , { IPC_ERROR_WRITE__NOT_ENOUGH_DATA, "ipc_write: no enough data sent" } + , { IPC_ERROR_READ__NO_MESSAGE_PARAM, "ipc_read: no message param" } - , IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC, "ipc_handle_new_connection: error on malloc function" + , { IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM, "ipc_handle_new_connection: no cinfo param" } + , { IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM, "ipc_handle_new_connection: no cinfos param" } - , IPC_ERROR_ADD__EMPTY_LIST, "ipc_clients_add: empty list: realloc failed" - , IPC_ERROR_ADD__NO_PARAM_CLIENTS, "ipc_clients_add: no param client list" - , IPC_ERROR_ADD__NO_PARAM_CLIENT, "ipc_clients_add: no param client" + , { IPC_ERROR_WAIT_EVENT__SELECT, "ipc_wait_event: error on the select function" } + , { 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_ADD_FD__NO_PARAM_CINFOS, "ipc_add_fd: no cinfos param" - , IPC_ERROR_ADD_FD__EMPTY_LIST, "ipc_add_fd: empty list after realloc (memory problem)" + , { 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_NETWORKD__NETWORKD, "ipc_contact_networkd: cannot retrieve fd"} - , IPC_ERROR_DEL_FD__NO_PARAM_CINFOS, "ipc_del_fd: no cinfos param" - , IPC_ERROR_DEL_FD__EMPTIED_LIST, "ipc_del_fd: empty list after realloc (memory problem)" - , IPC_ERROR_DEL_FD__EMPTY_LIST, "ipc_del_fd: empty list" - , IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT, "ipc_del_fd: cannot find user" + , { IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC, "ipc_handle_new_connection: error on malloc function" } + + , { IPC_ERROR_ADD__MALLOC, "ipc_add: first memory allocation failed" } + , { IPC_ERROR_ADD__EMPTY_LIST, "ipc_add: empty list: realloc failed" } + , { IPC_ERROR_ADD__NO_PARAM_CLIENTS, "ipc_add: no param client list" } + , { IPC_ERROR_ADD__NO_PARAM_CLIENT, "ipc_add: no param client" } + + , { IPC_ERROR_ADD_FD__NO_PARAM_CINFOS, "ipc_add_fd: no cinfos param" } + , { IPC_ERROR_ADD_FD__EMPTY_LIST, "ipc_add_fd: empty list after realloc (memory problem)" } + + , { IPC_ERROR_DEL_FD__NO_PARAM_CINFOS, "ipc_del_fd: no cinfos param" } + , { IPC_ERROR_DEL_FD__EMPTIED_LIST, "ipc_del_fd: empty list after realloc (memory problem)" } + , { IPC_ERROR_DEL_FD__EMPTY_LIST, "ipc_del_fd: empty list" } + , { IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT, "ipc_del_fd: cannot find user" } + + , { IPC_ERROR_DEL__EMPTY_LIST, "ipc_del: empty list" } + , { IPC_ERROR_DEL__EMPTIED_LIST, "ipc_del: cannot realloc" } + , { IPC_ERROR_DEL__CANNOT_FIND_CLIENT, "ipc_del: cannot find client" } + , { IPC_ERROR_DEL__NO_CLIENTS_PARAM, "ipc_del: no clients param" } + , { IPC_ERROR_DEL__NO_CLIENT_PARAM, "ipc_del: no client param" } - , IPC_ERROR_DEL__EMPTY_LIST, "ipc_clients_del: empty list" - , IPC_ERROR_DEL__EMPTIED_LIST, "ipc_clients_del: cannot realloc" - , IPC_ERROR_DEL__CANNOT_FIND_CLIENT, "ipc_clients_del: cannot find client" - , IPC_ERROR_DEL__NO_CLIENTS_PARAM, "ipc_clients_del: no clients param" - , IPC_ERROR_DEL__NO_CLIENT_PARAM, "ipc_clients_del: no client param" - /* unix socket */ - , IPC_ERROR_USOCK_SEND, "usock_send: cannot send message" + , { IPC_ERROR_USOCK_SEND, "usock_send: cannot send message" } - , IPC_ERROR_USOCK_CONNECT__SOCKET, "usock_connect: error on socket function" - , IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR, "usock_connect: wrong file descriptor" - , IPC_ERROR_USOCK_CONNECT__EMPTY_PATH, "usock_connect: empty path" + , { IPC_ERROR_USOCK_CONNECT__SOCKET, "usock_connect: error on socket function" } + , { IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR, "usock_connect: wrong file descriptor" } + , { IPC_ERROR_USOCK_CONNECT__EMPTY_PATH, "usock_connect: empty path" } - , IPC_ERROR_USOCK_CLOSE, "usock_close: close function" + , { IPC_ERROR_USOCK_CLOSE, "usock_close: close function" } - , IPC_ERROR_USOCK_REMOVE__UNLINK, "usock_remove: unlink function" - , IPC_ERROR_USOCK_REMOVE__NO_FILE, "usock_remove: file not found" + , { IPC_ERROR_USOCK_REMOVE__UNLINK, "usock_remove: unlink function" } + , { IPC_ERROR_USOCK_REMOVE__NO_FILE, "usock_remove: file not found" } - , IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR, "usock_init: no file descriptor" - , IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR, "usock_init: wrong file descriptor" - , IPC_ERROR_USOCK_INIT__EMPTY_PATH, "usock_init: empty path" - , IPC_ERROR_USOCK_INIT__BIND, "usock_init: error on bind function" - , IPC_ERROR_USOCK_INIT__LISTEN, "usock_init: error on listen function" + , { IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR, "usock_init: no file descriptor" } + , { IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR, "usock_init: wrong file descriptor" } + , { IPC_ERROR_USOCK_INIT__EMPTY_PATH, "usock_init: empty path" } + , { IPC_ERROR_USOCK_INIT__BIND, "usock_init: error on bind function" } + , { IPC_ERROR_USOCK_INIT__LISTEN, "usock_init: error on listen function" } - , IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR, "ipc_usock_accept: no path file descriptor" - , IPC_ERROR_USOCK_ACCEPT, "ipc_usock_accept: error on accept function" + , { IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR, "ipc_usock_accept: no path file descriptor" } + , { IPC_ERROR_USOCK_ACCEPT, "ipc_usock_accept: error on accept function" } - , IPC_ERROR_USOCK_RECV__NO_BUFFER, "ipc_usock_recv: no buffer in usock_recv" - , IPC_ERROR_USOCK_RECV__NO_LENGTH, "ipc_usock_recv: no length in usock_recv" - , IPC_ERROR_USOCK_RECV, "ipc_usock_recv: cannot receive message in usock_recv" + , { IPC_ERROR_USOCK_RECV__NO_BUFFER, "ipc_usock_recv: no buffer in usock_recv" } + , { IPC_ERROR_USOCK_RECV__NO_LENGTH, "ipc_usock_recv: no length in usock_recv" } + , { IPC_ERROR_USOCK_RECV, "ipc_usock_recv: cannot receive message in usock_recv" } + , { IPC_ERROR_USOCK_RECV__MESSAGE_SIZE, "ipc_usock_recv: message length > maximum allowed" } /* message function errors */ - , IPC_ERROR_MESSAGE_NEW__NO_MESSAGE_PARAM, "ipc_message_new: no message param" - , IPC_ERROR_MESSAGE_READ__NO_MESSAGE_PARAM, "ipc_message_read: no message param" + , { IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH, "ipc_message_write: message is longer than accepted" } - , IPC_ERROR_MESSAGE_WRITE__NO_MESSAGE_PARAM, "ipc_message_write: no message param" - , IPC_ERROR_MESSAGE_WRITE__NOT_ENOUGH_DATA, "ipc_message_write: no enough data sent" + , { IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM, "ipc_message_format: no message param" } + , { IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS, "ipc_message_format: inconsistent params" } + , { IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE, "ipc_message_format: length param > maximum allowed" } + , { IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE, "ipc_message_format: read message size > maximum allowed" } - , IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM, "ipc_message_format: no message param" - , IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS, "ipc_message_format: inconsistent params" - , IPC_ERROR_MESSAGE_FORMAT__LENGTH, "ipc_message_format: length param > maximum allowed" + , { IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE, "ipc_message_format_write: empty message" } + , { IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE, "ipc_message_format_write: empty message size" } + , { IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER, "ipc_message_format_write: empty buffer" } - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE, "ipc_message_format_write: empty message" - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE, "ipc_message_format_write: empty message size" - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER, "ipc_message_format_write: empty buffer" + , { IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE, "ipc_message_format_read: empty message" } + , { IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER, "ipc_message_format_read: empty buffer" } + , { IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE, "ipc_message_format_read: message size > maximum allowed" } - , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE, "ipc_message_format_read: empty message" - , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER, "ipc_message_format_read: empty buffer" - , IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE, "ipc_message_format_read: message size > maximum allowed" - - , IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST, "ipc_message_empty: empty message list" + , { IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST, "ipc_message_empty: empty message list" } }; const char * ipc_errors_get (enum ipc_errors e) diff --git a/src/ipc.h b/src/ipc.h index e43326b..6ca0701 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -9,133 +9,206 @@ #include // error numbers #include +/*** + * global defaults + **/ + #define RUNDIR "/run/ipc/" #define PATH_MAX 4096 #define IPC_HEADER_SIZE 6 #define IPC_MAX_MESSAGE_SIZE 8000000-IPC_HEADER_SIZE -// #define IPC_MAX_MESSAGE_SIZE 100-IPC_HEADER_SIZE -// #include "queue.h" + +#define IPC_VERSION 2 + +#if ! defined(IPC_WITHOUT_ERRORS) && ! defined(IPC_WITH_ERRORS) +#define IPC_WITH_ERRORS 2 +#endif +#define IPC_WITH_UNIX_SOCKETS + +#ifdef IPC_WITH_UNIX_SOCKETS +#include "usocket.h" +#endif + +/*** + * grooming macros + **/ #define SECURE_DECLARATION(t,v) t v; memset(&v,0,sizeof(t)); +#define SECURE_BUFFER_DECLARATION(type,name,size) type name[size]; memset(&name, 0, sizeof(type) * size); +#define SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr,r) { p = malloc (len); if (p == NULL) { instr; r; } ; memset(p, 0, len); } +#define SECURE_BUFFER_HEAP_ALLOCATION_R(p,len,instr,r) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, return r ) +#define SECURE_BUFFER_HEAP_ALLOCATION_Q(p,len,instr,r) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, exit(r)) -#define IPC_VERSION 1 +#if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 +// print error string +#define PRINT_ERR(code) const char *estr = ipc_errors_get (code); LOG_ERROR ("%s", estr); +#define PRINT_ERR_STR(code,err) { const char *estr = ipc_errors_get (code); LOG_ERROR ("%s - %s", err, estr); } +#else +#define PRINT_ERR(code) +#define PRINT_ERR_STR(code,err) +#endif +// Test macros, requiring the variable `enum ipc_errors ret` + +// one macro to rule them all! +// 1. function to test +// 2. Test IPC error based (test itself) +// 3. Print error (then ipc-error message) +// 4. Instructions to exec on failure +// 5. Return something +#define TIPC_T_P_I_R(f, t, err, instr, r) { enum ipc_errors ret = f;\ + if (t) {\ + PRINT_ERR_STR(ret, err); \ + instr;\ + r;\ + } } + +// P = print somehting with LOG_ERROR +// NP = no LOG_ERROR print +// R = return r param +// RR = return "ret" variable +// RV = return void +// Q = quit +// I = additionnal instructions before returning on error + +#define TIPC_P_I_R(f, t, err, instr, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, instr, return r) +#define TIPC_P_I_Q(f, t, err, instr, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, instr, quit(r)) +#define TIPC_P_Q(f, err,r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, ;, exit(r)) +#define TIPC_P_R(f, err,r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, ;, return r) +#define TIPC_P_RR(f, err) TIPC_P_R(f,err,ret) +#define TIPC_F_RR(f, format) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", LOG_ERROR format ;, return ret) +#define TIPC_F_Q(f, format, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", LOG_ERROR format ;, exit(r)) +#define TIPC_F_R(f, format, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", LOG_ERROR format ;, return r) +#define TIPC_P_RV(f, err) TIPC_P_R(f,err,;) +#define TIPC_P(f, err) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, ;, ;) +#define TIPC_T_I_P_Q(f,t,instr,err,r) TIPC_T_P_I_R(f, t, err, instr, exit(r)) +#define TIPC_T_I_RR(f,t,instr) TIPC_T_P_I_R(f, t, "", instr, return ret) +#define TIPC_I_RR(f,instr) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", instr, return ret) +#define TIPC_RR(f) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", ;, return ret) +#define TIPC_NP_RR(f) { enum ipc_errors ret = f; if (ret != IPC_ERROR_NONE) { return ret; } } + +// Tests macros, do not require `enum ipc_errors ret` variable +// test => return error code +#define T_R(t,r) if t { return r; } +// test => perror, formatted message then return (for system functions) +#define T_PERROR_F_R(t,m,fmt,r) if t { perror(m); LOG_ERROR fmt; return r; } +// test => perror then return (for system functions) +#define T_PERROR_R(t,m,r) if t { perror(m); return r; } +// test => perror then exit (for system functions) +#define T_PERROR_Q(t,m,r) if t { perror(m); exit(r); } + + +// Switch cases macros +// print on error +#define ERROR_CASE(e,f,m) case e : { LOG_ERROR ("function %s: %s", f, m); } break; + + +/*** + * structures and enumerations + **/ enum msg_types { - MSG_TYPE_SERVER_CLOSE = 0 - , MSG_TYPE_ERR - , MSG_TYPE_DATA + MSG_TYPE_SERVER_CLOSE = 0 + , MSG_TYPE_ERR = 1 + , MSG_TYPE_DATA = 2 + , MSG_TYPE_NETWORK_LOOKUP = 3 } message_types; enum ipc_event_type { - IPC_EVENT_TYPE_NOT_SET - , IPC_EVENT_TYPE_ERROR - - , IPC_EVENT_TYPE_EXTRA_SOCKET - - , IPC_EVENT_TYPE_CONNECTION - , IPC_EVENT_TYPE_DISCONNECTION - , IPC_EVENT_TYPE_MESSAGE + 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 }; enum ipc_errors { + /* general errors */ - IPC_ERROR_NONE - , IPC_ERROR_NOT_ENOUGH_MEMORY - , IPC_ERROR_CLOSED_RECIPIENT - - , IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM - , IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM - , IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM - , IPC_ERROR_SERVER_INIT__MALLOC - - , IPC_ERROR_CONNECTION__NO_SERVER - , IPC_ERROR_CONNECTION__NO_SERVICE_NAME - , IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM - - , IPC_ERROR_CONNECTION_GEN__NO_CINFO - - , IPC_ERROR_ACCEPT__NO_SERVICE_PARAM - , IPC_ERROR_ACCEPT__NO_CLIENT_PARAM - , IPC_ERROR_ACCEPT - - , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM - , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM - - , IPC_ERROR_WAIT_EVENT__SELECT - , IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM - , IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM - - , IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC - - , IPC_ERROR_ADD__EMPTY_LIST - , IPC_ERROR_ADD__NO_PARAM_CLIENTS - , IPC_ERROR_ADD__NO_PARAM_CLIENT - - , IPC_ERROR_ADD_FD__NO_PARAM_CINFOS - , IPC_ERROR_ADD_FD__EMPTY_LIST - - , IPC_ERROR_DEL_FD__NO_PARAM_CINFOS - , IPC_ERROR_DEL_FD__EMPTIED_LIST - , IPC_ERROR_DEL_FD__EMPTY_LIST - , IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT - - , IPC_ERROR_DEL__EMPTY_LIST - , IPC_ERROR_DEL__EMPTIED_LIST - , IPC_ERROR_DEL__CANNOT_FIND_CLIENT - , IPC_ERROR_DEL__NO_CLIENTS_PARAM - , IPC_ERROR_DEL__NO_CLIENT_PARAM + IPC_ERROR_NONE = 0 + , IPC_ERROR_NOT_ENOUGH_MEMORY = 1 + , IPC_ERROR_CLOSED_RECIPIENT = 2 + , IPC_ERROR_SERVICE_PATH__NO_PATH = 3 + , IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME = 4 + , IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM = 5 + , IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM = 6 + , IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM = 7 + , IPC_ERROR_SERVER_INIT__MALLOC = 8 + , IPC_ERROR_WRITE__NO_MESSAGE_PARAM = 9 + , IPC_ERROR_WRITE__NOT_ENOUGH_DATA = 10 + , IPC_ERROR_READ__NO_MESSAGE_PARAM = 11 + , IPC_ERROR_CONNECTION__NO_SERVER = 12 + , IPC_ERROR_CONNECTION__NO_SERVICE_NAME = 13 + , IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM = 14 + , IPC_ERROR_CONNECTION_GEN__NO_CINFO = 15 + , IPC_ERROR_ACCEPT__NO_SERVICE_PARAM = 16 + , IPC_ERROR_ACCEPT__NO_CLIENT_PARAM = 17 + , IPC_ERROR_ACCEPT = 18 + , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM = 19 + , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM = 20 + , IPC_ERROR_WAIT_EVENT__SELECT = 21 + , IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM = 22 + , IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM = 23 + , IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC = 24 + , IPC_ERROR_ADD__EMPTY_LIST = 25 + , IPC_ERROR_ADD__NO_PARAM_CLIENTS = 26 + , IPC_ERROR_ADD__NO_PARAM_CLIENT = 27 + , IPC_ERROR_ADD__MALLOC = 28 + , IPC_ERROR_ADD_FD__NO_PARAM_CINFOS = 29 + , IPC_ERROR_ADD_FD__EMPTY_LIST = 30 + , IPC_ERROR_DEL_FD__NO_PARAM_CINFOS = 31 + , IPC_ERROR_DEL_FD__EMPTIED_LIST = 32 + , IPC_ERROR_DEL_FD__EMPTY_LIST = 33 + , IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT = 34 + , IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM = 35 + , IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM = 36 + , IPC_ERROR_CONTACT_NETWORKD__NETWORKD = 37 + , IPC_ERROR_DEL__EMPTY_LIST = 38 + , IPC_ERROR_DEL__EMPTIED_LIST = 39 + , IPC_ERROR_DEL__CANNOT_FIND_CLIENT = 40 + , IPC_ERROR_DEL__NO_CLIENTS_PARAM = 41 + , IPC_ERROR_DEL__NO_CLIENT_PARAM = 42 - /* unix socket */ - - , IPC_ERROR_USOCK_SEND - - , IPC_ERROR_USOCK_CONNECT__SOCKET - , IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR - , IPC_ERROR_USOCK_CONNECT__EMPTY_PATH - , IPC_ERROR_USOCK_CONNECT__CONNECT - - , IPC_ERROR_USOCK_CLOSE - - , IPC_ERROR_USOCK_REMOVE__UNLINK - , IPC_ERROR_USOCK_REMOVE__NO_FILE - - , IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR - , IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR - , IPC_ERROR_USOCK_INIT__EMPTY_PATH - , IPC_ERROR_USOCK_INIT__BIND - , IPC_ERROR_USOCK_INIT__LISTEN - - , IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR - , IPC_ERROR_USOCK_ACCEPT - - , IPC_ERROR_USOCK_RECV__NO_BUFFER - , IPC_ERROR_USOCK_RECV__NO_LENGTH - , IPC_ERROR_USOCK_RECV - + , IPC_ERROR_USOCK_SEND = 1 + , IPC_ERROR_USOCK_CONNECT__SOCKET = 43 + , IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR = 44 + , IPC_ERROR_USOCK_CONNECT__EMPTY_PATH = 45 + , IPC_ERROR_USOCK_CONNECT__CONNECT = 46 + , IPC_ERROR_USOCK_CLOSE = 47 + , IPC_ERROR_USOCK_REMOVE__UNLINK = 48 + , IPC_ERROR_USOCK_REMOVE__NO_FILE = 49 + , IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR = 50 + , IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR = 51 + , IPC_ERROR_USOCK_INIT__EMPTY_PATH = 52 + , IPC_ERROR_USOCK_INIT__BIND = 53 + , IPC_ERROR_USOCK_INIT__LISTEN = 54 + , IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR = 55 + , IPC_ERROR_USOCK_ACCEPT = 56 + , IPC_ERROR_USOCK_RECV__NO_BUFFER = 57 + , IPC_ERROR_USOCK_RECV__NO_LENGTH = 58 + , IPC_ERROR_USOCK_RECV = 59 + , IPC_ERROR_USOCK_RECV__MESSAGE_SIZE = 60 + , IPC_ERROR_RECEIVE_FD__NO_PARAM_FD = 61 + , IPC_ERROR_RECEIVE_FD__RECVMSG = 62 + , IPC_ERROR_PROVIDE_FD__SENDMSG = 63 /* message function errors */ - - , IPC_ERROR_MESSAGE_NEW__NO_MESSAGE_PARAM - , IPC_ERROR_MESSAGE_READ__NO_MESSAGE_PARAM - - , IPC_ERROR_MESSAGE_WRITE__NO_MESSAGE_PARAM - , IPC_ERROR_MESSAGE_WRITE__NOT_ENOUGH_DATA - - , IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM - , IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS - , IPC_ERROR_MESSAGE_FORMAT__LENGTH - - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER - - , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE - , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER - , IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE - - , IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST + , IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH = 64 + , IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE = 65 + , IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM = 66 + , IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS = 67 + , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE = 68 + , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE = 69 + , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER = 70 + , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE = 71 + , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER = 72 + , IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE = 73 + , IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE = 74 + , IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST = 75 }; @@ -149,7 +222,7 @@ struct ipc_connection_info { struct ipc_connection_infos { struct ipc_connection_info ** cinfos; - int32_t size; + size_t size; }; @@ -167,27 +240,42 @@ struct ipc_event { }; -/** - * MACROS +/*** + * logging macros **/ -// #define IPC_WITH_ERRORS 3 - #ifdef IPC_WITH_ERRORS #include "logger.h" -#define handle_err(fun,msg)\ - do { log_error ("%s: file %s line %d %s", fun, __FILE__, __LINE__, msg); } while (0) +// XXX: ##__VA_ARGS__ is a GNU extension to avoid requiring more arguments +#define LOG_ERROR(format, ...) log_error ( __FILE__ ":%d:" format, __LINE__, ##__VA_ARGS__ ) +#define LOG_INFO(format, ...) log_info ( __FILE__ ":%d:" format, __LINE__, ##__VA_ARGS__ ) #else -#define handle_err(fun,msg) +#define LOG_ERROR(format, ...) +#define LOG_INFO(format, ...) #endif +#if IPC_WITH_ERRORS > 2 +#define LOG_DEBUG(format, ...) log_debug ( __FILE__ ":%d:" format, __LINE__, ##__VA_ARGS__ ) +#else +#define LOG_DEBUG(format, ...) +#endif + +/*** + * ipc event macros + **/ + #define IPC_EVENT_SET(pevent,type_,message_,origin_) {\ pevent->type = type_; \ 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) {\ pevent->type = IPC_EVENT_TYPE_NOT_SET;\ if (pevent->m != NULL) {\ @@ -197,21 +285,19 @@ struct ipc_event { }\ }; -#define IPC_WITH_UNIX_SOCKETS -#ifdef IPC_WITH_UNIX_SOCKETS -#include "usocket.h" -#endif - -#define LOG +/*** + * logging functions + **/ void log_error (const char* message, ...); void log_info (const char* message, ...); void log_debug (const char* message, ...); + /** * main public functions - */ + **/ enum ipc_errors ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname); enum ipc_errors ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname); @@ -243,40 +329,78 @@ int8_t ipc_connection_eq (const struct ipc_connection_info *p1, const struct ipc enum ipc_errors ipc_connection_gen (struct ipc_connection_info *cinfo , uint32_t index, uint32_t version, int fd, char type); -void ipc_connection_print (struct ipc_connection_info *cinfo); -void ipc_connections_print (struct ipc_connection_infos *cinfos); +void ipc_connection_print (struct ipc_connection_info *cinfo); +void ipc_connections_print (struct ipc_connection_infos *cinfos); +void ipc_connections_close (struct ipc_connection_infos *cinfos); // get explanation about an error const char * ipc_errors_get (enum ipc_errors e); -/** +/*** * message functions **/ -// used to create msg structure with a certain payload length (0 for no payload memory allocation) -enum ipc_errors ipc_message_new (struct ipc_message **m, ssize_t paylen); +uint32_t ipc_message_raw_serialize (char *buffer, char type, char user_type, char * message, uint32_t message_size); + // used to create msg structure from buffer -enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, ssize_t msize); +enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, size_t msize); // used to create buffer from msg structure -enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **buf, ssize_t *msize); +enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **buf, size_t *msize); -// read a structure msg from fd -enum ipc_errors ipc_message_read (int32_t fd, struct ipc_message *m); -// write a structure msg to fd -enum ipc_errors ipc_message_write (int32_t fd, const struct ipc_message *m); - -enum ipc_errors ipc_message_format (struct ipc_message *m - , char type, char utype, const char *payload, ssize_t length); -enum ipc_errors ipc_message_format_data (struct ipc_message *m - , char utype, const char *payload, ssize_t length); +enum ipc_errors ipc_message_format (struct ipc_message *m, char type, char utype, const char *payload, size_t length); +enum ipc_errors ipc_message_format_data (struct ipc_message *m, char utype, const char *payload, size_t length); enum ipc_errors ipc_message_format_server_close (struct ipc_message *m); - enum ipc_errors ipc_message_empty (struct ipc_message *m); +/*** + * non public functions + **/ -// non public functions -void service_path (char *path, const char *sname, int32_t index, int32_t version); + +enum ipc_errors ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p); +enum ipc_errors ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname); +enum ipc_errors service_path (char *path, const char *sname, int32_t index, int32_t version); +char * log_get_logfile_dir (char *buf, size_t size); +void log_get_logfile_name (char *buf, size_t size); + + +/*** + * networkd 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; +}; + +enum ipc_errors 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); + + +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_print (struct ipc_switchings *is); + + +enum ipc_errors ipc_receive_fd (int sock, int *fd); +enum ipc_errors ipc_provide_fd (int sock, int fd); #endif diff --git a/src/logger.c b/src/logger.c index 5fda936..1962a93 100644 --- a/src/logger.c +++ b/src/logger.c @@ -3,18 +3,86 @@ #include #include #include +#include +#include +#include +#include + +#include "ipc.h" + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_GNU_SOURCE) +#else +extern char *__progname; +#endif + +char * log_get_logfile_dir (char *buf, size_t size) +{ + char * datadir = getenv ("XDG_DATA_HOME"); + if (datadir == NULL) { + datadir = getenv ("HOME"); + if (datadir == NULL) { + return buf + snprintf (buf, size, "./ipc/"); + } + else { + return buf + snprintf (buf, size, "%s/.local/share/ipc/", datadir); + } + } + return buf + snprintf (buf, size, "%s/ipc/", datadir); +} + +void log_get_logfile_name (char *buf, size_t size) { + char *logfile = getenv ("IPC_LOGFILE"); + if (logfile == NULL) { + char *buf_after_dir; + buf_after_dir = log_get_logfile_dir (buf, size); + pid_t pid = getpid(); + +#if defined(__APPLE__) || defined(__FreeBSD__) + const char * appname = getprogname(); +#elif defined(_GNU_SOURCE) + const char * appname = program_invocation_name; +#elif defined(__linux__) + const char * appname = __progname; +#else +#error "cannot know the application name for this environment" +#endif + + snprintf (buf_after_dir, size - (buf_after_dir - buf), "%s-%d.log", appname, pid); + return; + } + + snprintf (buf, size, "%s", logfile); +} void log_format (const char* tag, const char* message, va_list args) { time_t now; time(&now); - char * date =ctime(&now); - date[strlen(date) - 1] = '\0'; - printf("%s:%s: ", date, tag); - vprintf(message, args); + struct tm *t = localtime (&now); - printf("\n"); + SECURE_BUFFER_DECLARATION (char, date, 200); + + snprintf (date, 200, "%d-%02d-%02d_%02d-%02d-%02d" + , t->tm_year+1900, t->tm_mon +1, t->tm_mday + , t->tm_hour, t->tm_min, t->tm_sec); + + SECURE_BUFFER_DECLARATION (char, logfile, BUFSIZ); + log_get_logfile_name (logfile, BUFSIZ); + + FILE * logfd = fopen (logfile, "a"); + if (logfd == NULL) { + fprintf (stderr, "something gone horribly wrong: cannot open logfile: %s\n", logfile); + return; + } + + fprintf (logfd, "%s:%s:", date, tag); + vfprintf(logfd, message, args); + fprintf (logfd, "\n"); + + fflush (logfd); + + fclose (logfd); } void log_error (const char* message, ...) { diff --git a/src/message.c b/src/message.c index 850ad52..8626555 100644 --- a/src/message.c +++ b/src/message.c @@ -9,70 +9,55 @@ #include "message.h" #include "usocket.h" -#include +// #define IPC_WITH_ERRORS 3 + +uint32_t ipc_message_raw_serialize (char *buffer, char type, char user_type, char * message, uint32_t message_size) +{ + uint32_t msize = 6 + message_size; + buffer[0] = type; + + uint32_t msize_n = htonl (message_size); + uint32_t index = 1; + + memcpy (buffer + index, &msize_n, sizeof (uint32_t)); + index += sizeof (uint32_t); + buffer[index] = user_type; + index += 1; + memcpy (buffer + index, message, message_size); + + return msize; +} -#define IPC_WITH_ERRORS 3 void ipc_message_print (const struct ipc_message *m) { - assert (m != NULL); + if (m == NULL) return; + #if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 - printf ("msg: type %d len %d\n", m->type, m->length); + LOG_INFO ("msg: type %d len %d\n", m->type, m->length); #endif } - -enum ipc_errors ipc_message_new (struct ipc_message **m, ssize_t paylen) +enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, size_t msize) { - m = malloc (sizeof(struct ipc_message)); - if (m == NULL) { - return IPC_ERROR_MESSAGE_NEW__NO_MESSAGE_PARAM; - } - - memset (*m, 0, sizeof (struct ipc_message)); - - if (paylen != 0) { - ((struct ipc_message *)m)->payload = malloc (paylen); - if (((struct ipc_message *)m)->payload == NULL) { - free (*m); - return IPC_ERROR_NOT_ENOUGH_MEMORY; - } - } - - return IPC_ERROR_NONE; -} - -enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, ssize_t msize) -{ - assert (m != NULL); - assert (buf != NULL); - assert (msize <= IPC_MAX_MESSAGE_SIZE); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE; - } - - if (buf == NULL) { - return IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER; - } - - if (msize > IPC_MAX_MESSAGE_SIZE) { - return IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE; - } + T_R ((m == NULL), IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE); + T_R ((buf == NULL), IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER); + T_R ((msize > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE); // message format: // Type (1 B) | Length (4 B) | UserType (1 B) | Payload (Length B) m->type = buf[0]; - size_t unformated_size = 0; - memcpy (&unformated_size, buf+1, sizeof(size_t)); + uint32_t unformated_size = 0; + memcpy (&unformated_size, buf+1, sizeof(uint32_t)); m->length = ntohl (unformated_size); m->user_type = buf[1 + sizeof m->length]; - assert (m->length <= IPC_MAX_MESSAGE_SIZE); + T_R ((m->length > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE); #if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 - printf ("receiving msg:\ttype %d, paylen %u, total %lu\n", m->type, m->length, msize); + LOG_INFO ("receiving msg: type %d, paylen %u, total %lu", m->type, m->length, msize); #endif - assert (m->length == msize - IPC_HEADER_SIZE || m->length == 0); + T_R ((m->length != msize - IPC_HEADER_SIZE && m->length != 0) + , IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE); if (m->payload != NULL) { free (m->payload); @@ -90,24 +75,12 @@ enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, return IPC_ERROR_NONE; } -enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **buf, ssize_t *msize) +enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **buf, size_t *msize) { - assert (m != NULL); - assert (buf != NULL); - assert (msize != NULL); - assert (m->length <= IPC_MAX_MESSAGE_SIZE); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE; - } - - if (buf == NULL) { - return IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER; - } - - if (msize == NULL) { - return IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE; - } + T_R ((m == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE); + T_R ((buf == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER); + T_R ((msize == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE); + T_R ((m->length > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH); if (*buf == NULL) { *buf = malloc (IPC_HEADER_SIZE + m->length); @@ -115,10 +88,9 @@ enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **bu } char *buffer = *buf; - uint32_t paylen = htonl(m->length); + uint32_t net_paylen = htonl(m->length); buffer[0] = m->type; - uint32_t net_paylen = htonl(m->length); memcpy (buffer + 1, &net_paylen, sizeof(uint32_t)); buffer[1 + sizeof m->length] = m->user_type; if (m->payload != NULL && m->length > 0) { @@ -128,96 +100,21 @@ enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **bu *msize = IPC_HEADER_SIZE + m->length; #if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 - printf ("sending msg:\ttype %u, paylen %u, msize %lu\n", m->type, m->length, *msize); + LOG_INFO ("sending msg: type %u, paylen %u, msize %lu", m->type, m->length, *msize); #endif return IPC_ERROR_NONE; } -// IPC_ERROR_CLOSED_RECIPIENT on closed recipient -enum ipc_errors ipc_message_read (int32_t fd, struct ipc_message *m) -{ - assert (m != NULL); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_READ__NO_MESSAGE_PARAM; - } - - char *buf = NULL; - ssize_t msize = IPC_MAX_MESSAGE_SIZE; - - enum ipc_errors ret = usock_recv (fd, &buf, &msize); - if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) { - handle_err ("msg_read", "usock_recv"); - return ret; - } - - // closed recipient, buffer already freed - if (ret == IPC_ERROR_CLOSED_RECIPIENT) { - return IPC_ERROR_CLOSED_RECIPIENT; - } - - if (buf != NULL) { - ret = ipc_message_format_read (m, buf, msize); - free (buf); - } - return ret; // propagates ipc_message_format return -} - -enum ipc_errors ipc_message_write (int32_t fd, const struct ipc_message *m) -{ - assert (m != NULL); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_WRITE__NO_MESSAGE_PARAM; - } - - char *buf = NULL; - ssize_t msize = 0; - ipc_message_format_write (m, &buf, &msize); - - ssize_t nbytes_sent = 0; - enum ipc_errors ret = usock_send (fd, buf, msize, &nbytes_sent); - if (buf != NULL) { - free (buf); - } - - if (ret != IPC_ERROR_NONE) { - handle_err ("msg_write", "usock_send"); - return ret; - } - - // what was sent != what should have been sent - if (nbytes_sent != msize) { - handle_err ("msg_write", "usock_send did not send enough data"); - return IPC_ERROR_MESSAGE_WRITE__NOT_ENOUGH_DATA; - } - - return IPC_ERROR_NONE; -} - // MSG FORMAT enum ipc_errors ipc_message_format (struct ipc_message *m - , char type, char utype, const char *payload, ssize_t length) + , char type, char utype, const char *payload, size_t length) { - assert (m != NULL); - assert (length <= IPC_MAX_MESSAGE_SIZE); - assert ((length == 0 && payload == NULL) || (length > 0 && payload != NULL)); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM; - } - - if ((length == 0 && payload != NULL) || (length > 0 && payload == NULL)) { - return IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS; - } - - if (length > IPC_MAX_MESSAGE_SIZE) { - handle_err ("msg_format_con", "msgsize > BUFSIZ"); - printf ("msg to format: %ld B)\n", length); - return IPC_ERROR_MESSAGE_FORMAT__LENGTH; - } + T_R ((m == NULL), IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM); + T_R ((length > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE); + T_R (((length == 0 && payload != NULL) || (length > 0 && payload == NULL)) + , IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS); m->type = type; m->user_type = utype; @@ -228,11 +125,7 @@ enum ipc_errors ipc_message_format (struct ipc_message *m free (m->payload); } - m->payload = malloc (length); - if (m->payload == NULL) { - return IPC_ERROR_NOT_ENOUGH_MEMORY; - } - memset (m->payload, 0, length); + SECURE_BUFFER_HEAP_ALLOCATION_R (m->payload, length, , IPC_ERROR_NOT_ENOUGH_MEMORY); } if (payload != NULL) { @@ -241,7 +134,7 @@ enum ipc_errors ipc_message_format (struct ipc_message *m return IPC_ERROR_NONE; } -enum ipc_errors ipc_message_format_data (struct ipc_message *m, char utype, const char *payload, ssize_t length) +enum ipc_errors ipc_message_format_data (struct ipc_message *m, char utype, const char *payload, size_t length) { return ipc_message_format (m, MSG_TYPE_DATA, utype, payload, length); } @@ -253,11 +146,7 @@ enum ipc_errors ipc_message_format_server_close (struct ipc_message *m) enum ipc_errors ipc_message_empty (struct ipc_message *m) { - assert (m != NULL); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST; - } + T_R ((m == NULL), IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST); if (m->payload != NULL) { free (m->payload); diff --git a/src/network.c b/src/network.c new file mode 100644 index 0000000..943f3f7 --- /dev/null +++ b/src/network.c @@ -0,0 +1,163 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ipc.h" + +/** + * TODO: + * describe a protocol to get this working into networkd + * asking networkd 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 + */ + + + +enum ipc_errors ipc_receive_fd (int sock, int *fd) +{ + T_R ((fd == NULL), IPC_ERROR_RECEIVE_FD__NO_PARAM_FD); + *fd = -1; + + SECURE_DECLARATION (struct msghdr, msg); + SECURE_BUFFER_DECLARATION (char, c_buffer, 256); + + /* On Mac OS X, the struct iovec is needed, even if it points to minimal data */ + char m_buffer[1]; + struct iovec io = { .iov_base = m_buffer, .iov_len = sizeof(m_buffer) }; + msg.msg_iov = &io; + msg.msg_iovlen = 1; + + msg.msg_control = c_buffer; + msg.msg_controllen = sizeof(c_buffer); + + T_PERROR_R ((recvmsg(sock, &msg, 0) <= 0), "recvmsg", IPC_ERROR_RECEIVE_FD__RECVMSG); + + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); + + memmove(fd, CMSG_DATA(cmsg), sizeof(*fd)); + + return IPC_ERROR_NONE; +} + +enum ipc_errors ipc_provide_fd (int sock, int fd) +{ + SECURE_DECLARATION (struct msghdr, msg); + SECURE_BUFFER_DECLARATION (char, buf, CMSG_SPACE(sizeof(fd))); + + /* On Mac OS X, the struct iovec is needed, even if it points to minimal data */ + struct iovec io = { .iov_base = "", .iov_len = 1 }; + + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + + struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + + memmove(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + msg.msg_controllen = cmsg->cmsg_len; + + T_PERROR_R ((sendmsg(sock, &msg, 0) < 0), "sendmsg", IPC_ERROR_PROVIDE_FD__SENDMSG); + + return IPC_ERROR_NONE; +} + +void ipc_switching_add (struct ipc_switchings *is, int orig, int dest) +{ + is->collection = realloc(is->collection, sizeof(struct ipc_switching) * (is->size+1)); + if (is->collection == NULL) { + LOG_ERROR ("error realloc"); + exit (EXIT_FAILURE); + } + + is->size++; + + is->collection[is->size-1].orig = orig; + is->collection[is->size-1].dest = dest; +} + +int ipc_switching_del (struct ipc_switchings *is, int fd) +{ + for (size_t i = 0; i < is->size; i++) { + if (is->collection[i].orig == fd || is->collection[i].dest == fd) { + int ret; + + if (fd == is->collection[i].orig) { + ret = is->collection[i].dest; + } + else { + ret = is->collection[i].orig; + } + + 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) { + LOG_ERROR ("error realloc"); + exit (EXIT_FAILURE); + } + + is->size--; + return ret; + } + } + + return -1; +} + +int ipc_switching_get (struct ipc_switchings *is, int fd) +{ + for (size_t i = 0; i < is->size; i++) { + if (is->collection[i].orig == fd) { + return is->collection[i].dest; + } + else if (is->collection[i].dest == fd) { + return is->collection[i].orig; + } + } + + return -1; +} + +void ipc_switching_free (struct ipc_switchings *is) +{ + if (is == NULL) + return; + + if (is->collection != NULL) { + free (is->collection); + is->collection = NULL; + } + is->size = 0; +} + +void ipc_switching_print (struct ipc_switchings *is) +{ + for (size_t i = 0; i < is->size; i++) { + LOG_DEBUG ("client %d - %d", is->collection[i].orig, is->collection[i].dest); + } +} diff --git a/src/usocket.c b/src/usocket.c index 33eb794..8f65ea1 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -9,59 +9,45 @@ #include #include #include -#include #include #include "usocket.h" #include "utils.h" -#define IPC_DEBUG - -#undef handle_err -#define handle_err(a,b) fprintf (stderr, "FUNCTION %s LINE %d ERROR %s\n", a, __LINE__, b); +// #define IPC_DEBUG 3 /** * TODO: non blocking read */ -enum ipc_errors usock_send (const int32_t fd, const char *buf, ssize_t len, ssize_t *sent) +enum ipc_errors usock_send (const int32_t fd, const char *buf, size_t len, size_t *sent) { ssize_t ret = 0; ret = send (fd, buf, len, MSG_NOSIGNAL); - if (ret <= 0) { - handle_err ("usock_send", "send ret <= 0"); - return IPC_ERROR_USOCK_SEND; - } + T_R ((ret <= 0), IPC_ERROR_USOCK_SEND); *sent = ret; return IPC_ERROR_NONE; } // *len is changed to the total message size read (header + payload) -enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) +enum ipc_errors usock_recv (const int32_t fd, char **buf, size_t *len) { - assert(buf != NULL); - assert(len != NULL); + T_R ((buf == NULL), IPC_ERROR_USOCK_RECV__NO_BUFFER); + T_R ((len == NULL), IPC_ERROR_USOCK_RECV__NO_LENGTH); int32_t ret_recv = 0; - if (buf == NULL) { - handle_err ("usock_recv", "buf == NULL"); - return IPC_ERROR_USOCK_RECV__NO_BUFFER; - } - - if (len == NULL) { - handle_err ("usock_recv", "len == NULL"); - return IPC_ERROR_USOCK_RECV__NO_LENGTH; - } + if (*len == 0) + *len = IPC_MAX_MESSAGE_SIZE; if (*buf == NULL) { // do not allocate too much memory if (*len > IPC_MAX_MESSAGE_SIZE) { - handle_err ("usock_recv", "len > IPC_MAX_MESSAGE_SIZE"); + LOG_ERROR ("usock_recv: len > IPC_MAX_MESSAGE_SIZE"); *len = IPC_MAX_MESSAGE_SIZE; } - *buf = malloc (*len + IPC_HEADER_SIZE); + SECURE_BUFFER_HEAP_ALLOCATION (*buf,*len + IPC_HEADER_SIZE, , return (IPC_ERROR_NOT_ENOUGH_MEMORY)); } uint32_t msize = 0; @@ -69,99 +55,78 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) do { ret_recv = recv (fd, *buf, *len, 0); +#ifdef IPC_DEBUG + if (ret_recv > 0) { + print_hexa ("msg recv", (uint8_t *)*buf, ret_recv); + fflush(stdout); + } +#endif + if (ret_recv > 0) { if (msize == 0) { memcpy (&msize, *buf + 1, sizeof msize); } - else { - printf ("pas la première boucle, msize == %u\n", msize); - } msize = ntohl (msize); if (msize >= IPC_MAX_MESSAGE_SIZE) { #ifdef IPC_DEBUG - printf ("lecture bien passée : %d octets\n", ret_recv); print_hexa ("msg recv", (uint8_t *)*buf, ret_recv); fflush(stdout); #endif } - assert (msize < IPC_MAX_MESSAGE_SIZE); + 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) + if (*buf != NULL) { free (*buf); + *buf = NULL; + } *len = 0; switch (errno) { // The receive buffer pointer(s) point outside the process's address space. - case EFAULT: - handle_err ("usock_recv", "critical error: use of unallocated memory, quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: EFAULT\n"); - break; + ERROR_CASE (EFAULT, "usock_recv", "critical error: use of unallocated memory, quitting..."); // Invalid argument passed. - case EINVAL: - handle_err ("usock_recv", "critical error: invalid arguments to read(2), quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: EINVAL\n"); - break; + ERROR_CASE (EINVAL, "usock_recv", "critical error: invalid arguments to read(2), quitting..."); // Could not allocate memory for recvmsg(). - case ENOMEM: - handle_err ("usock_recv", "critical error: cannot allocate memory, quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: ENOMEM\n"); - break; + ERROR_CASE (ENOMEM, "usock_recv", "critical error: cannot allocate memory, quitting..."); // The argument sockfd is an invalid descriptor. - case EBADF: - handle_err ("usock_recv", "critical error: invalid descriptor, quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: EBADF\n"); - break; + ERROR_CASE (EBADF, "usock_recv", "critical error: invalid descriptor, quitting..."); // The file descriptor sockfd does not refer to a socket. - case ENOTSOCK: - handle_err ("usock_recv", "critical error: fd is not a socket, quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: ENOTSOCK\n"); - break; + ERROR_CASE (ENOTSOCK, "usock_recv", "critical error: fd is not a socket, quitting..."); // The socket is associated with a connection-oriented protocol and has not // been connected (see connect(2) and accept(2)). - case ENOTCONN: - handle_err ("usock_recv", "critical error: read(2) on a non connected socket, quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: ENOTCONN\n"); - break; + ERROR_CASE (ENOTCONN, "usock_recv", "critical error: read(2) on a non connected socket, quitting..."); - case EAGAIN: - fprintf (stderr, "ERROR WHILE RECEIVING: EAGAIN / EWOULDBLOCK\n"); - break; + ERROR_CASE (EAGAIN, "usock_recv", "ERROR WHILE RECEIVING: EAGAIN / EWOULDBLOCK"); // A remote host refused to allow the network connection // (typically because it is not running the requested service). - case ECONNREFUSED: - fprintf (stderr, "ERROR WHILE RECEIVING: ECONNREFUSED\n"); - break; + ERROR_CASE (ECONNREFUSED, "usock_recv", "ERROR WHILE RECEIVING: ECONNREFUSED"); // The receive was interrupted by delivery of a signal before // any data were available; see signal(7). - case EINTR: - handle_err ("usock_recv", "unsupported error"); - break; + ERROR_CASE (EINTR, "usock_recv", "unsupported error"); default: - printf ("usock_recv unsupported error : %d\n", errno); - handle_err ("usock_recv", "unsupported error"); + LOG_ERROR ("usock_recv: unsupported error"); } - handle_err ("usock_recv", "recv < 0"); - perror("recv"); - + LOG_ERROR ("usock_recv: recv < 0"); return IPC_ERROR_USOCK_RECV; } +#if 0 #if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 - printf ("fragmentation: message size read %u, should read %u\n", msize_read, msize); + LOG_ERROR ("fragmentation: message size read %u, should read %u", msize_read, msize); +#endif #endif } while (msize > msize_read); @@ -173,6 +138,7 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) free (*buf); *buf = NULL; } + *len = 0; return IPC_ERROR_CLOSED_RECIPIENT; } @@ -183,41 +149,24 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) enum ipc_errors usock_connect (int32_t *fd, const char *path) { - assert (fd != NULL); - assert (path != NULL); + T_R ((fd == NULL), IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR); + T_R ((path == NULL), IPC_ERROR_USOCK_CONNECT__EMPTY_PATH); - if (fd == NULL) { - handle_err ("usock_connect", "fd == NULL"); - return IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR; - } - - if (path == NULL) { - handle_err ("usock_connect", "path == NULL"); - return IPC_ERROR_USOCK_CONNECT__EMPTY_PATH; - } + SECURE_DECLARATION (struct sockaddr_un, my_addr); + my_addr.sun_family = AF_UNIX; int32_t sfd; - struct sockaddr_un my_addr; - socklen_t peer_addr_size; + socklen_t peer_addr_size = sizeof(struct sockaddr_un); - sfd = socket (AF_UNIX, SOCK_STREAM, 0); - if (sfd == -1) { - handle_err ("usock_connect", "sfd == -1"); - return IPC_ERROR_USOCK_CONNECT__SOCKET; - } - - // clear structure - memset(&my_addr, 0, sizeof(struct sockaddr_un)); - - my_addr.sun_family = AF_UNIX; + T_PERROR_R (((sfd = socket (AF_UNIX, SOCK_STREAM, 0)) == -1), "socket", IPC_ERROR_USOCK_CONNECT__SOCKET); strncpy(my_addr.sun_path, path, (strlen (path) < PATH_MAX) ? strlen(path) : PATH_MAX); - peer_addr_size = sizeof(struct sockaddr_un); - if(connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) { - handle_err ("usock_connect", "connect == -1"); - perror("connect"); - return IPC_ERROR_USOCK_CONNECT__CONNECT; - } + /** TODO: massive series of tests */ + T_PERROR_F_R ( + /** test */ (connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) + , /** perror */ "connect" + , /** log error */ ("unix socket connection to the path %s not possible", path) + , /** return value */ IPC_ERROR_USOCK_CONNECT__CONNECT); *fd = sfd; @@ -226,52 +175,26 @@ enum ipc_errors usock_connect (int32_t *fd, const char *path) enum ipc_errors usock_init (int32_t *fd, const char *path) { - assert (fd != NULL); - assert (path != NULL); - - if (fd == NULL) { - handle_err ("usock_init", "fd == NULL"); - return IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR; - } - - if (path == NULL) { - handle_err ("usock_init", "path == NULL"); - return IPC_ERROR_USOCK_INIT__EMPTY_PATH; - } - - int32_t sfd; - struct sockaddr_un my_addr; - socklen_t peer_addr_size; - - sfd = socket (AF_UNIX, SOCK_STREAM, 0); - if (sfd == -1) { - handle_err ("usock_init", "sfd == -1"); - return IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR; - } - - // clear structure - memset(&my_addr, 0, sizeof(struct sockaddr_un)); + T_R ((fd == NULL), IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR); + T_R ((path == NULL), IPC_ERROR_USOCK_INIT__EMPTY_PATH); + SECURE_DECLARATION (struct sockaddr_un, my_addr); my_addr.sun_family = AF_UNIX; strncpy(my_addr.sun_path, path, strlen (path)); + int32_t sfd; + socklen_t peer_addr_size; + + T_PERROR_R (((sfd = socket (AF_UNIX, SOCK_STREAM, 0)) == -1), "socket", IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR); + // delete the unix socket if already created // ignore otherwise usock_remove (path); peer_addr_size = sizeof(struct sockaddr_un); - if (bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) { - handle_err ("usock_init", "bind == -1"); - perror("bind"); - return IPC_ERROR_USOCK_INIT__BIND; - } - - if (listen (sfd, LISTEN_BACKLOG) == -1) { - handle_err ("usock_init", "listen == -1"); - perror("listen"); - return IPC_ERROR_USOCK_INIT__LISTEN; - } + T_PERROR_R ((bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1), "bind", IPC_ERROR_USOCK_INIT__BIND); + T_PERROR_R ((listen (sfd, LISTEN_BACKLOG) == -1), "listen", IPC_ERROR_USOCK_INIT__LISTEN); *fd = sfd; @@ -280,54 +203,29 @@ enum ipc_errors usock_init (int32_t *fd, const char *path) enum ipc_errors usock_accept (int32_t fd, int32_t *pfd) { - assert (pfd != NULL); + T_R ((pfd == NULL), IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR); - if (pfd == NULL) { - handle_err ("usock_accept", "pfd == NULL"); - return IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR; - } - - struct sockaddr_un peer_addr; - memset (&peer_addr, 0, sizeof (struct sockaddr_un)); + SECURE_DECLARATION (struct sockaddr_un, peer_addr); socklen_t peer_addr_size = 0; - *pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size); - if (*pfd < 0) { - handle_err ("usock_accept", "accept < 0"); - perror("listen"); - return IPC_ERROR_USOCK_ACCEPT; - } + T_PERROR_R (((*pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size)) < 0), "accept", IPC_ERROR_USOCK_ACCEPT); return IPC_ERROR_NONE; } enum ipc_errors usock_close (int32_t fd) { - int32_t ret = 0; - - ret = close (fd); - if (ret < 0) { - handle_err ("usock_close", "close ret < 0"); - perror ("closing"); - return IPC_ERROR_USOCK_CLOSE; - } + T_PERROR_R ((close (fd) < 0), "close", IPC_ERROR_USOCK_CLOSE); return IPC_ERROR_NONE; } enum ipc_errors usock_remove (const char *path) { - struct stat file_state; - memset (&file_state, 0, sizeof (struct stat)); + SECURE_DECLARATION(struct stat, file_state); // if file exists, remove it - int ret = stat (path, &file_state); - if (ret == 0) { - ret = unlink (path); - if (ret != 0) { - return IPC_ERROR_USOCK_REMOVE__UNLINK; - } - return IPC_ERROR_NONE; - } + T_R ((stat (path, &file_state) != 0), IPC_ERROR_USOCK_REMOVE__NO_FILE); + T_R ((unlink (path) != 0), IPC_ERROR_USOCK_REMOVE__UNLINK); - return IPC_ERROR_USOCK_REMOVE__NO_FILE; + return IPC_ERROR_NONE; } diff --git a/src/usocket.h b/src/usocket.h index 79bb3c2..df06027 100644 --- a/src/usocket.h +++ b/src/usocket.h @@ -7,12 +7,12 @@ // input: len = max buf size // output: *sent = nb received bytes -enum ipc_errors usock_send (const int32_t fd, const char *buf, ssize_t len, ssize_t *sent); +enum ipc_errors usock_send (const int32_t fd, const char *buf, size_t len, size_t *sent); // allocation of *len bytes on *buf == NULL // // output: *len = nb sent bytes -enum ipc_errors usock_recv (int32_t fd, char **buf, ssize_t *len); +enum ipc_errors usock_recv (int32_t fd, char **buf, size_t *len); enum ipc_errors usock_close (int32_t fd); diff --git a/src/utils.c b/src/utils.c index d6c5f37..bd4d2fe 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,22 +1,36 @@ #include "utils.h" +#include "ipc.h" void print_hexa (const char *prefix, uint8_t *payload, size_t size) { - if (! payload) + if (payload == NULL) return ; + SECURE_BUFFER_DECLARATION (char, buffer, BUFSIZ); + + char *cur = buffer, * const end = buffer + sizeof buffer; + size_t i; - for(i = 0; i < size; i++) - { - if(! (i % 4)) - printf("\n%s (%ld) ", prefix, size); - printf("%2x ", payload[i]); + size_t linenum = 0; + for(i = 0; i < size; i++) { + if (i == 0) { + cur += snprintf(cur, end-cur, "\033[32m[%2ld/%2ld]\033[00m \033[36m%s\033[00m (%ld) ", linenum +1, (size / 16) +1, prefix, size); + linenum ++; + } + else if(! (i % 16)) { + LOG_DEBUG ("%s", buffer); + memset (buffer, 0, BUFSIZ); + cur = buffer; + cur += snprintf(cur, end-cur, "\033[32m[%2ld/%2ld]\033[00m \033[36m%s\033[00m (%ld) ", linenum +1, (size / 16) +1, prefix, size); + linenum ++; + } + else if (! (i % 4)) { + cur += snprintf(cur, end-cur, " "); + } + cur += snprintf(cur, end-cur, "%2x ", payload[i]); } - printf("\n"); -} - -void mprint_hexa (char *prefix, uint8_t *buf, size_t length) -{ - print_hexa (prefix, buf, length); + if ((i % 16)) { + LOG_DEBUG ("%s", buffer); + } } diff --git a/src/utils.h b/src/utils.h index 352b78f..6d3c0e3 100644 --- a/src/utils.h +++ b/src/utils.h @@ -8,6 +8,5 @@ #include void print_hexa (const char *prefix, uint8_t *payload, size_t size); -void mprint_hexa (char *prefix, uint8_t *buf, size_t length); #endif diff --git a/tests/build.sh b/tests/build.sh new file mode 100755 index 0000000..72b2e2f --- /dev/null +++ b/tests/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +nontapmsg() { + echo $* +} + +for i in *.c +do + f=`echo $i | sed "s/.c$//"` + nontapmsg "compiling $f" + gcc $f.c -Wall -Wextra -Wno-unused-parameter -g -o $f.bin -I../src -L../ -lipc +done diff --git a/tests/func_01_connection_establishment.c b/tests/func_01_connection_establishment.c new file mode 100644 index 0000000..21730e6 --- /dev/null +++ b/tests/func_01_connection_establishment.c @@ -0,0 +1,31 @@ +#include "../src/ipc.h" + +#include +#include +#include + +#define SERVICE_NAME "pong" + +int main(int argc, char * argv[], char **env) +{ + enum ipc_errors ret; + SECURE_DECLARATION(struct ipc_connection_info,service); + SECURE_DECLARATION(struct ipc_event, event); + + ret = ipc_connection (env, &service, SERVICE_NAME); + if (ret != IPC_ERROR_NONE) { + return EXIT_FAILURE; + } + + // ret = ipc_wait_event (services, struct ipc_event *event); + // if (ret != IPC_ERROR_NONE) { + // return EXIT_FAILURE; + // } + + ret = ipc_close (&service); + if (ret != IPC_ERROR_NONE) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/tests/func_01_connection_establishmentd.c b/tests/func_01_connection_establishmentd.c new file mode 100644 index 0000000..0968964 --- /dev/null +++ b/tests/func_01_connection_establishmentd.c @@ -0,0 +1,56 @@ +#include "../src/ipc.h" + +#include +#include +#include + +#define SERVICE_NAME "pong" + +int main(int argc, char * argv[], char **env) +{ + enum ipc_errors ret; + SECURE_DECLARATION(struct ipc_connection_info,srv); + + printf ("func 01 - server init...\n"); + ret = ipc_server_init (env, &srv, SERVICE_NAME); + if (ret != IPC_ERROR_NONE) { + return EXIT_FAILURE; + } + printf ("func 01 - 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 + ret = ipc_wait_event (&clients, &srv, &event); + + switch (event.type) { + case IPC_EVENT_TYPE_CONNECTION : + { + printf ("ok - connection establishment\n"); + break; + } + case IPC_EVENT_TYPE_NOT_SET : + case IPC_EVENT_TYPE_ERROR : + case IPC_EVENT_TYPE_EXTRA_SOCKET : + case IPC_EVENT_TYPE_DISCONNECTION : + case IPC_EVENT_TYPE_MESSAGE : + default : + printf ("not ok - should not happen\n"); + exit (EXIT_FAILURE); + break; + } + + printf ("func 01 - closing clients...\n"); + ipc_connections_free (&clients); + printf ("func 01 - closing server...\n"); + ret = ipc_server_close(&srv); + if (ret != IPC_ERROR_NONE) + { + const char * error_explanation = ipc_errors_get (ret); + printf ("ipc_server_close: %s\n", error_explanation); + } + + return EXIT_SUCCESS; +} diff --git a/tests/func_02_pong.c b/tests/func_02_pong.c new file mode 100644 index 0000000..96c5712 --- /dev/null +++ b/tests/func_02_pong.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include + +#include "../src/ipc.h" + +#define MSG "coucou" +#define SERVICE_NAME "pong" + +#define PRINTERR(ret,msg) {\ + const char * err = ipc_errors_get (ret);\ + fprintf(stderr, "error while %s: %s\n", msg, err);\ +} + +void non_interactive (char *env[]) +{ + enum ipc_errors ret; + struct ipc_message m; + memset (&m, 0, sizeof (struct ipc_message)); + SECURE_DECLARATION(struct ipc_connection_info, srv); + + // init service + ret = ipc_connection (env, &srv, SERVICE_NAME); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret, "application connection"); + exit (EXIT_FAILURE); + } + + printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen(MSG) +1, (int) strlen(MSG), MSG); + ret = ipc_message_format_data (&m, /* type */ 'a', MSG, (ssize_t) strlen(MSG) +1); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret, "message format data"); + exit (EXIT_FAILURE); + } + + // printf ("msg to send in the client: "); + // ipc_message_print (&m); + ret = ipc_write (&srv, &m); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret, "application write"); + exit (EXIT_FAILURE); + } + ipc_message_empty (&m); + + ret = ipc_read (&srv, &m); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret, "application read"); + exit (EXIT_FAILURE); + } + + printf ("msg recv: %s\n", m.payload); + ipc_message_empty (&m); + + ret = ipc_close (&srv); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret, "application close"); + exit (EXIT_FAILURE); + } +} + +void interactive (char *env[]) +{ + enum ipc_errors ret; + SECURE_DECLARATION(struct ipc_connection_info, srv); + + // index and version should be filled + srv.index = 0; + srv.version = 0; + + // init service + ret = ipc_connection (env, &srv, SERVICE_NAME); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret, "application connection"); + exit (EXIT_FAILURE); + } + + SECURE_DECLARATION(struct ipc_event, event); + SECURE_DECLARATION(struct ipc_connection_infos, services); + + ipc_add (&services, &srv); + + while (1) { + printf ("msg to send: "); + fflush (stdout); + ret = ipc_wait_event (&services, NULL, &event); + + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret, "application peek event"); + exit (EXIT_FAILURE); + } + + switch (event.type) { + case IPC_EVENT_TYPE_EXTRA_SOCKET: + { + struct ipc_message *m = event.m; + if ( m->length == 0 || strncmp (m->payload, "exit", 4) == 0) { + + ipc_message_empty (m); + free (m); + + ipc_connections_free (&services); + + ret = ipc_close (&srv); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret, "application close"); + exit (EXIT_FAILURE); + } + + exit (EXIT_SUCCESS); + } + + ret = ipc_write (&srv, m); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret, "application write"); + exit (EXIT_FAILURE); + } + } + break; + case IPC_EVENT_TYPE_MESSAGE: + { + struct ipc_message *m = event.m; + printf ("msg recv: %.*s", m->length, m->payload); + }; + break; + case IPC_EVENT_TYPE_DISCONNECTION: + case IPC_EVENT_TYPE_NOT_SET: + case IPC_EVENT_TYPE_CONNECTION: + case IPC_EVENT_TYPE_ERROR: + default : + fprintf (stderr, "should not happen, event type %d\n", event.type); + } + } +} + +int main (int argc, char *argv[], char *env[]) +{ + argc = argc; // warnings + argv = argv; // warnings + + if (argc == 1) + non_interactive (env); + else + interactive (env); + + return EXIT_SUCCESS; +} diff --git a/tests/func_02_pongd.c b/tests/func_02_pongd.c new file mode 100644 index 0000000..9252258 --- /dev/null +++ b/tests/func_02_pongd.c @@ -0,0 +1,163 @@ +#include "../src/ipc.h" +#include + +#include +#include +#include + +#define PONGD_SERVICE_NAME "pong" + +#define PRINTERR(ret,msg) {\ + const char * err = ipc_errors_get (ret);\ + fprintf(stderr, "error while %s: %s\n", msg, err);\ +} + +int cpt = 0; + +struct ipc_connection_info *srv = 0; +struct ipc_connection_infos *clients; + + +void main_loop () +{ + enum ipc_errors ret = 0; + + clients = malloc (sizeof (struct ipc_connection_infos)); + memset(clients, 0, sizeof(struct ipc_connection_infos)); + + SECURE_DECLARATION(struct ipc_event,event); + + 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); + if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) { + PRINTERR(ret,"service poll event"); + + // the application will shut down, and close the service + ret = ipc_server_close (srv); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret,"server close"); + } + exit (EXIT_FAILURE); + } + + switch (event.type) { + 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); + }; + break; + case IPC_EVENT_TYPE_DISCONNECTION: + { + cpt--; + printf ("disconnection: %d clients remaining\n", cpt); + + // free the ipc_connection_info structure + free (event.origin); + }; + 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); + } + + ret = ipc_write (event.origin, m); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret,"server write"); + } + }; + break; + case IPC_EVENT_TYPE_ERROR: + { + fprintf (stderr, "a problem happened with client %d\n" + , ((struct ipc_connection_info*) event.origin)->fd); + }; + break; + default : + { + fprintf (stderr, "there must be a problem, event not set\n"); + }; + } + } + + // should never go there + exit (1); +} + + +void exit_program(int signal) +{ + printf("Quitting, signal: %d\n", signal); + + // free remaining clients + for (int 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 + enum ipc_errors ret = ipc_server_close (srv); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret,"server close"); + } + free (srv); + + exit(EXIT_SUCCESS); +} + +/* + * service ping-pong: send back everything sent by the clients + * stop the program on SIG{TERM,INT,ALRM,USR{1,2},HUP} signals + */ + +int main(int argc, char * argv[], char **env) +{ + argc = argc; // warnings + argv = argv; // warnings + + printf ("pid = %d\n", getpid ()); + + srv = malloc (sizeof (struct ipc_connection_info)); + if (srv == NULL) { + exit (1); + } + memset (srv, 0, sizeof (struct ipc_connection_info)); + srv->index = 0; + srv->version = 0; + + // unlink("/tmp/ipc/pongd-0-0"); + + enum ipc_errors ret = ipc_server_init (env, srv, PONGD_SERVICE_NAME); + if (ret != IPC_ERROR_NONE) { + PRINTERR(ret,"server init"); + return EXIT_FAILURE; + } + printf ("Listening on %s.\n", srv->spath); + + printf("MAIN: server created\n" ); + + signal (SIGHUP, exit_program); + signal (SIGALRM, exit_program); + signal (SIGUSR1, exit_program); + signal (SIGUSR2, exit_program); + signal (SIGTERM, exit_program); + signal (SIGINT, exit_program); + + // the service will loop until the end of time, or a signal + main_loop (); + + // main_loop should not return + return EXIT_FAILURE; +} diff --git a/tests/func_03_multiple-communications-client.c b/tests/func_03_multiple-communications-client.c new file mode 100644 index 0000000..cfbff4e --- /dev/null +++ b/tests/func_03_multiple-communications-client.c @@ -0,0 +1,97 @@ +#include "../src/ipc.h" + +#include +#include +#include + +#define SERVICE_NAME "pong" +#define SECURE_MALLOC(p, s, wat) p = malloc (s); if (p == NULL) { wat; } + +void connection (char **env, struct ipc_connection_info *ci) +{ + enum ipc_errors ret = ipc_connection (env, ci, SERVICE_NAME); + if (ret != IPC_ERROR_NONE) { + fprintf (stderr, "cannot connect to the server\n"); + exit(EXIT_FAILURE); + } +} + +void closing (struct ipc_connection_info *ci) +{ + enum ipc_errors ret = ipc_close (ci); + if (ret != IPC_ERROR_NONE) { + fprintf (stderr, "cannot close server\n"); + exit(EXIT_FAILURE); + } +} + +// test the behavior of the server when the client never read its messages + +void send_message (struct ipc_connection_info *ci) +{ + SECURE_DECLARATION (struct ipc_message, m); + SECURE_MALLOC (m.payload, 5, exit(EXIT_FAILURE)); + memcpy (m.payload, "salut", 5); + m.type = MSG_TYPE_DATA; + m.user_type = 42; + m.length = 5; + + ipc_write (ci, &m); + + ipc_message_empty (&m); +} + + +void read_message (struct ipc_connection_info *ci) +{ +#if 0 + SECURE_DECLARATION(struct ipc_event, event); + SECURE_DECLARATION(struct ipc_connection_infos, clients); + + ipc_add (&clients, ci); + + ipc_wait_event (&clients, NULL, &event); + + switch (event.type) { + case IPC_EVENT_TYPE_MESSAGE : { + printf ("received message: %*.s\n", m.length, ((struct ipc_message*) event.m)->payload); + } + break; + case IPC_EVENT_TYPE_CONNECTION : + case IPC_EVENT_TYPE_DISCONNECTION : + case IPC_EVENT_TYPE_NOT_SET : + case IPC_EVENT_TYPE_ERROR : + case IPC_EVENT_TYPE_EXTRA_SOCKET : + default : + printf ("not ok - should not happen\n"); + exit (EXIT_FAILURE); + break; + } + + ipc_connections_free (&clients); +#else + SECURE_DECLARATION (struct ipc_message, m); + + ipc_read (ci, &m); + printf ("received message: %*.s\n", m.length, m.payload); + free (m.payload); +#endif +} + +int main(int argc, char * argv[], char **env) +{ + SECURE_DECLARATION(struct ipc_connection_info,srv1); + SECURE_DECLARATION(struct ipc_connection_info,srv2); + SECURE_DECLARATION(struct ipc_event, event); + + connection (env, &srv1); + connection (env, &srv2); + send_message (&srv1); + read_message (&srv1); + closing (&srv1); + send_message (&srv2); + read_message (&srv2); + closing (&srv2); + + return EXIT_SUCCESS; +} diff --git a/tests/func_03_multiple-communications-server.c b/tests/func_03_multiple-communications-server.c new file mode 100644 index 0000000..56dabe5 --- /dev/null +++ b/tests/func_03_multiple-communications-server.c @@ -0,0 +1,84 @@ +#include "../src/ipc.h" + +#include +#include +#include +#include + +#define SERVICE_NAME "pong" + +int main_loop(int argc, char * argv[], char **env) +{ + enum ipc_errors ret; + SECURE_DECLARATION (struct ipc_connection_info, srv); + + printf ("func 03 - server init...\n"); + ret = ipc_server_init (env, &srv, SERVICE_NAME); + if (ret != IPC_ERROR_NONE) { + exit(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) { + ret = ipc_wait_event (&clients, &srv, &event); + + switch (event.type) { + case IPC_EVENT_TYPE_CONNECTION : { + printf ("connection establishment: %d \n", event.origin->fd); + } + break; + case IPC_EVENT_TYPE_DISCONNECTION : { + printf ("client %d disconnecting\n", event.origin->fd); + }; + 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); + } + break; + case IPC_EVENT_TYPE_NOT_SET : + case IPC_EVENT_TYPE_ERROR : + case IPC_EVENT_TYPE_EXTRA_SOCKET : + default : + printf ("not ok - should not happen\n"); + exit (EXIT_FAILURE); + break; + } + } + + printf ("func 03 - closing clients...\n"); + ipc_connections_free (&clients); + printf ("func 03 - closing server...\n"); + ret = ipc_server_close(&srv); + if (ret != IPC_ERROR_NONE) + { + const char * error_explanation = ipc_errors_get (ret); + printf ("ipc_server_close: %s\n", error_explanation); + } + + return 0; +} + +void exit_program(int signal) +{ + printf("Quitting, signal: %d\n", signal); + exit(EXIT_SUCCESS); +} + + +int main(int argc, char * argv[], char **env) +{ + signal (SIGHUP, exit_program); + signal (SIGALRM, exit_program); + signal (SIGUSR1, exit_program); + signal (SIGUSR2, exit_program); + signal (SIGTERM, exit_program); + signal (SIGINT, exit_program); + main_loop (argc, argv, env); + return EXIT_SUCCESS; +} diff --git a/tests/func_04_empty_message.c b/tests/func_04_empty_message.c new file mode 100644 index 0000000..cd0d55c --- /dev/null +++ b/tests/func_04_empty_message.c @@ -0,0 +1,72 @@ +#include "../src/ipc.h" + +#include +#include +#include + +#define SERVICE_NAME "pong" +#define SECURE_MALLOC(p, s, wat) p = malloc (s); if (p == NULL) { wat; } + +void connection (char **env, struct ipc_connection_info *ci) +{ + enum ipc_errors ret = ipc_connection (env, ci, SERVICE_NAME); + if (ret != IPC_ERROR_NONE) { + fprintf (stderr, "cannot connect to the server\n"); + exit(EXIT_FAILURE); + } +} + +void closing (struct ipc_connection_info *ci) +{ + enum ipc_errors ret = ipc_close (ci); + if (ret != IPC_ERROR_NONE) { + fprintf (stderr, "cannot close server\n"); + exit(EXIT_FAILURE); + } +} + +// test the behavior of the server when the client never read its messages + +void send_message (struct ipc_connection_info *ci) +{ + SECURE_DECLARATION (struct ipc_message, m); + SECURE_MALLOC (m.payload, 1, exit(EXIT_FAILURE)); + memcpy (m.payload, "", 0); + m.type = MSG_TYPE_DATA; + m.user_type = 42; + m.length = 0; + + ipc_write (ci, &m); + + ipc_message_empty (&m); +} + + +void read_message (struct ipc_connection_info *ci) +{ + SECURE_DECLARATION (struct ipc_message, m); + + ipc_read (ci, &m); + if (m.length > 0) { + printf ("received message: %*.s\n", m.length, m.payload); + } + else { + printf ("received empty message as intended : %d bytes\n", m.length); + if (m.payload == NULL) { + printf ("message payload is NULL\n"); + } + } + free (m.payload); +} + +int main(int argc, char * argv[], char **env) +{ + SECURE_DECLARATION(struct ipc_connection_info,srv1); + + connection (env, &srv1); + send_message (&srv1); + read_message (&srv1); + closing (&srv1); + + return EXIT_SUCCESS; +} diff --git a/tests/unit_01_service-path.c b/tests/unit_01_service-path.c new file mode 100644 index 0000000..cf2d531 --- /dev/null +++ b/tests/unit_01_service-path.c @@ -0,0 +1,34 @@ +#include "../src/ipc.h" + +#include +#include +#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) { + 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); + + // printf ("servicename: %s, index: %d, version: %d\n", sname, index, version); + printf ("%s\n", path); + + return EXIT_SUCCESS; +} diff --git a/tests/unit_02_usock-remove.c b/tests/unit_02_usock-remove.c new file mode 100644 index 0000000..168d91f --- /dev/null +++ b/tests/unit_02_usock-remove.c @@ -0,0 +1,26 @@ +#include "../src/ipc.h" +#include "../src/usocket.h" + +#include +#include +#include + +#define FILE_TO_REMOVE "/tmp/FILE_TO_REMOVE" + +int main(int argc, char * argv[]) +{ + char * ftr = FILE_TO_REMOVE; + + if (argc == 2) { + ftr = argv[1]; + } + else if (argc > 2) { + fprintf (stderr, "usage: %s [file-to-remove]\n", argv[0]); + return EXIT_FAILURE; + } + + enum ipc_errors ret = usock_remove (ftr); + if (ret == IPC_ERROR_NONE) + return 0; + return 1; +} diff --git a/tests/unit_03_connection-add-remove.c b/tests/unit_03_connection-add-remove.c new file mode 100644 index 0000000..17968aa --- /dev/null +++ b/tests/unit_03_connection-add-remove.c @@ -0,0 +1,15 @@ +#include "../src/ipc.h" + +#include +#include +#include + +/*** + * TODO + */ + +// int main(int argc, char * argv[]) +int main(void) +{ + return EXIT_SUCCESS; +}