diff --git a/Makefile b/Makefile index 859cdf6..567fa5c 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,8 @@ MANDIR := $(SHAREDIR)/man CC := cc AR := ar RANLIB := ranlib -CFLAGS := -LDFLAGS := +CFLAGS := -g +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,162 +36,162 @@ 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/communication.o src/error.o src/logger.o src/message.o src/usocket.o src/utils.o - @echo ' LD > libipc.so' + @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/communication.o src/error.o src/logger.o src/message.o src/usocket.o src/utils.o - @echo ' LD > libipc.a' + @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/communication.o: src/communication.c src/ipc.h src/utils.h src/message.h - @echo ' CC > src/communication.o' + @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' + @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' + @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/usocket.h - @echo ' CC > src/message.o' + @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 - @echo ' CC > src/usocket.o' + @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/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 @: @@ -221,7 +221,7 @@ 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 \ @@ -233,7 +233,6 @@ $(PACKAGE)-$(VERSION).tar.gz: distdir $(PACKAGE)-$(VERSION)/src/message.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ - $(PACKAGE)-$(VERSION)/src/communication.h \ $(PACKAGE)-$(VERSION)/src/logger.h \ $(PACKAGE)-$(VERSION)/src/message.h \ $(PACKAGE)-$(VERSION)/src/usocket.h \ @@ -241,7 +240,7 @@ $(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 \ @@ -253,7 +252,6 @@ $(PACKAGE)-$(VERSION).tar.xz: distdir $(PACKAGE)-$(VERSION)/src/message.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ - $(PACKAGE)-$(VERSION)/src/communication.h \ $(PACKAGE)-$(VERSION)/src/logger.h \ $(PACKAGE)-$(VERSION)/src/message.h \ $(PACKAGE)-$(VERSION)/src/usocket.h \ @@ -261,7 +259,7 @@ $(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 \ @@ -273,45 +271,44 @@ $(PACKAGE)-$(VERSION).tar.bz2: distdir $(PACKAGE)-$(VERSION)/src/message.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ - $(PACKAGE)-$(VERSION)/src/communication.h \ $(PACKAGE)-$(VERSION)/src/logger.h \ $(PACKAGE)-$(VERSION)/src/message.h \ $(PACKAGE)-$(VERSION)/src/usocket.h \ $(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: false' + @echo ' - colors: true' @echo '' - @echo 'Rebuild the Makefile with:' - @echo ' zsh ./build.zsh' + @echo 'Rebuild the Makefile with:' + @echo ' zsh ./build.zsh -c' .PHONY: all subdirs clean distclean dist install uninstall help diff --git a/examples/pong.c b/examples/pong.c index 6383504..eea4b60 100644 --- a/examples/pong.c +++ b/examples/pong.c @@ -6,28 +6,24 @@ #include "../src/ipc.h" #define MSG "coucou" -#define SERVICE_NAME "pongd" +#define SERVICE_NAME "pong" #define PRINTERR(ret,msg) {\ const char * err = ipc_errors_get (ret);\ fprintf(stderr, "error while %s: %s\n", msg, err);\ } +struct ipc_connection_info *srv; + 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); + ret = ipc_connection (env, srv, SERVICE_NAME); if (ret != IPC_ERROR_NONE) { handle_err("main", "ipc_application_connection < 0"); PRINTERR(ret, "application connection"); @@ -43,7 +39,7 @@ void non_interactive (char *env[]) // printf ("msg to send in the client: "); // ipc_message_print (&m); - ret = ipc_write (&srv, &m); + ret = ipc_write (srv, &m); if (ret != IPC_ERROR_NONE) { handle_err("main", "application_write"); PRINTERR(ret, "application write"); @@ -51,7 +47,7 @@ void non_interactive (char *env[]) } ipc_message_empty (&m); - ret = ipc_read (&srv, &m); + ret = ipc_read (srv, &m); if (ret != IPC_ERROR_NONE) { handle_err("main", "application_read"); PRINTERR(ret, "application read"); @@ -61,7 +57,7 @@ void non_interactive (char *env[]) printf ("msg recv (type: %u): %s\n", m.user_type, m.payload); ipc_message_empty (&m); - ret = ipc_close (&srv); + ret = ipc_close (srv); if (ret != IPC_ERROR_NONE) { handle_err("main", "application_close"); PRINTERR(ret, "application close"); @@ -72,15 +68,9 @@ void non_interactive (char *env[]) 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); + ret = ipc_connection (env, srv, SERVICE_NAME); if (ret != IPC_ERROR_NONE) { handle_err ("main", "ipc_application_connection < 0"); PRINTERR(ret, "application connection"); @@ -92,48 +82,66 @@ void interactive (char *env[]) struct ipc_connection_infos services; memset (&services, 0, sizeof (struct ipc_connection_infos)); - ipc_add (&services, &srv); + ipc_add (&services, srv); ipc_add_fd (&services, 0); // add STDIN + ipc_connections_print(&services); + 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"); + PRINTERR(ret, "wait 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) { + // structure not read, should read the message here - ipc_message_empty (m); - free (m); + ssize_t len; + char buf[4096]; + memset(buf, 0, 4096); - ipc_connections_free (&services); + len = read (event.origin->fd, buf, 4096); - ret = ipc_close (&srv); + buf[100] = '\0'; + + // 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", "application_close < 0"); + handle_err("main", "ipc_close"); PRINTERR(ret, "application close"); exit (EXIT_FAILURE); } + ipc_connections_free (&services); + exit (EXIT_SUCCESS); } - ret = ipc_write (&srv, m); + // send the message read on STDIN + struct ipc_message *m = NULL; + m = malloc (sizeof (struct ipc_message)); + memset (m, 0, sizeof (struct ipc_message)); + + ret = ipc_write (srv, m); if (ret != IPC_ERROR_NONE) { - handle_err("main", "application_write < 0"); - PRINTERR(ret, "application write"); + handle_err("main", "ipc_write"); + PRINTERR(ret, "ipc_write"); exit (EXIT_FAILURE); } + + ipc_message_empty (m); + free (m); } break; case IPC_EVENT_TYPE_MESSAGE: @@ -157,6 +165,13 @@ 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; + if (argc == 1) non_interactive (env); else diff --git a/examples/pongd.c b/examples/pongd.c index 24f81c6..eba67fb 100644 --- a/examples/pongd.c +++ b/examples/pongd.c @@ -5,7 +5,8 @@ #include #include -#define PONGD_SERVICE_NAME "pongd" +#define PONGD_SERVICE_NAME "pong" +#define PONGD_VERBOSE #define PRINTERR(ret,msg) {\ const char * err = ipc_errors_get (ret);\ @@ -32,16 +33,15 @@ void main_loop () 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 + // printf ("before wait event\n"); // TODO remove ret = ipc_wait_event (clients, srv, &event); + // printf ("after wait event\n"); // TODO remove 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); @@ -51,14 +51,18 @@ void main_loop () case IPC_EVENT_TYPE_CONNECTION: { cpt++; - printf ("connection: %d clients connected\n", cpt); - printf ("new client has the fd %d\n", (event.origin)->fd); +#ifdef PONGD_VERBOSE + printf ("connection: %d clients connected, new client is %d\n" + , cpt, (event.origin)->fd); +#endif }; break; case IPC_EVENT_TYPE_DISCONNECTION: { cpt--; +#ifdef PONGD_VERBOSE printf ("disconnection: %d clients remaining\n", cpt); +#endif // free the ipc_client structure free (event.origin); @@ -68,21 +72,25 @@ void main_loop () { 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 } 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); + cpt--; + fprintf (stderr, "a problem happened with client %d (now disconnected)", (event.origin)->fd); + fprintf (stderr, ", %d clients remaining\n", cpt); + + // free the ipc_client structure + free (event.origin); }; break; default : @@ -117,7 +125,6 @@ void exit_program(int signal) // 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); @@ -150,7 +157,6 @@ int main(int argc, char * argv[], char **env) 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; } diff --git a/examples/simple-tcp-client.c b/examples/simple-tcp-client.c new file mode 100644 index 0000000..1cf0693 --- /dev/null +++ b/examples/simple-tcp-client.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "../src/ipc.h" +#include "../src/utils.h" + +/** + * tcp connection to localhost port argv[1] + * message 1: pong + * message 2: echo with libipc format + * + * [messagetype | len | usertype | payload ] + * 1 B | 4 B | 1 B | ] + */ + + +int connection(int port) +{ + int sockfd; + struct sockaddr_in server; + socklen_t addrlen; + + // socket factory + if((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) + { + perror("socket"); + exit(EXIT_FAILURE); + } + + // init remote addr structure and other params + server.sin_family = AF_INET; + server.sin_port = htons(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); + } + + printf("Trying to connect to the remote host\n"); + if(connect(sockfd, (struct sockaddr *) &server, addrlen) == -1) + { + perror("connect"); + exit(EXIT_FAILURE); + } + + printf("Connection OK\n"); + + return sockfd; +} + + +void send_receive (int sockfd) { + unsigned char buf[BUFSIZ]; + memset (buf, 0, BUFSIZ); + + // first, send service name "pong" + // send string + if(send(sockfd, "pong", 4, 0) == -1) { + perror("send pong"); + close(sockfd); + exit(EXIT_FAILURE); + } + printf ("message 'pong' sent\n"); + + 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); + } + 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 { + fprintf (stderr, "error: disconnection from the server\n"); + exit (EXIT_FAILURE); + } + +#if 0 + // send string + if(sendto(sockfd, , ), 0) == -1) + { + perror("sendto"); + close(sockfd); + exit(EXIT_FAILURE); + } +#endif +} + + +int main(int argc, char * argv[]) +{ + int port = 9000; + if (argc > 1) { + port = atoi (argv[1]); + } + + int sockfd = connection (port); + + send_receive (sockfd); + + printf("Disconnection\n"); + + // close the socket + close(sockfd); + + + return EXIT_SUCCESS; +} diff --git a/examples/simple-tcpd.c b/examples/simple-tcpd.c new file mode 100644 index 0000000..691f36e --- /dev/null +++ b/examples/simple-tcpd.c @@ -0,0 +1,463 @@ +#include "../src/ipc.h" +#include "../src/utils.h" +#include + +#include +#include +#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); } } + +/* + * + * TODO: + * This program is under heavy developement. + * Still many things to do. + * NOT READY FOR PRODUCTION. + * + Server side: + 1. sock_tcp = tcp socket + 2. ipc_server_init + 3. ipc_add (ipc_server, sock_tcp) + 4. wait_event + if reading on extra socket + if reading on sock_tcp + sock_client = accept + ipc_add_fd sock_client + elif reading on sock_client + TODO (first draft): print messages + else + lolwat shouldn't happen :( + elif reading on usual socket + do something + **/ + +#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) +{ + is->collection = realloc(is->collection, sizeof(struct ipc_switching) * (is->size+1)); + if (is->collection == NULL) { + printf ("error realloc\n"); + 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 orig) +{ + 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; + + 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; + } + } + + 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"); + + // TODO: tests + if (send (fd, "OK", 2, 0) <= 0) { + fprintf (stderr, "error: cannot send message\n"); + perror("send"); + exit (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); + + 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); +} + +void handle_extra_socket (struct ipc_event event, int sockfd, char **env) +{ + SECURE_DECLARATION (struct sockaddr_in, client); + socklen_t addrlen = 0; + + printf ("something comes from somewhere: fd %d\n", event.origin->fd); + + // 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); + + 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); + } + } +} + + +void main_loop (int argc, char **argv, char **env) +{ + argc = argc; // FIXME: useless + int sockfd; + + 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); + } + + int yes = 1; + + if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { + perror ("setsockopt"); + } + + + // init local addr structure and other params + my_addr.sin_family = AF_INET; + my_addr.sin_port = htons(atoi(argv[1])); + my_addr.sin_addr.s_addr = INADDR_ANY; + 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); + } + + // 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); + } + + printf("Waiting for incomming connection\n"); + + + 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); + + + while(1) { + // ipc_service_poll_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); + } + + switch (event.type) { + case IPC_EVENT_TYPE_EXTRA_SOCKET: + { + handle_extra_socket (event, sockfd, env); + } + break; + + case IPC_EVENT_TYPE_CONNECTION: + { + ctx->cpt++; + printf ("connection: %d clients connected\n", ctx->cpt); + printf ("new client has the fd %d\n", (event.origin)->fd); + }; + break; + case IPC_EVENT_TYPE_DISCONNECTION: + { + ctx->cpt--; + printf ("disconnection: %d clients remaining\n", ctx->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 < ctx->clients->size ; i++) { + struct ipc_connection_info *cli = ctx->clients->cinfos[i]; + if (cli != NULL) { + free (cli); + } + ctx->clients->cinfos[i] = NULL; + } + + ipc_connections_free (ctx->clients); + 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); + + 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); +} + +/* + * 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) +{ + // check the number of args on command line + if(argc != 2) + { + printf("USAGE: %s port_num\n", argv[0]); + exit(-1); + } + + printf ("pid = %d\n", getpid ()); + + ctx = malloc (sizeof (struct networkd)); + memset (ctx, 0, sizeof (struct networkd)); + + + 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); + + 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 (argc, argv, env); + + // main_loop should not return + return EXIT_FAILURE; +} diff --git a/src/communication.c b/src/communication.c index 3e0ce7b..78c58ef 100644 --- a/src/communication.c +++ b/src/communication.c @@ -14,6 +14,9 @@ #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) { assert (path != NULL); @@ -25,7 +28,7 @@ void service_path (char *path, const char *sname, int32_t index, int32_t version if (rundir == NULL) rundir = RUNDIR; - snprintf (path, PATH_MAX, "%s/%s-%d-%d", rundir, sname, index, version); + snprintf (path, PATH_MAX-1, "%s/%s-%d-%d", rundir, sname, index, version); } /*calculer le max filedescriptor*/ @@ -68,6 +71,7 @@ enum ipc_errors ipc_server_init (char **env, struct ipc_connection_info *srv, co // gets the service path if (srv->spath != NULL) { free (srv->spath); + srv->spath = NULL; } size_t s = strlen (buf); @@ -157,6 +161,8 @@ enum ipc_errors ipc_accept (struct ipc_connection_info *srv, struct ipc_connecti return IPC_ERROR_ACCEPT; } + p->type = IPC_CONNECTION_TYPE_IPC; + return IPC_ERROR_NONE; } @@ -182,33 +188,25 @@ enum ipc_errors handle_new_connection (struct ipc_connection_info *cinfo return IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM; } - *new_client = malloc(sizeof(struct ipc_connection_info)); + *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) @@ -276,6 +274,15 @@ enum ipc_errors ipc_wait_event (struct ipc_connection_infos *cinfos } else { for(j = 0; j < cinfos->size; j++) { if(i == cinfos->cinfos[j]->fd ) { + + struct ipc_connection_info *pc = cinfos->cinfos[j]; + + // 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; @@ -287,13 +294,23 @@ enum ipc_errors ipc_wait_event (struct ipc_connection_infos *cinfos memset (m, 0, sizeof (struct ipc_message)); // current talking client - 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); + // 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; } @@ -318,14 +335,7 @@ enum ipc_errors ipc_wait_event (struct ipc_connection_infos *cinfos return IPC_ERROR_NONE; } - // 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); - } + IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc); return IPC_ERROR_NONE; } } @@ -351,7 +361,14 @@ enum ipc_errors ipc_add (struct ipc_connection_infos *cinfos, struct ipc_connect } cinfos->size++; - cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * 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; @@ -381,6 +398,7 @@ enum ipc_errors ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connect int32_t i; for (i = 0; i < cinfos->size; i++) { if (cinfos->cinfos[i] == p) { + // TODO: possible memory leak if the ipc_connection_info is not free'ed cinfos->cinfos[i] = cinfos->cinfos[cinfos->size-1]; cinfos->size--; if (cinfos->size == 0) { @@ -404,13 +422,15 @@ enum ipc_errors ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connect 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]); + } 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) @@ -427,14 +447,12 @@ struct ipc_connection_info * ipc_connection_copy (const struct ipc_connection_in 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) { @@ -457,12 +475,55 @@ enum ipc_errors ipc_add_fd (struct ipc_connection_infos *cinfos, int fd) return IPC_ERROR_ADD_FD__NO_PARAM_CINFOS; } - struct ipc_connection_info *cinfo; + 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)); enum ipc_errors ret; - ret = ipc_connection_gen (cinfo, 0, 0, fd, 'a'); + ipc_connection_gen (cinfo, 0, 0, fd, IPC_CONNECTION_TYPE_EXTERNAL); - return IPC_ERROR_NONE; + 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; + } + + if (cinfos->cinfos == NULL) { + return IPC_ERROR_DEL_FD__EMPTY_LIST; + } + + int32_t i; + for (i = 0; i < cinfos->size; i++) { + if (cinfos->cinfos[i]->fd == fd) { + free (cinfos->cinfos[i]); + cinfos->size--; + if (cinfos->size == 0) { + // free cinfos->cinfos + ipc_connections_free (cinfos); + } + else { + cinfos->cinfos[i] = cinfos->cinfos[cinfos->size]; + cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * cinfos->size); + + if (cinfos->cinfos == NULL) { + return IPC_ERROR_DEL_FD__EMPTIED_LIST; + } + } + + return IPC_ERROR_NONE; + } + } + + return IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT; } void ipc_connection_print (struct ipc_connection_info *cinfo) diff --git a/src/error.c b/src/error.c index d4e1344..553ea97 100644 --- a/src/error.c +++ b/src/error.c @@ -19,9 +19,10 @@ static struct ipc_errors_verbose ipc_errors_verbose [] = { , 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_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" @@ -43,6 +44,12 @@ static struct ipc_errors_verbose ipc_errors_verbose [] = { , 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_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_clients_del: empty list" , IPC_ERROR_DEL__EMPTIED_LIST, "ipc_clients_del: cannot realloc" diff --git a/src/ipc.h b/src/ipc.h index 3451d6d..e43326b 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -16,6 +16,8 @@ // #define IPC_MAX_MESSAGE_SIZE 100-IPC_HEADER_SIZE // #include "queue.h" +#define SECURE_DECLARATION(t,v) t v; memset(&v,0,sizeof(t)); + #define IPC_VERSION 1 @@ -71,6 +73,12 @@ enum ipc_errors { , 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 @@ -86,6 +94,7 @@ enum ipc_errors { , 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 @@ -166,13 +175,10 @@ struct ipc_event { #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 @@ -226,6 +232,7 @@ enum ipc_errors ipc_del (struct ipc_connection_infos *, struct ipc_connection_in // add an arbitrary file descriptor to read enum ipc_errors ipc_add_fd (struct ipc_connection_infos *cinfos, int fd); +enum ipc_errors ipc_del_fd (struct ipc_connection_infos *cinfos, int fd); void ipc_connections_free (struct ipc_connection_infos *); diff --git a/src/message.c b/src/message.c index 0a4c683..850ad52 100644 --- a/src/message.c +++ b/src/message.c @@ -4,11 +4,15 @@ #include +#include + #include "message.h" #include "usocket.h" #include +#define IPC_WITH_ERRORS 3 + void ipc_message_print (const struct ipc_message *m) { assert (m != NULL); @@ -59,12 +63,14 @@ enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, // message format: // Type (1 B) | Length (4 B) | UserType (1 B) | Payload (Length B) m->type = buf[0]; - memcpy (&m->length, buf+1, sizeof m->length); + size_t unformated_size = 0; + memcpy (&unformated_size, buf+1, sizeof(size_t)); + m->length = ntohl (unformated_size); m->user_type = buf[1 + sizeof m->length]; assert (m->length <= IPC_MAX_MESSAGE_SIZE); #if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 - printf ("type %d, paylen = %u, total = %lu\n", m->type, m->length, msize); + printf ("receiving msg:\ttype %d, paylen %u, total %lu\n", m->type, m->length, msize); #endif assert (m->length == msize - IPC_HEADER_SIZE || m->length == 0); @@ -77,6 +83,9 @@ enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, m->payload = malloc (m->length); memcpy (m->payload, buf+IPC_HEADER_SIZE, m->length); } + else { + m->payload = malloc (1); + } return IPC_ERROR_NONE; } @@ -106,18 +115,20 @@ enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **bu } char *buffer = *buf; + uint32_t paylen = htonl(m->length); buffer[0] = m->type; - memcpy (buffer + 1, &m->length, sizeof m->length); + 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) { + if (m->payload != NULL && m->length > 0) { memcpy (buffer + IPC_HEADER_SIZE, m->payload, m->length); } *msize = IPC_HEADER_SIZE + m->length; #if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 - printf ("sending msg: type %u, size %d, msize %ld\n", m->type, m->length, *msize); + printf ("sending msg:\ttype %u, paylen %u, msize %lu\n", m->type, m->length, *msize); #endif return IPC_ERROR_NONE; @@ -137,21 +148,19 @@ enum ipc_errors ipc_message_read (int32_t fd, struct ipc_message *m) 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 ret; } // closed recipient, buffer already freed if (ret == IPC_ERROR_CLOSED_RECIPIENT) { - if (buf != NULL) - free (buf); return IPC_ERROR_CLOSED_RECIPIENT; } - ret = ipc_message_format_read (m, buf, msize); - free (buf); + if (buf != NULL) { + ret = ipc_message_format_read (m, buf, msize); + free (buf); + } return ret; // propagates ipc_message_format return } diff --git a/src/usocket.c b/src/usocket.c index 200d4ad..33eb794 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -11,9 +11,20 @@ #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); + +/** + * TODO: non blocking read + */ + enum ipc_errors usock_send (const int32_t fd, const char *buf, ssize_t len, ssize_t *sent) { ssize_t ret = 0; @@ -32,7 +43,7 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) assert(buf != NULL); assert(len != NULL); - ssize_t ret = 0; + int32_t ret_recv = 0; if (buf == NULL) { handle_err ("usock_recv", "buf == NULL"); @@ -57,71 +68,95 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) uint32_t msize_read = 0; do { - ret = recv (fd, *buf, *len, 0); - if (msize == 0) { - if (ret != 0) { + ret_recv = recv (fd, *buf, *len, 0); + if (ret_recv > 0) { + if (msize == 0) { memcpy (&msize, *buf + 1, sizeof msize); } - } - assert (msize < IPC_MAX_MESSAGE_SIZE); - msize_read += ret - IPC_HEADER_SIZE; + else { + printf ("pas la première boucle, msize == %u\n", msize); + } + msize = ntohl (msize); - if (ret < 0) { + 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); + msize_read += ret_recv - IPC_HEADER_SIZE; + + } + else if (ret_recv < 0) { if (*buf != NULL) free (*buf); - - handle_err ("usock_recv", "recv ret < 0"); - perror("recv"); *len = 0; - switch (ret) { + 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..."); - exit (1); + fprintf (stderr, "ERROR WHILE RECEIVING: EFAULT\n"); + break; // Invalid argument passed. case EINVAL: handle_err ("usock_recv", "critical error: invalid arguments to read(2), quitting..."); - exit (1); + fprintf (stderr, "ERROR WHILE RECEIVING: EINVAL\n"); + break; // Could not allocate memory for recvmsg(). case ENOMEM: handle_err ("usock_recv", "critical error: cannot allocate memory, quitting..."); - exit (1); + fprintf (stderr, "ERROR WHILE RECEIVING: ENOMEM\n"); + break; // The argument sockfd is an invalid descriptor. case EBADF: handle_err ("usock_recv", "critical error: invalid descriptor, quitting..."); - exit (1); + fprintf (stderr, "ERROR WHILE RECEIVING: EBADF\n"); + break; // The file descriptor sockfd does not refer to a socket. case ENOTSOCK: handle_err ("usock_recv", "critical error: fd is not a socket, quitting..."); - exit (1); + fprintf (stderr, "ERROR WHILE RECEIVING: ENOTSOCK\n"); + break; // 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..."); - exit (1); + fprintf (stderr, "ERROR WHILE RECEIVING: ENOTCONN\n"); + break; - // EWOULDBLOCK case EAGAIN: + fprintf (stderr, "ERROR WHILE RECEIVING: EAGAIN / EWOULDBLOCK\n"); + break; // 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; // 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; default: + printf ("usock_recv unsupported error : %d\n", errno); handle_err ("usock_recv", "unsupported error"); - ; } + + handle_err ("usock_recv", "recv < 0"); + perror("recv"); + return IPC_ERROR_USOCK_RECV; } @@ -133,7 +168,7 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) *len = msize + IPC_HEADER_SIZE; // 1 on none byte received, indicates a closed recipient - if (ret == 0) { + if (ret_recv == 0) { if (*buf != NULL) { free (*buf); *buf = NULL; @@ -181,7 +216,7 @@ enum ipc_errors usock_connect (int32_t *fd, const char *path) if(connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) { handle_err ("usock_connect", "connect == -1"); perror("connect"); - exit(errno); + return IPC_ERROR_USOCK_CONNECT__CONNECT; } *fd = sfd; diff --git a/src/usocket.h b/src/usocket.h index 89c1bba..79bb3c2 100644 --- a/src/usocket.h +++ b/src/usocket.h @@ -9,20 +9,14 @@ // output: *sent = nb received bytes 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) -// exit on most errors from read(2) -// // 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); -// -1 on close(2) < 0 enum ipc_errors usock_close (int32_t fd); // same as connect(2) -// -1 on fd == NULL enum ipc_errors usock_connect (int32_t *fd, const char *path); enum ipc_errors usock_init (int32_t *fd, const char *path);