diff --git a/Makefile b/Makefile index 6f2659e..859cdf6 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,8 @@ MANDIR := $(SHAREDIR)/man CC := cc AR := ar RANLIB := ranlib -CFLAGS := -LDFLAGS := +CFLAGS := +LDFLAGS := Q := @ @@ -28,7 +28,7 @@ libipc.clean: libipc.so.clean libipc.a.clean libipc.uninstall: libipc.so.uninstall libipc.a.uninstall src/ipc.h.install: src/ipc.h - @echo ' IN > $(INCLUDEDIR)/ipc.h' + @echo ' IN > $(INCLUDEDIR)/ipc.h' $(Q)mkdir -p '$(DESTDIR)$(INCLUDEDIR)' $(Q)install -m0644 src/ipc.h $(DESTDIR)$(INCLUDEDIR)/ipc.h @@ -36,169 +36,169 @@ src/ipc.h.clean: src/ipc.h $(Q): src/ipc.h.uninstall: - @echo ' RM > $(INCLUDEDIR)/ipc.h' + @echo ' RM > $(INCLUDEDIR)/ipc.h' $(Q)rm -f '$(DESTDIR)$(INCLUDEDIR)/ipc.h' man/libipc.7: man/libipc.7.md - @echo ' MAN > man/libipc.7' + @echo ' MAN > man/libipc.7' $(Q)pandoc -s --from markdown --to man 'man/libipc.7.md' -o 'man/libipc.7' man/libipc.7.install: man/libipc.7 - @echo ' IN > $(MANDIR)/man7/libipc.7' + @echo ' IN > $(MANDIR)/man7/libipc.7' $(Q)mkdir -p '$(DESTDIR)$(MANDIR)/man7' $(Q)install -m0644 man/libipc.7 $(DESTDIR)$(MANDIR)/man7/libipc.7 man/libipc.7.clean: - @echo ' RM > man/libipc.7' + @echo ' RM > man/libipc.7' $(Q)rm -f man/libipc.7 man/libipc.7.uninstall: - @echo ' RM > $(MANDIR)/man7/libipc.7' + @echo ' RM > $(MANDIR)/man7/libipc.7' $(Q)rm -f '$(DESTDIR)$(MANDIR)/man7/libipc.7' -libipc.so: src/client.o src/communication.o src/logger.o src/message.o src/usocket.o src/utils.o - @echo ' LD > libipc.so' - $(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/client.o src/communication.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/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 libipc.so.install: libipc.so - @echo ' IN > $(LIBDIR)/libipc.so.0.1.0' + @echo ' IN > $(LIBDIR)/libipc.so.0.1.0' $(Q)mkdir -p '$(DESTDIR)$(LIBDIR)' $(Q)install -m0755 libipc.so $(DESTDIR)$(LIBDIR)/libipc.so.0.1.0 - @echo ' LN > $(LIBDIR)/libipc.so.0.1' + @echo ' LN > $(LIBDIR)/libipc.so.0.1' $(Q)ln -sf '$(LIBDIR)/libipc.so.0.1.0' '$(DESTDIR)/$(LIBDIR)/libipc.so.0.1' - @echo ' LN > $(LIBDIR)/libipc.so.0' + @echo ' LN > $(LIBDIR)/libipc.so.0' $(Q)ln -sf '$(LIBDIR)/libipc.so.0.1.0' '$(DESTDIR)/$(LIBDIR)/libipc.so.0' - @echo ' LN > $(LIBDIR)/libipc.so' + @echo ' LN > $(LIBDIR)/libipc.so' $(Q)ln -sf '$(LIBDIR)/libipc.so.0.1.0' '$(DESTDIR)/$(LIBDIR)/libipc.so' libipc.so.clean: - @echo ' RM > libipc.so' + @echo ' RM > libipc.so' $(Q)rm -f libipc.so libipc.so.uninstall: - @echo ' RM > $(LIBDIR)/libipc.so.0.1.0' + @echo ' RM > $(LIBDIR)/libipc.so.0.1.0' $(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so.0.1.0' - @echo ' RM > $(LIBDIR)/libipc.so.0.1' + @echo ' RM > $(LIBDIR)/libipc.so.0.1' $(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so.0.1' - @echo ' RM > $(LIBDIR)/libipc.so.0' + @echo ' RM > $(LIBDIR)/libipc.so.0' $(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so.0' - @echo ' RM > $(LIBDIR)/libipc.so' + @echo ' RM > $(LIBDIR)/libipc.so' $(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so' -libipc.a: src/client.o src/communication.o src/logger.o src/message.o src/usocket.o src/utils.o - @echo ' LD > libipc.a' - $(Q)$(AR) rc 'libipc.a' src/client.o src/communication.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/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 libipc.a.install: libipc.a - @echo ' IN > $(LIBDIR)/libipc.a' + @echo ' IN > $(LIBDIR)/libipc.a' $(Q)mkdir -p '$(DESTDIR)$(LIBDIR)' $(Q)install -m0755 libipc.a $(DESTDIR)$(LIBDIR)/libipc.a libipc.a.clean: - @echo ' RM > libipc.a' + @echo ' RM > libipc.a' $(Q)rm -f libipc.a libipc.a.uninstall: - @echo ' RM > $(LIBDIR)/libipc.a' + @echo ' RM > $(LIBDIR)/libipc.a' $(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.a' -src/client.o: src/client.c src/client.h - @echo ' CC > src/client.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/client.c -fPIC -o src/client.o - -src/client.o.install: - -src/client.o.clean: - @echo ' RM > src/client.o' - $(Q)rm -f src/client.o - -src/client.o.uninstall: - -src/communication.o: src/communication.c src/communication.h src/utils.h src/error.h src/event.h - @echo ' CC > src/communication.o' +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 src/communication.o.install: src/communication.o.clean: - @echo ' RM > src/communication.o' + @echo ' RM > src/communication.o' $(Q)rm -f src/communication.o src/communication.o.uninstall: +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 + +src/error.o.install: + +src/error.o.clean: + @echo ' RM > src/error.o' + $(Q)rm -f src/error.o + +src/error.o.uninstall: + src/logger.o: src/logger.c src/logger.h - @echo ' CC > src/logger.o' + @echo ' CC > src/logger.o' $(Q)$(CC) $(CFLAGS) -fPIC -c src/logger.c -fPIC -o src/logger.o src/logger.o.install: src/logger.o.clean: - @echo ' RM > src/logger.o' + @echo ' RM > src/logger.o' $(Q)rm -f src/logger.o src/logger.o.uninstall: -src/message.o: src/message.c src/message.h src/error.h src/usocket.h - @echo ' CC > src/message.o' +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 src/message.o.install: src/message.o.clean: - @echo ' RM > src/message.o' + @echo ' RM > src/message.o' $(Q)rm -f src/message.o src/message.o.uninstall: -src/usocket.o: src/usocket.c src/usocket.h src/utils.h src/error.h - @echo ' CC > src/usocket.o' +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 src/usocket.o.install: src/usocket.o.clean: - @echo ' RM > src/usocket.o' + @echo ' RM > src/usocket.o' $(Q)rm -f src/usocket.o src/usocket.o.uninstall: src/utils.o: src/utils.c src/utils.h - @echo ' CC > src/utils.o' + @echo ' CC > src/utils.o' $(Q)$(CC) $(CFLAGS) -fPIC -c src/utils.c -fPIC -o src/utils.o src/utils.o.install: src/utils.o.clean: - @echo ' RM > src/utils.o' + @echo ' RM > src/utils.o' $(Q)rm -f src/utils.o src/utils.o.uninstall: $(DESTDIR)$(PREFIX): - @echo ' DIR > $(PREFIX)' + @echo ' DIR > $(PREFIX)' $(Q)mkdir -p $(DESTDIR)$(PREFIX) $(DESTDIR)$(BINDIR): - @echo ' DIR > $(BINDIR)' + @echo ' DIR > $(BINDIR)' $(Q)mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(LIBDIR): - @echo ' DIR > $(LIBDIR)' + @echo ' DIR > $(LIBDIR)' $(Q)mkdir -p $(DESTDIR)$(LIBDIR) $(DESTDIR)$(SHAREDIR): - @echo ' DIR > $(SHAREDIR)' + @echo ' DIR > $(SHAREDIR)' $(Q)mkdir -p $(DESTDIR)$(SHAREDIR) $(DESTDIR)$(INCLUDEDIR): - @echo ' DIR > $(INCLUDEDIR)' + @echo ' DIR > $(INCLUDEDIR)' $(Q)mkdir -p $(DESTDIR)$(INCLUDEDIR) $(DESTDIR)$(MANDIR): - @echo ' DIR > $(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/client.o.install src/communication.o.install src/logger.o.install src/message.o.install src/usocket.o.install src/utils.o.install src/client.o.install src/communication.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/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 @: subdirs.install: -uninstall: subdirs.uninstall libipc.uninstall src/ipc.h.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/client.o.uninstall src/communication.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/client.o.uninstall src/communication.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/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 @: subdirs.uninstall: @@ -208,7 +208,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/client.o.clean src/communication.o.clean src/logger.o.clean src/message.o.clean src/usocket.o.clean src/utils.o.clean src/client.o.clean src/communication.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/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 distclean: clean @@ -221,21 +221,18 @@ distdir: dist-gz: $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)-$(VERSION).tar.gz: distdir - @echo ' TAR > $(PACKAGE)-$(VERSION).tar.gz' + @echo ' TAR > $(PACKAGE)-$(VERSION).tar.gz' $(Q)tar czf $(PACKAGE)-$(VERSION).tar.gz \ $(PACKAGE)-$(VERSION)/Makefile \ $(PACKAGE)-$(VERSION)/project.zsh \ - $(PACKAGE)-$(VERSION)/src/error.h \ $(PACKAGE)-$(VERSION)/src/ipc.h \ - $(PACKAGE)-$(VERSION)/src/event.h \ $(PACKAGE)-$(VERSION)/man/libipc.7.md \ - $(PACKAGE)-$(VERSION)/src/client.c \ $(PACKAGE)-$(VERSION)/src/communication.c \ + $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/logger.c \ $(PACKAGE)-$(VERSION)/src/message.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ - $(PACKAGE)-$(VERSION)/src/client.h \ $(PACKAGE)-$(VERSION)/src/communication.h \ $(PACKAGE)-$(VERSION)/src/logger.h \ $(PACKAGE)-$(VERSION)/src/message.h \ @@ -244,21 +241,18 @@ $(PACKAGE)-$(VERSION).tar.gz: distdir dist-xz: $(PACKAGE)-$(VERSION).tar.xz $(PACKAGE)-$(VERSION).tar.xz: distdir - @echo ' TAR > $(PACKAGE)-$(VERSION).tar.xz' + @echo ' TAR > $(PACKAGE)-$(VERSION).tar.xz' $(Q)tar cJf $(PACKAGE)-$(VERSION).tar.xz \ $(PACKAGE)-$(VERSION)/Makefile \ $(PACKAGE)-$(VERSION)/project.zsh \ - $(PACKAGE)-$(VERSION)/src/error.h \ $(PACKAGE)-$(VERSION)/src/ipc.h \ - $(PACKAGE)-$(VERSION)/src/event.h \ $(PACKAGE)-$(VERSION)/man/libipc.7.md \ - $(PACKAGE)-$(VERSION)/src/client.c \ $(PACKAGE)-$(VERSION)/src/communication.c \ + $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/logger.c \ $(PACKAGE)-$(VERSION)/src/message.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ - $(PACKAGE)-$(VERSION)/src/client.h \ $(PACKAGE)-$(VERSION)/src/communication.h \ $(PACKAGE)-$(VERSION)/src/logger.h \ $(PACKAGE)-$(VERSION)/src/message.h \ @@ -267,21 +261,18 @@ $(PACKAGE)-$(VERSION).tar.xz: distdir dist-bz2: $(PACKAGE)-$(VERSION).tar.bz2 $(PACKAGE)-$(VERSION).tar.bz2: distdir - @echo ' TAR > $(PACKAGE)-$(VERSION).tar.bz2' + @echo ' TAR > $(PACKAGE)-$(VERSION).tar.bz2' $(Q)tar cjf $(PACKAGE)-$(VERSION).tar.bz2 \ $(PACKAGE)-$(VERSION)/Makefile \ $(PACKAGE)-$(VERSION)/project.zsh \ - $(PACKAGE)-$(VERSION)/src/error.h \ $(PACKAGE)-$(VERSION)/src/ipc.h \ - $(PACKAGE)-$(VERSION)/src/event.h \ $(PACKAGE)-$(VERSION)/man/libipc.7.md \ - $(PACKAGE)-$(VERSION)/src/client.c \ $(PACKAGE)-$(VERSION)/src/communication.c \ + $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/logger.c \ $(PACKAGE)-$(VERSION)/src/message.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ - $(PACKAGE)-$(VERSION)/src/client.h \ $(PACKAGE)-$(VERSION)/src/communication.h \ $(PACKAGE)-$(VERSION)/src/logger.h \ $(PACKAGE)-$(VERSION)/src/message.h \ @@ -289,38 +280,38 @@ $(PACKAGE)-$(VERSION).tar.bz2: distdir $(PACKAGE)-$(VERSION)/src/utils.h help: - @echo ' :: ipc-0.1.0' + @echo ' :: ipc-0.1.0' @echo '' - @echo 'Generic targets:' - @echo ' - help  Prints this help message.' - @echo ' - all  Builds all targets.' - @echo ' - dist  Creates tarballs of the files of the project.' - @echo ' - install  Installs the project.' - @echo ' - clean  Removes compiled files.' - @echo ' - uninstall  Deinstalls the project.' + @echo 'Generic targets:' + @echo ' - help Prints this help message.' + @echo ' - all Builds all targets.' + @echo ' - dist Creates tarballs of the files of the project.' + @echo ' - install Installs the project.' + @echo ' - clean Removes compiled files.' + @echo ' - uninstall Deinstalls the project.' @echo '' - @echo 'CLI-modifiable variables:' - @echo ' - CC  ${CC}' - @echo ' - CFLAGS  ${CFLAGS}' - @echo ' - LDFLAGS  ${LDFLAGS}' - @echo ' - DESTDIR  ${DESTDIR}' - @echo ' - PREFIX  ${PREFIX}' - @echo ' - BINDIR  ${BINDIR}' - @echo ' - LIBDIR  ${LIBDIR}' - @echo ' - SHAREDIR  ${SHAREDIR}' - @echo ' - INCLUDEDIR  ${INCLUDEDIR}' - @echo ' - MANDIR  ${MANDIR}' + @echo 'CLI-modifiable variables:' + @echo ' - CC ${CC}' + @echo ' - CFLAGS ${CFLAGS}' + @echo ' - LDFLAGS ${LDFLAGS}' + @echo ' - DESTDIR ${DESTDIR}' + @echo ' - PREFIX ${PREFIX}' + @echo ' - BINDIR ${BINDIR}' + @echo ' - LIBDIR ${LIBDIR}' + @echo ' - SHAREDIR ${SHAREDIR}' + @echo ' - INCLUDEDIR ${INCLUDEDIR}' + @echo ' - MANDIR ${MANDIR}' @echo '' - @echo 'Project targets: ' - @echo ' - libipc  library' - @echo ' - src/ipc.h  header' - @echo ' - man/libipc.7  man' + @echo 'Project targets: ' + @echo ' - libipc library' + @echo ' - src/ipc.h header' + @echo ' - man/libipc.7 man' @echo '' - @echo 'Makefile options:' + @echo 'Makefile options:' @echo ' - gnu: false' - @echo ' - colors: true' + @echo ' - colors: false' @echo '' - @echo 'Rebuild the Makefile with:' - @echo ' zsh ./build.zsh -c' + @echo 'Rebuild the Makefile with:' + @echo ' zsh ./build.zsh' .PHONY: all subdirs clean distclean dist install uninstall help diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..7fca6e9 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,14 @@ +# how to compile + +./build.sh + +# how to launch + + export IPC_RUNDIR=/tmp + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../ + ./pongd + + # in another terminal + export IPC_RUNDIR=/tmp + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../ + ./pong diff --git a/examples/build.sh b/examples/build.sh new file mode 100755 index 0000000..8c14e3e --- /dev/null +++ b/examples/build.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +nontapmsg() { + echo $* +} + +for i in *.c +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 +done diff --git a/examples/pong.c b/examples/pong.c new file mode 100644 index 0000000..676edf6 --- /dev/null +++ b/examples/pong.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include + +#include "../src/ipc.h" + +#define MSG "coucou" +#define SERVICE_NAME "pongd" + +#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[]) +{ + struct ipc_message m; + memset (&m, 0, sizeof (struct ipc_message)); + struct ipc_connection_info srv; + memset (&srv, 0, sizeof (struct ipc_connection_info)); + + // index and version should be filled + srv.index = 0; + srv.version = 0; + + 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); + } + + printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen(MSG) +1, (int) strlen(MSG), MSG); + ret = ipc_message_format_data (&m, 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); + } + 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); + } + + printf ("msg recv: %s\n", 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); + } +} + +void interactive (char *env[]) +{ + enum ipc_errors ret; + struct ipc_connection_info srv; + memset (&srv, 0, sizeof (struct ipc_connection_info)); + + // 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) { + handle_err ("main", "ipc_application_connection < 0"); + PRINTERR(ret, "application connection"); + exit (EXIT_FAILURE); + } + + struct ipc_event event; + memset (&event, 0, sizeof (struct ipc_event)); + + struct ipc_connection_infos services; + memset (&services, 0, sizeof (struct ipc_connection_infos)); + ipc_add (&services, &srv); + + ipc_add_fd (&services, 0); // add STDIN + + while (1) { + printf ("msg to send: "); + fflush (stdout); + ret = ipc_wait_event (&services, NULL, &event); + + if (ret != IPC_ERROR_NONE) { + handle_error("ipc_application_peek_event != 0"); + 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) { + handle_err("main", "application_close < 0"); + PRINTERR(ret, "application close"); + exit (EXIT_FAILURE); + } + + exit (EXIT_SUCCESS); + } + + ret = ipc_write (&srv, m); + if (ret != IPC_ERROR_NONE) { + handle_err("main", "application_write < 0"); + 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/examples/pongd.c b/examples/pongd.c new file mode 100644 index 0000000..24f81c6 --- /dev/null +++ b/examples/pongd.c @@ -0,0 +1,173 @@ +#include "../src/ipc.h" +#include + +#include +#include +#include + +#define PONGD_SERVICE_NAME "pongd" + +#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 = NULL; +struct ipc_connection_infos *clients = NULL; + + +void main_loop () +{ + enum ipc_errors ret = 0; + + clients = malloc (sizeof (struct ipc_connection_infos)); + memset(clients, 0, sizeof(struct ipc_connection_infos)); + + struct ipc_event event; + memset(&event, 0, sizeof (struct ipc_event)); + event.type = IPC_EVENT_TYPE_NOT_SET; + + while(1) { + // ipc_service_poll_event provides one event at a time + // warning: event->m is free'ed if not NULL + printf ("before poll\n"); // TODO remove + ret = ipc_wait_event (clients, srv, &event); + if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) { + handle_error("ipc_service_poll_event != IPC_ERROR_NONE"); + PRINTERR(ret,"service poll event"); + + // the application will shut down, and close the service + ret = ipc_server_close (srv); + if (ret != IPC_ERROR_NONE) { + handle_error("ipc_server_close < 0"); + 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", (event.origin)->fd); + }; + break; + case IPC_EVENT_TYPE_DISCONNECTION: + { + cpt--; + printf ("disconnection: %d clients remaining\n", cpt); + + // free the ipc_client 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) { + handle_err( "handle_new_msg", "server_write < 0"); + PRINTERR(ret,"server write"); + } + }; + break; + case IPC_EVENT_TYPE_ERROR: + { + 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"); + }; + } + } + + // should never go there + exit (EXIT_FAILURE); +} + + +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) { + handle_error("ipc_server_close < 0"); + 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 (EXIT_FAILURE); + } + memset (srv, 0, sizeof (struct ipc_connection_info)); + srv->type = '\0'; + srv->index = 0; + srv->version = 0; + srv->fd = 0; + srv->spath = NULL; + + enum ipc_errors ret = ipc_server_init (env, srv, PONGD_SERVICE_NAME); + if (ret != IPC_ERROR_NONE) { + handle_error("ipc_server_init != 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/man/libipc.7.md b/man/libipc.7.md index b309cc5..136c8eb 100644 --- a/man/libipc.7.md +++ b/man/libipc.7.md @@ -10,18 +10,118 @@ section: 7 libipc - Simple, easy-to-use IPC library -# SYNOPSIS - -**`#include `** - -**`...`** - # DESCRIPTION **libipc** is a library that provides interprocess communication medium between applications. It provides both client and server code. -# USAGE +# SYNOPSIS + +**`#include `** + +## Initialization, exchanges, disconnection + +// server initialization\ +*enum ipc_errors* **ipc_server_init** (*char* \*\*env , *struct ipc_connection_info* \*srv, *const char* \*sname);\ +// connection establishement to a server\ +*enum ipc_errors* **ipc_connection** (*char* \*\*env, *struct ipc_connection_info* \*, *const char* \*);\ + +// closing a server\ +*enum ipc_errors* **ipc_server_close** (*struct ipc_connection_info* \*srv);\ +// closing a connection\ +*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); + +*enum ipc_errors* **ipc_read** (*const struct ipc_connection_info* \*, *struct ipc_message* \*m);\ +*enum ipc_errors* **ipc_write** (*const struct ipc_connection_info* \*, *const struct ipc_message* \*m);\ +*enum ipc_errors* **ipc_wait_event** (*struct ipc_connection_infos* \*clients, *struct ipc_connection_info* \*srv, *struct ipc_event* \*event); + + +// store and remove only pointers on allocated structures\ +*enum ipc_errors* **ipc_add** (*struct ipc_connection_infos* \*cinfos, *struct ipc_connection_info* \*cinfo);\ +*enum ipc_errors* **ipc_del** (*struct ipc_connection_infos* \*cinfos, *struct ipc_connection_info* \*cinfo); + +// add an arbitrary file descriptor to read\ +*enum ipc_errors* **ipc_add_fd** (*struct ipc_connection_infos* \*cinfos, *int* fd); + + +## 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);\ + +*enum ipc_errors* **ipc_message_empty** (*struct ipc_message* \*m); + + +# STRUCTURES + + struct ipc_connection_info { + uint32_t version; + uint32_t index; + int32_t fd; + char type; // may be an arbitrary fd + char *spath; // max size: PATH_MAX, used to store unix socket path + }; + + struct ipc_connection_infos { + struct ipc_connection_info ** cinfos; + int32_t size; + }; + + struct ipc_message { + char type; + uint32_t length; + char *payload; + }; + + struct ipc_event { + enum ipc_event_type type; + void* origin; // currently used as an client or service pointer + void* m; // message pointer + }; + + +# ENUMERATIONS + + enum msg_types { + MSG_TYPE_SERVER_CLOSE = 0 + , MSG_TYPE_ERR + , MSG_TYPE_DATA + } message_types; + +Function **ipc_wait_event** returns an *event type* structure.\ +The event may be a (dis)connection, received data or an error.\ +It also can be *IPC_EVENT_TYPE_EXTRA_SOCKET* since an arbitrary file descriptor can be added to the *ipc_connection_infos* structure with **ipc_add_fd**. + + 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 + }; + + enum ipc_errors { + ... + }; + + +# EXAMPLES + +Examples are available in the */examples* directory. # NOTES @@ -31,5 +131,4 @@ It provides both client and server code. - Documentation is currently limited. - Rerouting IPC connexions through other services (for example, through a network bridge service) is currently not possible. - - Errors management is currently limited, and precise errors cannot be distinguished. diff --git a/project.zsh b/project.zsh index ce4e9ea..ac69258 100644 --- a/project.zsh +++ b/project.zsh @@ -11,5 +11,5 @@ type[src/ipc.h]=header type[man/libipc.7]=man -dist=(Makefile project.zsh src/error.h src/ipc.h src/event.h man/*.md) +dist=(Makefile project.zsh src/ipc.h man/*.md) diff --git a/src/client.c b/src/client.c deleted file mode 100644 index 46cefc4..0000000 --- a/src/client.c +++ /dev/null @@ -1,108 +0,0 @@ -#include "client.h" -#include -#include -#include - -#include - -struct ipc_client * ipc_server_client_copy (const struct ipc_client *p) -{ - if (p == NULL) - return NULL; - - struct ipc_client * copy = malloc (sizeof(struct ipc_client)); - memset (copy, 0, sizeof (struct ipc_client)); - memcpy (copy, p, sizeof (struct ipc_client)); - - return copy; -} - -int32_t ipc_server_client_eq (const struct ipc_client *p1, const struct ipc_client *p2) -{ - return (p1->version == p2->version && p1->index == p2->index - && p1->proc_fd == p2->proc_fd); -} - -void ipc_server_client_gen (struct ipc_client *p - , uint32_t index, uint32_t version) -{ - p->version = version; - p->index = index; -} - -int32_t ipc_clients_add (struct ipc_clients *clients, struct ipc_client *p) -{ - assert(clients != NULL); - assert(p != NULL); - - clients->size++; - clients->clients = realloc(clients->clients - , sizeof(struct ipc_client) * clients->size); - - if (clients->clients == NULL) { - return -1; - } - - clients->clients[clients->size - 1] = p; - return 0; -} - -int32_t ipc_clients_del (struct ipc_clients *clients, struct ipc_client *p) -{ - assert(clients != NULL); - assert(p != NULL); - - if (clients->clients == NULL) { - return -1; - } - - int32_t i; - for (i = 0; i < clients->size; i++) { - if (clients->clients[i] == p) { - clients->clients[i] = clients->clients[clients->size-1]; - clients->size--; - if (clients->size == 0) { - ipc_clients_free (clients); - } - else { - clients->clients = realloc(clients->clients - , sizeof(struct ipc_client) * clients->size); - - if (clients->clients == NULL) { - return -2; - } - } - - return 0; - } - } - - return -3; -} - -void client_print (struct ipc_client *p) -{ - if (p != NULL) - printf ("client %d : index %d, version %d\n" - , p->proc_fd, p->index, p->version); -} - -void ipc_clients_print (struct ipc_clients *ap) -{ - int32_t i; - for (i = 0; i < ap->size; i++) { - printf("%d : ", i); - client_print(ap->clients[i]); - } -} - -void ipc_clients_free (struct ipc_clients *ap) -{ - if (ap->clients != NULL) { - free (ap->clients); - ap->clients = NULL; - } - ap->size = 0; -} - - diff --git a/src/client.h b/src/client.h deleted file mode 100644 index 8366fe0..0000000 --- a/src/client.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __IPC_CLIENT_H__ -#define __IPC_CLIENT_H__ - -#include -#include "ipc.h" - -void ipc_clients_print (struct ipc_clients *); -void client_print (struct ipc_client *); - -#endif diff --git a/src/communication.c b/src/communication.c index f56447a..3e0ce7b 100644 --- a/src/communication.c +++ b/src/communication.c @@ -1,309 +1,227 @@ -#include "communication.h" +#include "ipc.h" + #include "utils.h" -#include "error.h" -#include "event.h" #include #include #include -#include +#include // error numbers + +#include +#include + +// print structures +#include "message.h" + void service_path (char *path, const char *sname, int32_t index, int32_t version) { assert (path != NULL); assert (sname != NULL); + memset (path, 0, PATH_MAX); - snprintf (path, PATH_MAX, "%s/%s-%d-%d", RUNDIR, sname, index, version); + + char * rundir = getenv ("IPC_RUNDIR"); + if (rundir == NULL) + rundir = RUNDIR; + + snprintf (path, PATH_MAX, "%s/%s-%d-%d", rundir, sname, index, version); } -int32_t ipc_server_init (char **env - , struct ipc_service *srv, const char *sname) +/*calculer le max filedescriptor*/ +static int32_t get_max_fd (struct ipc_connection_infos *cinfos) { + int32_t i; + int32_t max = 0; + + for (i = 0; i < cinfos->size; i++ ) { + if (cinfos->cinfos[i]->fd > max) { + max = cinfos->cinfos[i]->fd; + } + } + + return max; +} + +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; + if (srv == NULL) - return IPC_ERROR_WRONG_PARAMETERS; + return IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM; - // TODO - // use env parameters - // it will be useful to change some parameters transparently - // ex: to get resources from other machines, choosing the - // remote with environment variables + if (sname == NULL) + return IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM; + // 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; // gets the service path - service_path (srv->spath, sname, srv->index, srv->version); + char buf [PATH_MAX]; + memset (buf, 0, PATH_MAX); + service_path (buf, sname, srv->index, srv->version); - int32_t ret = usock_init (&srv->service_fd, srv->spath); - if (ret < 0) { - handle_err ("ipc_server_init", "usock_init ret < 0"); - return -1; + // gets the service path + if (srv->spath != NULL) { + free (srv->spath); } - return 0; -} + 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 -int32_t ipc_server_accept (struct ipc_service *srv, struct ipc_client *p) -{ - assert (srv != NULL); - assert (p != NULL); - - int32_t ret = usock_accept (srv->service_fd, &p->proc_fd); - if (ret < 0) { - handle_err ("ipc_server_accept", "usock_accept < 0"); - return -1; + enum ipc_errors ret = usock_init (&srv->fd, srv->spath); + if (ret != IPC_ERROR_NONE) { + handle_err ("ipc_server_init", "usock_init"); + return ret; } - return 0; + return IPC_ERROR_NONE; } -// empty the srv structure -int32_t ipc_server_close (struct ipc_service *srv) +enum ipc_errors ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname) { - usock_close (srv->service_fd); - int32_t ret = usock_remove (srv->spath); - ipc_service_empty (srv); - return ret; -} - -int32_t ipc_server_close_client (struct ipc_client *p) -{ - return usock_close (p->proc_fd); -} - -int32_t ipc_server_read (const struct ipc_client *p, struct ipc_message *m) -{ - return ipc_message_read (p->proc_fd, m); -} - -int32_t ipc_server_write (const struct ipc_client *p, const struct ipc_message *m) -{ - return ipc_message_write (p->proc_fd, m); -} - -int32_t ipc_application_connection (char **env - , struct ipc_service *srv, const char *sname) -{ - // TODO - // use env parameters - // it will be useful to change some parameters transparently - // ex: to get resources from other machines, choosing the - // remote with environment variables - + // 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; assert (srv != NULL); assert (sname != NULL); if (srv == NULL) { - return -1; + return IPC_ERROR_CONNECTION__NO_SERVER; + } + + if (sname == NULL) { + return IPC_ERROR_CONNECTION__NO_SERVICE_NAME; } // gets the service path - service_path (srv->spath, sname, srv->index, srv->version); + char buf [PATH_MAX]; + memset (buf, 0, PATH_MAX); + service_path (buf, sname, srv->index, srv->version); - int32_t ret = usock_connect (&srv->service_fd, srv->spath); - if (ret < 0) { - handle_err ("ipc_application_connection", "usock_connect ret <= 0"); - return -1; + enum ipc_errors ret = usock_connect (&srv->fd, buf); + if (ret != IPC_ERROR_NONE) { + handle_err ("ipc_connection", "usock_connect ret"); + return ret; } - return 0; + return IPC_ERROR_NONE; } -// close the socket -int32_t ipc_application_close (struct ipc_service *srv) +enum ipc_errors ipc_server_close (struct ipc_connection_info *srv) { - return usock_close (srv->service_fd); + usock_close (srv->fd); + enum ipc_errors ret = usock_remove (srv->spath); + if (srv->spath != NULL) { + free (srv->spath); + srv->spath = NULL; + } + return ret; } -int32_t ipc_application_read (struct ipc_service *srv, struct ipc_message *m) -{ - return ipc_message_read (srv->service_fd, m); -} - -int32_t ipc_application_write (struct ipc_service *srv, const struct ipc_message *m) +enum ipc_errors ipc_close (struct ipc_connection_info *p) { - return ipc_message_write (srv->service_fd, m); + return usock_close (p->fd); } - -/*calculer le max filedescriptor*/ -static int32_t get_max_fd_from_ipc_clients_ (struct ipc_clients *clients) +enum ipc_errors ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p) { - int32_t i; - int32_t max = 0; + assert (srv != NULL); + assert (p != NULL); - for (i = 0; i < clients->size; i++ ) { - if (clients->clients[i]->proc_fd > max) { - max = clients->clients[i]->proc_fd; - } - } - - return max; -} - -static int32_t get_max_fd_from_ipc_services_ (struct ipc_services *services) -{ - int32_t i; - int32_t max = 0; - - for (i = 0; i < services->size; i++ ) { - if (services->services[i]->service_fd > max) { - max = services->services[i]->service_fd; - } - } - - return max; -} - -/* - * ipc_server_select prend en parametre - * * un tableau de client qu'on écoute - * * le service qui attend de nouvelles connexions - * * un tableau de client qui souhaitent parler - * - * 0 = OK - * -1 = error - */ - -int32_t ipc_server_select (struct ipc_clients *clients, struct ipc_service *srv - , struct ipc_clients *active_clients, int32_t *new_connection) -{ - *new_connection = 0; - assert (clients != NULL); - assert (active_clients != NULL); - - // delete previous read active_clients array - ipc_clients_free (active_clients); - - int32_t i, j; - /* master file descriptor list */ - fd_set master; - fd_set readf; - - /* maximum file descriptor number */ - int32_t fdmax; - /* listening socket descriptor */ - int32_t listener = srv->service_fd; - - /* clear the master and temp sets */ - FD_ZERO(&master); - FD_ZERO(&readf); - /* add the listener to the master set */ - FD_SET(listener, &master); - - for (i=0; i < clients->size; i++) { - FD_SET(clients->clients[i]->proc_fd, &master); - } - - /* keep track of the biggest file descriptor */ - fdmax = get_max_fd_from_ipc_clients_ (clients) > srv->service_fd ? get_max_fd_from_ipc_clients_ (clients) : srv->service_fd; - - readf = master; - if(select(fdmax+1, &readf, NULL, NULL, NULL) == -1) { - perror("select"); - return -1; + if (srv == NULL) { + return IPC_ERROR_ACCEPT__NO_SERVICE_PARAM; } - for (i = 0; i <= fdmax; i++) { - if (FD_ISSET(i, &readf)) { - if (i == listener) { - *new_connection = 1; - } else { - for(j = 0; j < clients->size; j++) { - if(i == clients->clients[j]->proc_fd ) { - ipc_clients_add (active_clients, clients->clients[j]); - } - } - } - } + if (p == NULL) { + return IPC_ERROR_ACCEPT__NO_CLIENT_PARAM; } - return 0; + 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; + } + + return IPC_ERROR_NONE; } -/* - * ipc_application_select prend en parametre - * * un tableau de server qu'on écoute - * * le service qui attend de nouvelles connexions - * * un tableau de client qui souhaitent parler - * - * 0 = OK - * -1 = error - */ - -int32_t ipc_application_select (struct ipc_services *services, struct ipc_services *active_services) +enum ipc_errors ipc_read (const struct ipc_connection_info *p, struct ipc_message *m) { - assert (services != NULL); - assert (active_services != NULL); - - // delete previous read active_services array - ipc_services_free (active_services); - - int32_t i, j; - /* master file descriptor list */ - fd_set master; - fd_set readf; - - /* maximum file descriptor number */ - int32_t fdmax; - - /* clear the master and temp sets */ - FD_ZERO(&master); - FD_ZERO(&readf); - - for (i=0; i < services->size; i++) { - FD_SET(services->services[i]->service_fd, &master); - } - - /* keep track of the biggest file descriptor */ - fdmax = get_max_fd_from_ipc_services_ (services); - - readf = master; - if(select(fdmax+1, &readf, NULL, NULL, NULL) == -1) { - perror("select"); - return -1; - } - - for (i = 0; i <= fdmax; i++) { - if (FD_ISSET(i, &readf)) { - for(j = 0; j < services->size; j++) { - if(i == services->services[j]->service_fd ) { - ipc_services_add (active_services, services->services[j]); - } - } - } - } - - return 0; + return ipc_message_read (p->fd, m); } -int32_t handle_new_connection (struct ipc_service *srv - , struct ipc_clients *clients - , struct ipc_client **new_client) +enum ipc_errors ipc_write (const struct ipc_connection_info *p, const struct ipc_message *m) { - *new_client = malloc(sizeof(struct ipc_client)); - memset(*new_client, 0, sizeof(struct ipc_client)); - - if (ipc_server_accept (srv, *new_client) < 0) { - handle_error("server_accept < 0"); - return 1; - } else { - // printf("new connection\n"); - } - - if (ipc_clients_add (clients, *new_client) < 0) { - handle_error("ipc_clients_add < 0"); - return 1; - } - - return 0; + return ipc_message_write (p->fd, m); } -int32_t ipc_service_poll_event (struct ipc_clients *clients, struct ipc_service *srv +enum ipc_errors handle_new_connection (struct ipc_connection_info *cinfo + , struct ipc_connection_infos *cinfos + , struct ipc_connection_info **new_client) +{ + if (cinfo == NULL) { + return IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM; + } + + if (cinfos == NULL) { + return IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM; + } + + *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)); + + enum ipc_errors ret = ipc_accept (cinfo, *new_client); + if (ret != IPC_ERROR_NONE) { + handle_error("server_accept error"); + return ret; + } + + ret = ipc_add (cinfos, *new_client); + if (ret != IPC_ERROR_NONE) { + handle_error("ipc_clients_add error"); + return ret; + } + + return IPC_ERROR_NONE; +} + +// TODO: should replace +// ipc_service_poll_event +// ipc_application_poll_event +// ipc_application_peek_event +// ipc_application_poll_event_ +enum ipc_errors ipc_wait_event (struct ipc_connection_infos *cinfos + , struct ipc_connection_info *cinfo // NULL for clients , struct ipc_event *event) { - assert (clients != NULL); + assert (cinfos != NULL); + + if (cinfos == NULL) { + return IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM; + } + + if (event == NULL) { + return IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM; + } IPC_EVENT_CLEAN(event); @@ -312,44 +230,55 @@ int32_t ipc_service_poll_event (struct ipc_clients *clients, struct ipc_service fd_set master; fd_set readf; - /* maximum file descriptor number */ - int32_t fdmax; - /* listening socket descriptor */ - int32_t listener = srv->service_fd; - /* clear the master and temp sets */ FD_ZERO(&master); FD_ZERO(&readf); - /* add the listener to the master set */ - FD_SET(listener, &master); - - for (i=0; i < clients->size; i++) { - FD_SET(clients->clients[i]->proc_fd, &master); - } + /* maximum file descriptor number */ /* keep track of the biggest file descriptor */ - fdmax = get_max_fd_from_ipc_clients_ (clients) > srv->service_fd ? get_max_fd_from_ipc_clients_ (clients) : srv->service_fd; + int32_t fdmax = get_max_fd (cinfos); + + /* listening socket descriptor */ + int32_t listener; + if (cinfo != NULL) { + listener = cinfo->fd; + + /* add the listener to the master set */ + FD_SET(listener, &master); + + // if listener is max fd + if (fdmax < listener) + fdmax = listener; + } + + for (i=0; i < cinfos->size; i++) { + FD_SET(cinfos->cinfos[i]->fd, &master); + } readf = master; if(select(fdmax+1, &readf, NULL, NULL, NULL) == -1) { perror("select"); - return -1; + return IPC_ERROR_WAIT_EVENT__SELECT; } for (i = 0; i <= fdmax; i++) { if (FD_ISSET(i, &readf)) { - if (i == listener) { + if (cinfo != NULL && i == listener) { // connection - struct ipc_client *new_client = NULL; - handle_new_connection (srv, clients, &new_client); + 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 0; + return IPC_ERROR_NONE; } else { - for(j = 0; j < clients->size; j++) { - if(i == clients->clients[j]->proc_fd ) { + for(j = 0; j < cinfos->size; j++) { + if(i == cinfos->cinfos[j]->fd ) { // listen to what they have to say (disconnection or message) // then add a client to `event`, the ipc_event structure - int32_t ret = 0; + enum ipc_errors ret; struct ipc_message *m = NULL; m = malloc (sizeof(struct ipc_message)); if (m == NULL) { @@ -358,24 +287,27 @@ int32_t ipc_service_poll_event (struct ipc_clients *clients, struct ipc_service memset (m, 0, sizeof (struct ipc_message)); // current talking client - struct ipc_client *pc = clients->clients[j]; - ret = ipc_server_read (pc, m); - if (ret < 0) { - handle_err ("ipc_service_poll_event", "ipc_server_read < 0"); + struct ipc_connection_info *pc = cinfos->cinfos[j]; + 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); IPC_EVENT_SET(event, IPC_EVENT_TYPE_ERROR, NULL, pc); - return IPC_ERROR_READ; + return ret; } - // disconnection: close the client then delete it from clients - if (ret == 1) { - if (ipc_server_close_client (pc) < 0) { - handle_err( "ipc_service_poll_event", "ipc_server_close_client < 0"); + // 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"); } - if (ipc_clients_del (clients, pc) < 0) { - handle_err( "ipc_service_poll_event", "ipc_clients_del < 0"); + + ret = ipc_del (cinfos, pc); + if (ret != IPC_ERROR_NONE) { + handle_err( "ipc_wait_event", "ipc_del"); } ipc_message_empty (m); free (m); @@ -383,131 +315,178 @@ int32_t ipc_service_poll_event (struct ipc_clients *clients, struct ipc_service IPC_EVENT_SET(event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc); // warning: do not forget to free the ipc_client structure - return 0; + return IPC_ERROR_NONE; } - // we received a new message from a client - IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc); - return 0; + // we received a new message + // from a client + if (pc->type == 'a') { + IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, m, pc); + } + else { + IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc); + } + return IPC_ERROR_NONE; } } } } } - return 0; + return IPC_ERROR_NONE; } -int32_t ipc_application_poll_event_ (struct ipc_services *services, struct ipc_event *event, int32_t interactive) +// store and remove only pointers on allocated structures +enum ipc_errors ipc_add (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p) { - assert (services != NULL); + assert(cinfos != NULL); + assert(p != NULL); - IPC_EVENT_CLEAN(event); - - int32_t i, j; - /* master file descriptor list */ - fd_set master; - fd_set readf; - - /* maximum file descriptor number */ - int32_t fdmax; - - /* clear the master and temp sets */ - FD_ZERO(&master); - FD_ZERO(&readf); - - if (interactive) { - FD_SET(0, &master); - } - - for (i=0; i < services->size; i++) { - FD_SET(services->services[i]->service_fd, &master); + if (cinfos == NULL) { + return IPC_ERROR_ADD__NO_PARAM_CLIENTS; } - /* keep track of the biggest file descriptor */ - fdmax = get_max_fd_from_ipc_services_ (services); + if (p == NULL) { + return IPC_ERROR_ADD__NO_PARAM_CLIENT; + } - readf = master; - if(select(fdmax+1, &readf, NULL, NULL, NULL) == -1) { - perror("select"); - return -1; + cinfos->size++; + cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * cinfos->size); + + if (cinfos->cinfos == NULL) { + return IPC_ERROR_ADD__EMPTY_LIST; + } + + cinfos->cinfos[cinfos->size - 1] = p; + return IPC_ERROR_NONE; +} + +enum ipc_errors ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p) +{ + assert(cinfos != NULL); + assert(p != NULL); + + 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; + for (i = 0; i < cinfos->size; i++) { + if (cinfos->cinfos[i] == p) { + cinfos->cinfos[i] = cinfos->cinfos[cinfos->size-1]; + cinfos->size--; + if (cinfos->size == 0) { + ipc_connections_free (cinfos); + } + else { + cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * cinfos->size); + + if (cinfos->cinfos == NULL) { + return IPC_ERROR_DEL__EMPTIED_LIST; + } + } + + return IPC_ERROR_NONE; + } + } + + return IPC_ERROR_DEL__CANNOT_FIND_CLIENT; +} + +void ipc_connections_free (struct ipc_connection_infos *cinfos) +{ + if (cinfos->cinfos != NULL) { + free (cinfos->cinfos); + cinfos->cinfos = NULL; + } + cinfos->size = 0; +} + +// TODO: should replace ipc_client_server_copy and ipc_server_client_copy +struct ipc_connection_info * ipc_connection_copy (const struct ipc_connection_info *p) +{ + if (p == NULL) + return 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)); + memcpy (copy, p, sizeof (struct ipc_connection_info)); + + return copy; +} + +// TODO: should replace ipc_server_client_eq, ipc_service_eq +int8_t ipc_connection_eq (const struct ipc_connection_info *p1, const struct ipc_connection_info *p2) +{ + return (p1->type == p2->type && p1->version == p2->version && p1->index == p2->index && p1->fd == p2->fd); +} + +// create the client service structure +// TODO: should replace ipc_client_server_gen, ipc_server_client_gen +enum ipc_errors ipc_connection_gen (struct ipc_connection_info *cinfo + , uint32_t index, uint32_t version, int fd, char type) +{ + if (cinfo == NULL) { + return IPC_ERROR_CONNECTION_GEN__NO_CINFO; } - for (i = 0; i <= fdmax; i++) { - if (FD_ISSET(i, &readf)) { + cinfo->type = type; + cinfo->version = version; + cinfo->index = index; + cinfo->fd = fd; - // interactive: input on stdin - if (i == 0) { - // XXX: by default, message type is 0 - struct ipc_message *m = malloc (sizeof (struct ipc_message)); - if (m == NULL) { - return IPC_ERROR_NOT_ENOUGH_MEMORY; - } - memset (m, 0, sizeof (struct ipc_message)); - m->payload = malloc (IPC_MAX_MESSAGE_SIZE); + return IPC_ERROR_NONE; +} - m->length = read(0, m->payload , IPC_MAX_MESSAGE_SIZE); - IPC_EVENT_SET(event, IPC_EVENT_TYPE_STDIN, m, NULL); - return 0; - } - - for(j = 0; j < services->size; j++) { - if(i == services->services[j]->service_fd ) { - // listen to what they have to say (disconnection or message) - // then add a client to `event`, the ipc_event structure - int32_t ret = 0; - 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 - struct ipc_service *ps = services->services[j]; - ret = ipc_application_read (ps, m); - if (ret < 0) { - handle_err ("ipc_application_poll_event", "ipc_application_read < 0"); - ipc_message_empty (m); - free (m); - - IPC_EVENT_SET(event, IPC_EVENT_TYPE_ERROR, NULL, ps); - return IPC_ERROR_READ; - } - - // disconnection: close the service - if (ret == 1) { - if (ipc_application_close (ps) < 0) { - handle_err( "ipc_application_poll_event", "ipc_application_close < 0"); - } - if (ipc_services_del (services, ps) < 0) { - handle_err( "ipc_application_poll_event", "ipc_services_del < 0"); - } - ipc_message_empty (m); - free (m); - - IPC_EVENT_SET(event, IPC_EVENT_TYPE_DISCONNECTION, NULL, ps); - - // warning: do not forget to free the ipc_client structure - return 0; - } - - // we received a new message from a client - IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, ps); - return 0; - - } - } - } +// 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; } - return 0; + struct ipc_connection_info *cinfo; + + enum ipc_errors ret; + ret = ipc_connection_gen (cinfo, 0, 0, fd, 'a'); + + return IPC_ERROR_NONE; } -int32_t ipc_application_poll_event (struct ipc_services *services, struct ipc_event *event) { - return ipc_application_poll_event_ (services, event, 0); +void ipc_connection_print (struct ipc_connection_info *cinfo) +{ + if (cinfo == NULL) { + return; + } + + 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"); + } } -int32_t ipc_application_peek_event (struct ipc_services *services, struct ipc_event *event) { - return ipc_application_poll_event_ (services, event, 1); +void ipc_connections_print (struct ipc_connection_infos *cinfos) +{ + int32_t i; + for (i = 0; i < cinfos->size; i++) { + printf("[%d] : ", i); + ipc_connection_print(cinfos->cinfos[i]); + } } diff --git a/src/communication.h b/src/communication.h index c98ee75..e3c31b0 100644 --- a/src/communication.h +++ b/src/communication.h @@ -1,20 +1,4 @@ #ifndef __IPC_COMMUNICATION_H__ #define __IPC_COMMUNICATION_H__ -#include -#include -#include -#include // error numbers - - -#include "ipc.h" -#include "client.h" -#include "event.h" -#include "message.h" - -#define IPC_WITH_UNIX_SOCKETS -#ifdef IPC_WITH_UNIX_SOCKETS -#include "usocket.h" -#endif - #endif diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..d4e1344 --- /dev/null +++ b/src/error.c @@ -0,0 +1,113 @@ +#include "ipc.h" + +#define NTAB(t) ((int) (sizeof (t) / sizeof (t)[0])) + +struct ipc_errors_verbose { + enum ipc_errors error_code; + char * explanation_string; +}; + +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_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_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_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_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_HANDLE_NEW_CONNECTION__MALLOC, "ipc_handle_new_connection: error on malloc function" + + , 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_ADD_FD__NO_PARAM_CINFOS, "ipc_add_fd: no cinfos 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_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_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_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" + + + /* 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_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__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_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" +}; + +const char * ipc_errors_get (enum ipc_errors e) +{ + for (int i = 0 ; i < NTAB(ipc_errors_verbose) ; i++) { + if (ipc_errors_verbose[i].error_code == e) { + return ipc_errors_verbose[i].explanation_string; + } + } + + return NULL; +} diff --git a/src/error.h b/src/error.h deleted file mode 100644 index cd1c780..0000000 --- a/src/error.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __IPC_ERROR_H__ -#define __IPC_ERROR_H__ - -// #define IPC_WITH_ERRORS 3 - -#ifdef IPC_WITH_ERRORS -#include "logger.h" -#define handle_error(msg) \ - do { log_error (msg); exit(EXIT_FAILURE); } while (0) - -#define handle_err(fun,msg)\ - do { log_error ("%s: file %s line %d %s", fun, __FILE__, __LINE__, msg); } while (0) -#else -#define handle_error(msg) -#define handle_err(fun,msg) -#endif - -#endif diff --git a/src/event.h b/src/event.h deleted file mode 100644 index eb97be6..0000000 --- a/src/event.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __IPC_EVENT__ -#define __IPC_EVENT__ - -#include "ipc.h" -#include "message.h" - -#define IPC_EVENT_SET(pevent,type_,message_,origin_) {\ - pevent->type = type_; \ - pevent->m = message_; \ - pevent->origin = origin_; \ -}; - -#define IPC_EVENT_CLEAN(pevent) {\ - pevent->type = IPC_EVENT_TYPE_NOT_SET;\ - if (pevent->m != NULL) {\ - ipc_message_empty (pevent->m);\ - free(pevent->m);\ - pevent->m = NULL;\ - }\ -}; - -#endif diff --git a/src/ipc.h b/src/ipc.h index c073a85..a937f87 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -28,40 +28,121 @@ enum msg_types { enum ipc_event_type { IPC_EVENT_TYPE_NOT_SET , IPC_EVENT_TYPE_ERROR - , IPC_EVENT_TYPE_STDIN + + , IPC_EVENT_TYPE_EXTRA_SOCKET + , IPC_EVENT_TYPE_CONNECTION , IPC_EVENT_TYPE_DISCONNECTION , IPC_EVENT_TYPE_MESSAGE }; enum ipc_errors { - IPC_ERROR_NOT_ENOUGH_MEMORY - , IPC_ERROR_WRONG_PARAMETERS - , IPC_ERROR_READ + /* 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_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 + + + /* 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_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 + + + /* 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 }; -struct ipc_service { + +struct ipc_connection_info { uint32_t version; uint32_t index; - char spath[PATH_MAX]; - int32_t service_fd; + int32_t fd; + char type; // server, client, arbitrary fd + char *spath; // max size: PATH_MAX }; -struct ipc_services { - struct ipc_service ** services; +struct ipc_connection_infos { + struct ipc_connection_info ** cinfos; int32_t size; }; -struct ipc_client { - uint32_t version; - uint32_t index; - int32_t proc_fd; -}; - -struct ipc_clients { - struct ipc_client **clients; - int32_t size; -}; struct ipc_message { char type; @@ -71,111 +152,122 @@ struct ipc_message { struct ipc_event { enum ipc_event_type type; - void* origin; // currently used as an client or service pointer + struct ipc_connection_info *origin; void* m; // message pointer }; - -/* - * SERVICE - * +/** + * MACROS **/ -// srv->version and srv->index must be already set -// init unix socket + fill srv->spath -int32_t ipc_server_init (char **env , struct ipc_service *srv, const char *sname); -int32_t ipc_server_close (struct ipc_service *srv); -int32_t ipc_server_close_client (struct ipc_client *p); -int32_t ipc_server_accept (struct ipc_service *srv, struct ipc_client *p); +// #define IPC_WITH_ERRORS 3 -// 1 on a recipient socket close -int32_t ipc_server_read (const struct ipc_client *, struct ipc_message *m); -int32_t ipc_server_write (const struct ipc_client *, const struct ipc_message *m); +#ifdef IPC_WITH_ERRORS +#include "logger.h" +#define handle_error(msg) \ + do { log_error (msg); exit(EXIT_FAILURE); } while (0) -int32_t ipc_server_select (struct ipc_clients * clients, struct ipc_service *srv - , struct ipc_clients *active_clients, int32_t *new_connection); +#define handle_err(fun,msg)\ + do { log_error ("%s: file %s line %d %s", fun, __FILE__, __LINE__, msg); } while (0) +#else +#define handle_error(msg) +#define handle_err(fun,msg) +#endif -int32_t ipc_service_poll_event (struct ipc_clients *clients, struct ipc_service *srv - , struct ipc_event *event); +#define IPC_EVENT_SET(pevent,type_,message_,origin_) {\ + pevent->type = type_; \ + pevent->m = message_; \ + pevent->origin = origin_; \ +}; + +#define IPC_EVENT_CLEAN(pevent) {\ + pevent->type = IPC_EVENT_TYPE_NOT_SET;\ + if (pevent->m != NULL) {\ + ipc_message_empty (pevent->m);\ + free(pevent->m);\ + pevent->m = NULL;\ + }\ +}; + +#define IPC_WITH_UNIX_SOCKETS +#ifdef IPC_WITH_UNIX_SOCKETS +#include "usocket.h" +#endif + + +#define LOG + +void log_error (const char* message, ...); +void log_info (const char* message, ...); +void log_debug (const char* message, ...); /** - * SERVICES + * 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); + +enum ipc_errors ipc_server_close (struct ipc_connection_info *srv); +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); + +enum ipc_errors ipc_read (const struct ipc_connection_info *, struct ipc_message *m); +enum ipc_errors ipc_write (const struct ipc_connection_info *, const struct ipc_message *m); + +enum ipc_errors ipc_wait_event (struct ipc_connection_infos *clients + , struct ipc_connection_info *srv + , struct ipc_event *event); + // store and remove only pointers on allocated structures -int32_t ipc_services_add (struct ipc_services *, struct ipc_service *); -int32_t ipc_services_del (struct ipc_services *, struct ipc_service *); +enum ipc_errors ipc_add (struct ipc_connection_infos *, struct ipc_connection_info *); +enum ipc_errors ipc_del (struct ipc_connection_infos *, struct ipc_connection_info *); -void ipc_services_free (struct ipc_services *); +// add an arbitrary file descriptor to read +enum ipc_errors ipc_add_fd (struct ipc_connection_infos *cinfos, int fd); -struct ipc_service * ipc_client_server_copy (const struct ipc_service *p); -int32_t ipc_service_eq (const struct ipc_service *p1, const struct ipc_service *p2); +void ipc_connections_free (struct ipc_connection_infos *); + + +struct ipc_connection_info * ipc_connection_copy (const struct ipc_connection_info *p); +int8_t ipc_connection_eq (const struct ipc_connection_info *p1, const struct ipc_connection_info *p2); // create the client service structure -void ipc_client_server_gen (struct ipc_service *p, uint32_t index, uint32_t version); +enum ipc_errors ipc_connection_gen (struct ipc_connection_info *cinfo + , uint32_t index, uint32_t version, int fd, char type); -static inline int32_t ipc_service_empty (struct ipc_service *srv) { srv = srv; return 0 ;}; +void ipc_connection_print (struct ipc_connection_info *cinfo); +void ipc_connections_print (struct ipc_connection_infos *cinfos); + +// get explanation about an error +const char * ipc_errors_get (enum ipc_errors e); -/* - * APPLICATION - * - **/ - -// Initialize connection with unix socket -// send the connection string to $TMP/ -// fill srv->spath && srv->service_fd -int32_t ipc_application_connection (char **env, struct ipc_service *, const char *); -int32_t ipc_application_close (struct ipc_service *); - -// 1 on a recipient socket close -int32_t ipc_application_read (struct ipc_service *srv, struct ipc_message *m); -int32_t ipc_application_write (struct ipc_service *, const struct ipc_message *m); - -int32_t ipc_application_select (struct ipc_services *services, struct ipc_services *active_services); -int32_t ipc_application_poll_event (struct ipc_services *services, struct ipc_event *event); -int32_t ipc_application_peek_event (struct ipc_services *services, struct ipc_event *event); - - - -/* - * MESSAGE - * +/** + * 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); // used to create msg structure from buffer -int32_t 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, ssize_t msize); // used to create buffer from msg structure -int32_t 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, ssize_t *msize); // read a structure msg from fd -int32_t ipc_message_read (int32_t fd, struct ipc_message *m); +enum ipc_errors ipc_message_read (int32_t fd, struct ipc_message *m); // write a structure msg to fd -int32_t ipc_message_write (int32_t fd, const struct ipc_message *m); +enum ipc_errors ipc_message_write (int32_t fd, const struct ipc_message *m); -int32_t ipc_message_format (struct ipc_message *m, char type, const char *payload, ssize_t length); -int32_t ipc_message_format_data (struct ipc_message *m, const char *payload, ssize_t length); -int32_t ipc_message_format_server_close (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); -int32_t ipc_message_empty (struct ipc_message *m); +enum ipc_errors ipc_message_empty (struct ipc_message *m); -/* - * CLIENT - * - **/ - -// store and remove only pointers on allocated structures -int32_t ipc_clients_add (struct ipc_clients *, struct ipc_client *); -int32_t ipc_clients_del (struct ipc_clients *, struct ipc_client *); - -void ipc_clients_free (struct ipc_clients *); - -struct ipc_client * ipc_server_client_copy (const struct ipc_client *p); -int32_t ipc_server_client_eq (const struct ipc_client *p1, const struct ipc_client *p2); -// create the service client structure -void ipc_server_client_gen (struct ipc_client *p, uint32_t index, uint32_t version); - +// non public functions +void service_path (char *path, const char *sname, int32_t index, int32_t version); #endif diff --git a/src/logger.h b/src/logger.h index 4c1c11f..3acf589 100644 --- a/src/logger.h +++ b/src/logger.h @@ -1,15 +1,9 @@ #ifndef __IPC_LOGGER_H__ #define __IPC_LOGGER_H__ -#define LOG - #include -void log_error (const char* message, ...); -void log_info (const char* message, ...); -void log_debug (const char* message, ...); - -// please use previous functions +// print log, format: date:tag: message void log_format (const char* tag, const char* message, va_list args); #endif diff --git a/src/message.c b/src/message.c index f1dcff5..a20cc72 100644 --- a/src/message.c +++ b/src/message.c @@ -1,5 +1,10 @@ +#include +#include +#include + +#include + #include "message.h" -#include "error.h" #include "usocket.h" #include @@ -12,14 +17,44 @@ void ipc_message_print (const struct ipc_message *m) #endif } -int32_t ipc_message_format_read (struct ipc_message *m, const char *buf, ssize_t msize) + +enum ipc_errors ipc_message_new (struct ipc_message **m, ssize_t paylen) +{ + 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 -1; + 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; + } m->type = buf[0]; memcpy (&m->length, buf+1, sizeof m->length); @@ -40,24 +75,27 @@ int32_t ipc_message_format_read (struct ipc_message *m, const char *buf, ssize_t memcpy (m->payload, buf+IPC_HEADER_SIZE, m->length); } - return 0; + return IPC_ERROR_NONE; } -int32_t 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, ssize_t *msize) { assert (m != NULL); assert (buf != NULL); assert (msize != NULL); assert (m->length <= IPC_MAX_MESSAGE_SIZE); - if (m == NULL) - return -1; + if (m == NULL) { + return IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE; + } - if (buf == NULL) - return -2; + if (buf == NULL) { + return IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER; + } - if (msize == NULL) - return -3; + if (msize == NULL) { + return IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE; + } if (*buf == NULL) { *buf = malloc (IPC_HEADER_SIZE + m->length); @@ -78,82 +116,93 @@ int32_t ipc_message_format_write (const struct ipc_message *m, char **buf, ssize printf ("sending msg: type %u, size %d, msize %ld\n", m->type, m->length, *msize); #endif - return 0; + return IPC_ERROR_NONE; } -// 1 on a recipient socket close -int32_t ipc_message_read (int32_t fd, struct ipc_message *m) +// 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; - int32_t ret = usock_recv (fd, &buf, &msize); - if (ret < 0) { - // on error, buffer already freed + enum ipc_errors ret = usock_recv (fd, &buf, &msize); + if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) { + if (buf != NULL) + free (buf); handle_err ("msg_read", "usock_recv"); - return -1; + return ret; } - + // closed recipient, buffer already freed - if (ret == 1) { - return 1; + if (ret == IPC_ERROR_CLOSED_RECIPIENT) { + if (buf != NULL) + free (buf); + return IPC_ERROR_CLOSED_RECIPIENT; } - if (ipc_message_format_read (m, buf, msize) < 0) { - return -1; - } + ret = ipc_message_format_read (m, buf, msize); free (buf); - - return 0; + return ret; // propagates ipc_message_format return } -int32_t ipc_message_write (int32_t fd, const struct ipc_message *m) +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; - int32_t ret = usock_send (fd, buf, msize, &nbytes_sent); - if (ret < 0) { - if (buf != NULL) { - free (buf); - } - handle_err ("msg_write", "usock_send ret < 0"); - return -1; + 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) { - if (buf != NULL) { - free (buf); - } handle_err ("msg_write", "usock_send did not send enough data"); - return -1; + return IPC_ERROR_MESSAGE_WRITE__NOT_ENOUGH_DATA; } - if (buf != NULL) { - free (buf); - } - - return 0; + return IPC_ERROR_NONE; } // MSG FORMAT -int32_t ipc_message_format (struct ipc_message *m, char type, const char *payload, ssize_t length) +enum ipc_errors ipc_message_format (struct ipc_message *m, char type, const char *payload, ssize_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"); - return -1; + printf ("msg to format: %ld B)\n", length); + return IPC_ERROR_MESSAGE_FORMAT__LENGTH; } m->type = type; @@ -174,25 +223,26 @@ int32_t ipc_message_format (struct ipc_message *m, char type, const char *payloa if (payload != NULL) { memcpy (m->payload, payload, length); } - return 0; + return IPC_ERROR_NONE; } -int32_t ipc_message_format_data (struct ipc_message *m, const char *payload, ssize_t length) +enum ipc_errors ipc_message_format_data (struct ipc_message *m, const char *payload, ssize_t length) { return ipc_message_format (m, MSG_TYPE_DATA, payload, length); } -int32_t ipc_message_format_server_close (struct ipc_message *m) +enum ipc_errors ipc_message_format_server_close (struct ipc_message *m) { return ipc_message_format (m, MSG_TYPE_SERVER_CLOSE, NULL, 0); } -int32_t ipc_message_empty (struct ipc_message *m) +enum ipc_errors ipc_message_empty (struct ipc_message *m) { assert (m != NULL); - if (m == NULL) - return -1; + if (m == NULL) { + return IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST; + } if (m->payload != NULL) { free (m->payload); @@ -201,5 +251,5 @@ int32_t ipc_message_empty (struct ipc_message *m) m->length = 0; - return 0; + return IPC_ERROR_NONE; } diff --git a/src/message.h b/src/message.h index 2aeac2a..8b85c27 100644 --- a/src/message.h +++ b/src/message.h @@ -1,12 +1,6 @@ #ifndef __IPC_MSG_H__ #define __IPC_MSG_H__ -#include -#include -#include - -#include - #include "ipc.h" void ipc_message_print (const struct ipc_message *m); diff --git a/src/usocket.c b/src/usocket.c index d553c66..200d4ad 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -1,6 +1,9 @@ -#include "usocket.h" -#include "utils.h" -#include "error.h" +#include +#include +#include + +#include +#include #include #include @@ -8,20 +11,23 @@ #include #include -int32_t usock_send (const int32_t fd, const char *buf, ssize_t len, ssize_t *sent) +#include "usocket.h" +#include "utils.h" + +enum ipc_errors usock_send (const int32_t fd, const char *buf, ssize_t len, ssize_t *sent) { ssize_t ret = 0; ret = send (fd, buf, len, MSG_NOSIGNAL); if (ret <= 0) { handle_err ("usock_send", "send ret <= 0"); - return -1; + return IPC_ERROR_USOCK_SEND; } *sent = ret; - return 0; + return IPC_ERROR_NONE; } // *len is changed to the total message size read (header + payload) -int32_t usock_recv (const int32_t fd, char **buf, ssize_t *len) +enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) { assert(buf != NULL); assert(len != NULL); @@ -30,12 +36,12 @@ int32_t usock_recv (const int32_t fd, char **buf, ssize_t *len) if (buf == NULL) { handle_err ("usock_recv", "buf == NULL"); - return -1; + return IPC_ERROR_USOCK_RECV__NO_BUFFER; } if (len == NULL) { handle_err ("usock_recv", "len == NULL"); - return -1; + return IPC_ERROR_USOCK_RECV__NO_LENGTH; } if (*buf == NULL) { @@ -116,7 +122,7 @@ int32_t usock_recv (const int32_t fd, char **buf, ssize_t *len) handle_err ("usock_recv", "unsupported error"); ; } - return -1; + return IPC_ERROR_USOCK_RECV; } #if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 @@ -132,27 +138,27 @@ int32_t usock_recv (const int32_t fd, char **buf, ssize_t *len) free (*buf); *buf = NULL; } - return 1; + return IPC_ERROR_CLOSED_RECIPIENT; } // print_hexa ("msg recv", (uint8_t *)*buf, *len); // fflush(stdout); - return 0; + return IPC_ERROR_NONE; } -int32_t usock_connect (int32_t *fd, const char *path) +enum ipc_errors usock_connect (int32_t *fd, const char *path) { assert (fd != NULL); assert (path != NULL); if (fd == NULL) { handle_err ("usock_connect", "fd == NULL"); - return -1; + return IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR; } if (path == NULL) { handle_err ("usock_connect", "path == NULL"); - return -1; + return IPC_ERROR_USOCK_CONNECT__EMPTY_PATH; } int32_t sfd; @@ -162,7 +168,7 @@ int32_t usock_connect (int32_t *fd, const char *path) sfd = socket (AF_UNIX, SOCK_STREAM, 0); if (sfd == -1) { handle_err ("usock_connect", "sfd == -1"); - return -1; + return IPC_ERROR_USOCK_CONNECT__SOCKET; } // clear structure @@ -180,22 +186,22 @@ int32_t usock_connect (int32_t *fd, const char *path) *fd = sfd; - return 0; + return IPC_ERROR_NONE; } -int32_t usock_init (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 -1; + return IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR; } if (path == NULL) { handle_err ("usock_init", "path == NULL"); - return -1; + return IPC_ERROR_USOCK_INIT__EMPTY_PATH; } int32_t sfd; @@ -205,7 +211,7 @@ int32_t usock_init (int32_t *fd, const char *path) sfd = socket (AF_UNIX, SOCK_STREAM, 0); if (sfd == -1) { handle_err ("usock_init", "sfd == -1"); - return -1; + return IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR; } // clear structure @@ -214,35 +220,36 @@ int32_t usock_init (int32_t *fd, const char *path) my_addr.sun_family = AF_UNIX; strncpy(my_addr.sun_path, path, strlen (path)); - // TODO FIXME - // delete the unix socket if already created + // 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 -1; + return IPC_ERROR_USOCK_INIT__BIND; } if (listen (sfd, LISTEN_BACKLOG) == -1) { handle_err ("usock_init", "listen == -1"); perror("listen"); - return -1; + return IPC_ERROR_USOCK_INIT__LISTEN; } *fd = sfd; - return 0; + return IPC_ERROR_NONE; } -int32_t usock_accept (int32_t fd, int32_t *pfd) +enum ipc_errors usock_accept (int32_t fd, int32_t *pfd) { assert (pfd != NULL); if (pfd == NULL) { handle_err ("usock_accept", "pfd == NULL"); - return -1; + return IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR; } struct sockaddr_un peer_addr; @@ -253,13 +260,13 @@ int32_t usock_accept (int32_t fd, int32_t *pfd) if (*pfd < 0) { handle_err ("usock_accept", "accept < 0"); perror("listen"); - return -1; + return IPC_ERROR_USOCK_ACCEPT; } - return 0; + return IPC_ERROR_NONE; } -int32_t usock_close (int32_t fd) +enum ipc_errors usock_close (int32_t fd) { int32_t ret = 0; @@ -267,116 +274,25 @@ int32_t usock_close (int32_t fd) if (ret < 0) { handle_err ("usock_close", "close ret < 0"); perror ("closing"); - return -1; + return IPC_ERROR_USOCK_CLOSE; } - return 0; + return IPC_ERROR_NONE; } -int32_t usock_remove (const char *path) +enum ipc_errors usock_remove (const char *path) { - return unlink (path); -} - - -// TODO: ipc_services functions - -struct ipc_service * ipc_client_server_copy (const struct ipc_service *p) -{ - if (p == NULL) - return NULL; - - struct ipc_service * copy = malloc (sizeof(struct ipc_service)); - memset (copy, 0, sizeof (struct ipc_service)); - memcpy (copy, p, sizeof (struct ipc_service)); - - return copy; -} - -int32_t ipc_client_server_eq (const struct ipc_service *p1, const struct ipc_service *p2) -{ - return (p1->version == p2->version && p1->index == p2->index - && p1->service_fd == p2->service_fd && memcmp(p1->spath, p1->spath, PATH_MAX) == 0 ); -} - -void ipc_client_server_gen (struct ipc_service *p - , uint32_t index, uint32_t version) -{ - p->version = version; - p->index = index; -} - -int32_t ipc_services_add (struct ipc_services *services, struct ipc_service *p) -{ - assert(services != NULL); - assert(p != NULL); - - services->size++; - services->services = realloc(services->services - , sizeof(struct ipc_service) * services->size); - - if (services->services == NULL) { - return -1; - } - - services->services[services->size - 1] = p; - return 0; -} - -int32_t ipc_services_del (struct ipc_services *services, struct ipc_service *p) -{ - assert(services != NULL); - assert(p != NULL); - - if (services->services == NULL) { - return -1; - } - - int32_t i; - for (i = 0; i < services->size; i++) { - if (services->services[i] == p) { - - services->services[i] = services->services[services->size-1]; - services->size--; - if (services->size == 0) { - ipc_services_free (services); - } - else { - services->services = realloc(services->services - , sizeof(struct ipc_service) * services->size); - - if (services->services == NULL) { - return -2; - } - } - - return 0; - } - } - - return -3; -} - -void service_print (struct ipc_service *p) -{ - if (p != NULL) - printf ("client %d : index %d, version %d\n" - , p->service_fd, p->index, p->version); -} - -void ipc_services_print (struct ipc_services *ap) -{ - int32_t i; - for (i = 0; i < ap->size; i++) { - printf("%d : ", i); - service_print(ap->services[i]); - } -} - -void ipc_services_free (struct ipc_services *ap) -{ - if (ap->services != NULL) { - free (ap->services); - ap->services = NULL; - } - ap->size = 0; + struct stat file_state; + memset (&file_state, 0, sizeof (struct stat)); + + // 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; + } + + return IPC_ERROR_USOCK_REMOVE__NO_FILE; } diff --git a/src/usocket.h b/src/usocket.h index 370eebb..89c1bba 100644 --- a/src/usocket.h +++ b/src/usocket.h @@ -1,22 +1,13 @@ #ifndef __IPC_USOCKET_H__ #define __IPC_USOCKET_H__ -#include -#include -#include - #include "ipc.h" -#include #define LISTEN_BACKLOG 128 -/** - * for all functions: 0 ok, < 0 not ok - */ - // input: len = max buf size // output: *sent = nb received bytes -int32_t 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, ssize_t len, ssize_t *sent); // -1 on msize == NULL or buf == NULL // -1 on unsupported errors from read(2) @@ -25,23 +16,20 @@ int32_t usock_send (const int32_t fd, const char *buf, ssize_t len, ssize_t *sen // allocation of *len bytes on *buf == NULL // // output: *len = nb sent bytes -int32_t usock_recv (int32_t fd, char **buf, ssize_t *len); +enum ipc_errors usock_recv (int32_t fd, char **buf, ssize_t *len); // -1 on close(2) < 0 -int32_t usock_close (int32_t fd); +enum ipc_errors usock_close (int32_t fd); // same as connect(2) // -1 on fd == NULL -int32_t usock_connect (int32_t *fd, const char *path); +enum ipc_errors usock_connect (int32_t *fd, const char *path); -int32_t usock_init (int32_t *fd, const char *path); +enum ipc_errors usock_init (int32_t *fd, const char *path); -int32_t usock_accept (int32_t fd, int32_t *pfd); +enum ipc_errors usock_accept (int32_t fd, int32_t *pfd); // same as unlink(2) -int32_t usock_remove (const char *path); - -void ipc_services_print (struct ipc_services *); -void service_print (struct ipc_service *); +enum ipc_errors usock_remove (const char *path); #endif