diff --git a/Makefile b/Makefile index 567fa5c..980ca4e 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ MANDIR := $(SHAREDIR)/man CC := cc AR := ar RANLIB := ranlib -CFLAGS := -g +CFLAGS := -Wall -Wextra -g LDFLAGS := Q := @ @@ -19,7 +19,7 @@ Q := @ all: libipc src/ipc.h man/libipc.7 @: -libipc: libipc.so libipc.a +libipc: libipc.so libipc.a @: libipc.install: libipc.so.install libipc.a.install @@ -27,7 +27,7 @@ libipc.clean: libipc.so.clean libipc.a.clean libipc.uninstall: libipc.so.uninstall libipc.a.uninstall -src/ipc.h.install: src/ipc.h +src/ipc.h.install: src/ipc.h src @echo ' IN > $(INCLUDEDIR)/ipc.h' $(Q)mkdir -p '$(DESTDIR)$(INCLUDEDIR)' $(Q)install -m0644 src/ipc.h $(DESTDIR)$(INCLUDEDIR)/ipc.h @@ -39,7 +39,7 @@ src/ipc.h.uninstall: @echo ' RM > $(INCLUDEDIR)/ipc.h' $(Q)rm -f '$(DESTDIR)$(INCLUDEDIR)/ipc.h' -man/libipc.7: man/libipc.7.md +man/libipc.7: man/libipc.7.md man @echo ' MAN > man/libipc.7' $(Q)pandoc -s --from markdown --to man 'man/libipc.7.md' -o 'man/libipc.7' @@ -57,9 +57,9 @@ man/libipc.7.uninstall: @echo ' RM > $(MANDIR)/man7/libipc.7' $(Q)rm -f '$(DESTDIR)$(MANDIR)/man7/libipc.7' -libipc.so: src/communication.o src/error.o src/logger.o src/message.o src/usocket.o src/utils.o +libipc.so: src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o @echo ' LD > libipc.so' - $(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/communication.o src/error.o src/logger.o src/message.o src/usocket.o src/utils.o + $(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o libipc.so.install: libipc.so @echo ' IN > $(LIBDIR)/libipc.so.0.1.0' @@ -86,9 +86,9 @@ libipc.so.uninstall: @echo ' RM > $(LIBDIR)/libipc.so' $(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so' -libipc.a: src/communication.o src/error.o src/logger.o src/message.o src/usocket.o src/utils.o +libipc.a: src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o @echo ' LD > libipc.a' - $(Q)$(AR) rc 'libipc.a' src/communication.o src/error.o src/logger.o src/message.o src/usocket.o src/utils.o + $(Q)$(AR) rc 'libipc.a' src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o libipc.a.install: libipc.a @echo ' IN > $(LIBDIR)/libipc.a' @@ -103,9 +103,9 @@ libipc.a.uninstall: @echo ' RM > $(LIBDIR)/libipc.a' $(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.a' -src/communication.o: src/communication.c src/ipc.h src/utils.h src/message.h +src/communication.o: src/communication.c src/ipc.h src/utils.h src/message.h @echo ' CC > src/communication.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/communication.c -fPIC -o src/communication.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/communication.c -fPIC -std=c11 -o src/communication.o src/communication.o.install: @@ -115,9 +115,9 @@ src/communication.o.clean: src/communication.o.uninstall: -src/error.o: src/error.c src/ipc.h +src/error.o: src/error.c src/ipc.h @echo ' CC > src/error.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/error.c -fPIC -o src/error.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/error.c -fPIC -std=c11 -o src/error.o src/error.o.install: @@ -127,9 +127,9 @@ src/error.o.clean: src/error.o.uninstall: -src/logger.o: src/logger.c src/logger.h +src/logger.o: src/logger.c src/logger.h @echo ' CC > src/logger.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/logger.c -fPIC -o src/logger.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/logger.c -fPIC -std=c11 -o src/logger.o src/logger.o.install: @@ -139,9 +139,9 @@ src/logger.o.clean: src/logger.o.uninstall: -src/message.o: src/message.c src/message.h src/usocket.h +src/message.o: src/message.c src/message.h src/usocket.h @echo ' CC > src/message.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/message.c -fPIC -o src/message.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/message.c -fPIC -std=c11 -o src/message.o src/message.o.install: @@ -151,9 +151,21 @@ src/message.o.clean: src/message.o.uninstall: -src/usocket.o: src/usocket.c src/usocket.h src/utils.h +src/network.o: src/network.c src/ipc.h + @echo ' CC > src/network.o' + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/network.c -fPIC -std=c11 -o src/network.o + +src/network.o.install: + +src/network.o.clean: + @echo ' RM > src/network.o' + $(Q)rm -f src/network.o + +src/network.o.uninstall: + +src/usocket.o: src/usocket.c src/usocket.h src/utils.h @echo ' CC > src/usocket.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/usocket.c -fPIC -o src/usocket.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/usocket.c -fPIC -std=c11 -o src/usocket.o src/usocket.o.install: @@ -163,9 +175,9 @@ src/usocket.o.clean: src/usocket.o.uninstall: -src/utils.o: src/utils.c src/utils.h +src/utils.o: src/utils.c src/utils.h src/ipc.h @echo ' CC > src/utils.o' - $(Q)$(CC) $(CFLAGS) -fPIC -c src/utils.c -fPIC -o src/utils.o + $(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/utils.c -fPIC -std=c11 -o src/utils.o src/utils.o.install: @@ -175,6 +187,10 @@ src/utils.o.clean: src/utils.o.uninstall: +src: + $(Q)mkdir -p src +man: + $(Q)mkdir -p man $(DESTDIR)$(PREFIX): @echo ' DIR > $(PREFIX)' $(Q)mkdir -p $(DESTDIR)$(PREFIX) @@ -193,12 +209,12 @@ $(DESTDIR)$(INCLUDEDIR): $(DESTDIR)$(MANDIR): @echo ' DIR > $(MANDIR)' $(Q)mkdir -p $(DESTDIR)$(MANDIR) -install: subdirs.install libipc.install src/ipc.h.install man/libipc.7.install libipc.so.install libipc.a.install src/communication.o.install src/error.o.install src/logger.o.install src/message.o.install src/usocket.o.install src/utils.o.install src/communication.o.install src/error.o.install src/logger.o.install src/message.o.install src/usocket.o.install src/utils.o.install +install: subdirs.install libipc.install src/ipc.h.install man/libipc.7.install libipc.so.install libipc.a.install src/communication.o.install src/error.o.install src/logger.o.install src/message.o.install src/network.o.install src/usocket.o.install src/utils.o.install src/communication.o.install src/error.o.install src/logger.o.install src/message.o.install src/network.o.install src/usocket.o.install src/utils.o.install @: subdirs.install: -uninstall: subdirs.uninstall libipc.uninstall src/ipc.h.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/communication.o.uninstall src/error.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/communication.o.uninstall src/error.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall +uninstall: subdirs.uninstall libipc.uninstall src/ipc.h.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/communication.o.uninstall src/error.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/network.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/communication.o.uninstall src/error.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/network.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall @: subdirs.uninstall: @@ -208,7 +224,7 @@ test: all subdirs subdirs.test subdirs.test: -clean: libipc.clean src/ipc.h.clean man/libipc.7.clean libipc.so.clean libipc.a.clean src/communication.o.clean src/error.o.clean src/logger.o.clean src/message.o.clean src/usocket.o.clean src/utils.o.clean src/communication.o.clean src/error.o.clean src/logger.o.clean src/message.o.clean src/usocket.o.clean src/utils.o.clean +clean: libipc.clean src/ipc.h.clean man/libipc.7.clean libipc.so.clean libipc.a.clean src/communication.o.clean src/error.o.clean src/logger.o.clean src/message.o.clean src/network.o.clean src/usocket.o.clean src/utils.o.clean src/communication.o.clean src/error.o.clean src/logger.o.clean src/message.o.clean src/network.o.clean src/usocket.o.clean src/utils.o.clean distclean: clean @@ -231,6 +247,7 @@ $(PACKAGE)-$(VERSION).tar.gz: distdir $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/logger.c \ $(PACKAGE)-$(VERSION)/src/message.c \ + $(PACKAGE)-$(VERSION)/src/network.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ $(PACKAGE)-$(VERSION)/src/logger.h \ @@ -250,6 +267,7 @@ $(PACKAGE)-$(VERSION).tar.xz: distdir $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/logger.c \ $(PACKAGE)-$(VERSION)/src/message.c \ + $(PACKAGE)-$(VERSION)/src/network.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ $(PACKAGE)-$(VERSION)/src/logger.h \ @@ -269,6 +287,7 @@ $(PACKAGE)-$(VERSION).tar.bz2: distdir $(PACKAGE)-$(VERSION)/src/error.c \ $(PACKAGE)-$(VERSION)/src/logger.c \ $(PACKAGE)-$(VERSION)/src/message.c \ + $(PACKAGE)-$(VERSION)/src/network.c \ $(PACKAGE)-$(VERSION)/src/usocket.c \ $(PACKAGE)-$(VERSION)/src/utils.c \ $(PACKAGE)-$(VERSION)/src/logger.h \ diff --git a/project.zsh b/project.zsh index ac69258..918d376 100644 --- a/project.zsh +++ b/project.zsh @@ -2,10 +2,13 @@ package=ipc version=0.1.0 +CFLAGS="-Wall -Wextra -g" + targets=(libipc src/ipc.h man/libipc.7) type[libipc]=library sources[libipc]="$(ls src/*.c)" +cflags[libipc]="-std=c11" type[src/ipc.h]=header diff --git a/src/communication.c b/src/communication.c index 78c58ef..0206d61 100644 --- a/src/communication.c +++ b/src/communication.c @@ -1,40 +1,41 @@ -#include "ipc.h" - -#include "utils.h" +#include #include -#include #include #include // error numbers #include #include +#include "ipc.h" +#include "utils.h" + +// FOR THE PURPOSE OF SOME EXPERIMENT +#include +#include + // print structures #include "message.h" - -#define IPC_CONNECTION_TYPE_IPC 'i' -#define IPC_CONNECTION_TYPE_EXTERNAL 'a' - -void service_path (char *path, const char *sname, int32_t index, int32_t version) +enum ipc_errors service_path (char *path, const char *sname, int32_t index, int32_t version) { - assert (path != NULL); - assert (sname != NULL); + T_R ((path == NULL), IPC_ERROR_SERVICE_PATH__NO_PATH); + T_R ((sname == NULL), IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME); memset (path, 0, PATH_MAX); - char * rundir = getenv ("IPC_RUNDIR"); - if (rundir == NULL) - rundir = RUNDIR; + char * rundir = getenv ("IPC_RUNDIR"); + if (rundir == NULL) + rundir = RUNDIR; snprintf (path, PATH_MAX-1, "%s/%s-%d-%d", rundir, sname, index, version); + + return IPC_ERROR_NONE; } -/*calculer le max filedescriptor*/ static int32_t get_max_fd (struct ipc_connection_infos *cinfos) { - int32_t i; + size_t i; int32_t max = 0; for (i = 0; i < cinfos->size; i++ ) { @@ -48,93 +49,133 @@ static int32_t get_max_fd (struct ipc_connection_infos *cinfos) enum ipc_errors ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname) { - if (env == NULL) - return IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM; + T_R ((env == NULL), IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM); + T_R ((srv == NULL), IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM); + T_R ((sname == NULL), IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM); - if (srv == NULL) - return IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM; - if (sname == NULL) - return IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM; +#if 0 + // For server init, no need for networkd evaluation - // TODO: loop over environment variables - // any IPC_NETWORK_* should be shared with the network service - // in order to route requests over any chosen protocol stack - // ex: IPC_NETWORK_AUDIO="tor://some.example.com/" - env = env; + // TODO: loop over environment variables + // any IPC_NETWORK_* should be shared with the network service + // in order to route requests over any chosen protocol stack + // ex: IPC_NETWORK_AUDIO="tor://some.example.com/" + for (size_t i = 0 ; env[i] != NULL ; i++) { + // TODO: check for every IPC_NETWORK_* environment variable + } +#endif // gets the service path - char buf [PATH_MAX]; - memset (buf, 0, PATH_MAX); - service_path (buf, sname, srv->index, srv->version); + SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); + TIPC_P_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path"); // gets the service path - if (srv->spath != NULL) { - free (srv->spath); - srv->spath = NULL; + if (srv->spath != NULL) { + free (srv->spath); + srv->spath = NULL; + } + + size_t s = strlen (buf); + + SECURE_BUFFER_HEAP_ALLOCATION_R (srv->spath, s+1, , IPC_ERROR_SERVER_INIT__MALLOC); + memcpy (srv->spath, buf, s); + srv->spath[s] = '\0'; // to be sure + + TIPC_F_RR (usock_init (&srv->fd, srv->spath), ("cannot init server %s", srv->spath) ); + + return IPC_ERROR_NONE; +} + +enum ipc_errors ipc_write_fd (int fd, const struct ipc_message *m); + +// when networkd is not working properly (or do not retrieve the service): srv->fd = 0 +enum ipc_errors ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname) +{ + T_R ((srv == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM); + T_R ((sname == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM); + + char *networkvar = getenv("IPC_NETWORK"); + if (networkvar == NULL) { + srv->fd = 0; + return IPC_ERROR_NONE; } - size_t s = strlen (buf); - srv->spath = malloc (s+1); - if (srv->spath == NULL) { - return IPC_ERROR_SERVER_INIT__MALLOC; - } - memcpy (srv->spath, buf, s); - srv->spath[s] = '\0'; // to be sure + // TODO: is there another, more interesting way to do this? + // currently, IPC_NETWORK is shared with the network service + // in order to route requests over any chosen protocol stack + // ex: IPC_NETWORK="audio tor://some.example.com/audio ;pong tls://pong.example.com/pong" - enum ipc_errors ret = usock_init (&srv->fd, srv->spath); - if (ret != IPC_ERROR_NONE) { - handle_err ("ipc_server_init", "usock_init"); - return ret; + // printf ("IPC_NETWORK: %s\n", networkvar); + + SECURE_BUFFER_DECLARATION (char, columnthensname, BUFSIZ); + columnthensname[0] = ';'; + memcpy (columnthensname +1, sname, strlen(sname)); + + if (strncmp (networkvar, sname, strlen(sname)) != 0 && strstr (networkvar, columnthensname) == NULL) { + // printf ("sname %s not found\n", sname); + srv->fd = 0; + return IPC_ERROR_NONE; + } + // printf ("(;)sname %s found\n", sname); + + // gets the service path + SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); + TIPC_P_RR (service_path (buf, "network", 0, 0), "cannot get network service path"); + + int networkdfd = 0; + + TIPC_F_R (usock_connect (&networkdfd, buf), ("cannot initiates a connection [%s]", buf) + , IPC_ERROR_CONTACT_NETWORKD__NETWORKD); + + SECURE_DECLARATION (struct ipc_message, msg); + msg.type = MSG_TYPE_NETWORK_LOOKUP; + msg.user_type = MSG_TYPE_NETWORK_LOOKUP; + + SECURE_BUFFER_DECLARATION (char, content, BUFSIZ); + snprintf (content, BUFSIZ, "%s;%s", sname, networkvar); + + msg.length = strlen (content); + msg.payload = content; + + TIPC_P_RR (ipc_write_fd (networkdfd, &msg), "cannot send a message to networkd"); + + enum ipc_errors ret = ipc_receive_fd (networkdfd, &srv->fd); + if (ret == IPC_ERROR_NONE) { + usock_close (networkdfd); } - return IPC_ERROR_NONE; + return ret; } enum ipc_errors ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname) { - // TODO: loop over environment variables - // any IPC_NETWORK_* should be shared with the network service - // in order to route requests over any chosen protocol stack - // ex: IPC_NETWORK_AUDIO="tor://some.example.com/" - env = env; - if (env == NULL) - return IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM; + T_R ((env == NULL), IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM); + T_R ((srv == NULL), IPC_ERROR_CONNECTION__NO_SERVER); + T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME); - assert (srv != NULL); - assert (sname != NULL); + TIPC_P (ipc_contact_networkd (srv, sname), "error during networkd connection"); - if (srv == NULL) { - return IPC_ERROR_CONNECTION__NO_SERVER; + // if networkd did not initiate the connection + if (srv->fd <= 0) { + // gets the service path + SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); + TIPC_P_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path"); + TIPC_F_RR (usock_connect (&srv->fd, buf), ("cannot initiates a connection [%s]", buf)); } - if (sname == NULL) { - return IPC_ERROR_CONNECTION__NO_SERVICE_NAME; - } - - // gets the service path - char buf [PATH_MAX]; - memset (buf, 0, PATH_MAX); - service_path (buf, sname, srv->index, srv->version); - - enum ipc_errors ret = usock_connect (&srv->fd, buf); - if (ret != IPC_ERROR_NONE) { - handle_err ("ipc_connection", "usock_connect ret"); - return ret; - } - return IPC_ERROR_NONE; } enum ipc_errors ipc_server_close (struct ipc_connection_info *srv) { - usock_close (srv->fd); - enum ipc_errors ret = usock_remove (srv->spath); - if (srv->spath != NULL) { - free (srv->spath); - srv->spath = NULL; - } - return ret; + usock_close (srv->fd); + enum ipc_errors ret = usock_remove (srv->spath); + if (srv->spath != NULL) { + free (srv->spath); + srv->spath = NULL; + } + return ret; } enum ipc_errors ipc_close (struct ipc_connection_info *p) @@ -144,86 +185,210 @@ enum ipc_errors ipc_close (struct ipc_connection_info *p) enum ipc_errors ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p) { - assert (srv != NULL); - assert (p != NULL); + T_R ((srv == NULL), IPC_ERROR_ACCEPT__NO_SERVICE_PARAM); + T_R ((p == NULL), IPC_ERROR_ACCEPT__NO_CLIENT_PARAM); - if (srv == NULL) { - return IPC_ERROR_ACCEPT__NO_SERVICE_PARAM; - } - - if (p == NULL) { - return IPC_ERROR_ACCEPT__NO_CLIENT_PARAM; - } - - enum ipc_errors ret = usock_accept (srv->fd, &p->fd); - if (ret != IPC_ERROR_NONE) { - handle_err ("ipc_accept", "usock_accept"); - return IPC_ERROR_ACCEPT; - } - - p->type = IPC_CONNECTION_TYPE_IPC; + TIPC_P_R (usock_accept (srv->fd, &p->fd), "cannot accept fd", IPC_ERROR_ACCEPT); + p->type = IPC_CONNECTION_TYPE_IPC; return IPC_ERROR_NONE; } +// receive then format in an ipc_message structure enum ipc_errors ipc_read (const struct ipc_connection_info *p, struct ipc_message *m) { - return ipc_message_read (p->fd, m); + T_R ((m == NULL), IPC_ERROR_READ__NO_MESSAGE_PARAM); + + char *buf = NULL; + size_t msize = IPC_MAX_MESSAGE_SIZE; + + // on error or closed recipient, the buffer already freed + TIPC_NP_RR (usock_recv (p->fd, &buf, &msize)); + TIPC_I_RR (ipc_message_format_read (m, buf, msize), if (buf != NULL) free (buf)); + + free (buf); + + return IPC_ERROR_NONE; // propagates ipc_message_format return +} + +enum ipc_errors ipc_write_fd (int fd, const struct ipc_message *m) +{ + T_R ((m == NULL), IPC_ERROR_WRITE__NO_MESSAGE_PARAM); + + char *buf = NULL; + size_t msize = 0; + ipc_message_format_write (m, &buf, &msize); + + size_t nbytes_sent = 0; + TIPC_I_RR (usock_send (fd, buf, msize, &nbytes_sent), if (buf != NULL) free (buf)); + + if (buf != NULL) { + free (buf); + } + + // what was sent != what should have been sent + T_R ((nbytes_sent != msize), IPC_ERROR_WRITE__NOT_ENOUGH_DATA); + + return IPC_ERROR_NONE; } enum ipc_errors ipc_write (const struct ipc_connection_info *p, const struct ipc_message *m) { - return ipc_message_write (p->fd, m); + return ipc_write_fd (p->fd, m); } enum ipc_errors handle_new_connection (struct ipc_connection_info *cinfo - , struct ipc_connection_infos *cinfos - , struct ipc_connection_info **new_client) + , struct ipc_connection_infos *cinfos + , struct ipc_connection_info **new_client) { - if (cinfo == NULL) { - return IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM; - } + T_R ((cinfo == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM); + T_R ((cinfos == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM); - if (cinfos == NULL) { - return IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM; - } + SECURE_BUFFER_HEAP_ALLOCATION_R (*new_client, sizeof(struct ipc_connection_info), , IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC); - *new_client = malloc (sizeof(struct ipc_connection_info)); - if (*new_client == NULL) { - return IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC; - } - memset(*new_client, 0, sizeof(struct ipc_connection_info)); + TIPC_P_RR (ipc_accept (cinfo, *new_client), "cannot accept the client during handle_new_connection"); + TIPC_P_RR (ipc_add (cinfos, *new_client), "cannot add the new accepted client"); - enum ipc_errors ret = ipc_accept (cinfo, *new_client); - if (ret != IPC_ERROR_NONE) { - return ret; - } - - ret = ipc_add (cinfos, *new_client); - if (ret != IPC_ERROR_NONE) { - return ret; - } - - return IPC_ERROR_NONE; + return IPC_ERROR_NONE; } -enum ipc_errors ipc_wait_event (struct ipc_connection_infos *cinfos - , struct ipc_connection_info *cinfo // NULL for clients - , struct ipc_event *event) +// new connection from a client +enum ipc_errors handle_connection (struct ipc_event *event, struct ipc_connection_infos *cinfos, struct ipc_connection_info *cinfo) { - assert (cinfos != NULL); + // connection + struct ipc_connection_info *new_client = NULL; - if (cinfos == NULL) { - return IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM; + TIPC_P_RR (handle_new_connection (cinfo, cinfos, &new_client), "cannot add new client"); + + IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client); + return IPC_ERROR_NONE; +} + +// new message +enum ipc_errors handle_message (struct ipc_event *event + , struct ipc_connection_infos *cinfos + , struct ipc_connection_info *pc + , struct ipc_switchings *switchdb) +{ + // if the socket is associated to another one for networkd + // read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch + if (switchdb != NULL) { + int talkingfd = pc->fd; + int correspondingfd = ipc_switching_get (switchdb, talkingfd); + if (correspondingfd != -1) { + char *buf = NULL; + size_t msize = 0; + + TIPC_T_P_I_R ( + /* function to test */ usock_recv (talkingfd, &buf, &msize) + , /* error condition */ ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT + , /* to say on error */ "error while receiving message from client" + , /* to do on error */ if (buf != NULL) free (buf) ; + IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc) + , /* return function */ return (ret)); + + /** TODO: there is a message, send it to the corresponding fd **/ + if (msize > 0) { + size_t nbytes_sent = 0; + TIPC_I_RR (usock_send (correspondingfd, buf, msize, &nbytes_sent), if (buf != NULL) free (buf)); + + if (nbytes_sent != msize) { + LOG_ERROR ("wrote not enough data from %d to fd %d", talkingfd, correspondingfd); + IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc); + return IPC_ERROR_NONE; // FIXME: return something else, maybe? + } + + LOG_DEBUG ("received a message on fd %d => switch to fd %d", talkingfd, correspondingfd); + + if (buf != NULL) + free (buf); + + // everything is OK: inform networkd of a successful transfer + IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, NULL, pc); + return IPC_ERROR_NONE; + } + else if (msize == 0) { + int delfd; + + delfd = ipc_switching_del (switchdb, talkingfd); + if (delfd >= 0) { + close (delfd); + ipc_del_fd (cinfos, delfd); + } + + close (talkingfd); + ipc_del_fd (cinfos, talkingfd); + + if (delfd >= 0) { + LOG_DEBUG ("disconnection of %d (and related fd %d)", talkingfd, delfd); + } + else { + LOG_DEBUG ("disconnection of %d", talkingfd); + } + + IPC_EVENT_SET(event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc); + return IPC_ERROR_CLOSED_RECIPIENT; + } + } } - if (event == NULL) { - return IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM; + // no treatment of the socket if external socket + if (pc->type == IPC_CONNECTION_TYPE_EXTERNAL) { + IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, NULL, pc); + return IPC_ERROR_NONE; } - IPC_EVENT_CLEAN(event); + // listen to what they have to say (disconnection or message) + // then add a client to `event`, the ipc_event structure + enum ipc_errors ret; + struct ipc_message *m = NULL; - int32_t i, j; + SECURE_BUFFER_HEAP_ALLOCATION_R (m, sizeof(struct ipc_message), , IPC_ERROR_NOT_ENOUGH_MEMORY); + + // current talking client + ret = ipc_read (pc, m); + if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) { + enum ipc_errors rvalue = ret; // store the final return value + ipc_message_empty (m); + free (m); + + // if there is a problem, just remove the client + TIPC_P (ipc_close (pc), "cannot close a connection in handle_message"); + TIPC_P (ipc_del (cinfos, pc), "cannot delete a connection in handle_message"); + + IPC_EVENT_SET(event, IPC_EVENT_TYPE_ERROR, NULL, pc); + return rvalue; + } + + // disconnection: close the client then delete it from cinfos + if (ret == IPC_ERROR_CLOSED_RECIPIENT) { + TIPC_P (ipc_close (pc), "cannot close a connection on closed recipient in handle_message"); + TIPC_P (ipc_del (cinfos, pc), "cannot delete a connection on closed recipient in handle_message"); + + ipc_message_empty (m); + free (m); + + IPC_EVENT_SET(event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc); + + // warning: do not forget to free the ipc_client structure + return IPC_ERROR_NONE; + } + + IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc); + return IPC_ERROR_NONE; +} + +enum ipc_errors ipc_wait_event_networkd (struct ipc_connection_infos *cinfos + , struct ipc_connection_info *cinfo // NULL for clients + , struct ipc_event *event + , struct ipc_switchings *switchdb) +{ + T_R ((cinfos == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM); + T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM); + + IPC_EVENT_CLEAN(event); + + size_t i, j; /* master file descriptor list */ fd_set master; fd_set readf; @@ -238,141 +403,64 @@ enum ipc_errors ipc_wait_event (struct ipc_connection_infos *cinfos /* listening socket descriptor */ int32_t listener; - if (cinfo != NULL) { - listener = cinfo->fd; + if (cinfo != NULL) { + listener = cinfo->fd; - /* add the listener to the master set */ - FD_SET(listener, &master); + /* add the listener to the master set */ + FD_SET(listener, &master); - // if listener is max fd - if (fdmax < listener) - fdmax = listener; - } + // if listener is max fd + if (fdmax < listener) + fdmax = listener; + } for (i=0; i < cinfos->size; i++) { FD_SET(cinfos->cinfos[i]->fd, &master); } - readf = master; - if(select(fdmax+1, &readf, NULL, NULL, NULL) == -1) { - perror("select"); - return IPC_ERROR_WAIT_EVENT__SELECT; - } + readf = master; + T_PERROR_R ((select(fdmax+1, &readf, NULL, NULL, NULL) == -1), "select", IPC_ERROR_WAIT_EVENT__SELECT); - for (i = 0; i <= fdmax; i++) { - if (FD_ISSET(i, &readf)) { - if (cinfo != NULL && i == listener) { - // connection - struct ipc_connection_info *new_client = NULL; - enum ipc_errors ret = handle_new_connection (cinfo, cinfos, &new_client); - if (ret != IPC_ERROR_NONE) { - // TODO: quit the program - return ret; - } - IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client); - return IPC_ERROR_NONE; - } else { - for(j = 0; j < cinfos->size; j++) { - if(i == cinfos->cinfos[j]->fd ) { + for (i = 0; i <= (size_t) fdmax; i++) { + if (FD_ISSET(i, &readf)) { + if (cinfo != NULL && i == (size_t) listener) { + return handle_connection (event, cinfos, cinfo); + } else { + for(j = 0; j < cinfos->size; j++) { + if(i == (size_t) cinfos->cinfos[j]->fd ) { + return handle_message (event, cinfos, cinfos->cinfos[j], switchdb); + } + } + } + } + } - struct ipc_connection_info *pc = cinfos->cinfos[j]; + return IPC_ERROR_NONE; +} - // no treatment of the socket if external socket - if (pc->type == IPC_CONNECTION_TYPE_EXTERNAL) { - IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, NULL, pc); - return IPC_ERROR_NONE; - } - - // listen to what they have to say (disconnection or message) - // then add a client to `event`, the ipc_event structure - enum ipc_errors ret; - struct ipc_message *m = NULL; - m = malloc (sizeof(struct ipc_message)); - if (m == NULL) { - return IPC_ERROR_NOT_ENOUGH_MEMORY; - } - memset (m, 0, sizeof (struct ipc_message)); - - // current talking client - ret = ipc_read (pc, m); - if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) { - handle_err ("ipc_wait_event", "ipc_read"); - ipc_message_empty (m); - free (m); - - // if there is a problem, just remove the client - ret = ipc_close (pc); - if (ret != IPC_ERROR_NONE) { - handle_err( "ipc_wait_event", "ipc_close"); - } - - ret = ipc_del (cinfos, pc); - if (ret != IPC_ERROR_NONE) { - handle_err( "ipc_wait_event", "ipc_del"); - } - - IPC_EVENT_SET(event, IPC_EVENT_TYPE_ERROR, NULL, pc); - return ret; - } - - // disconnection: close the client then delete it from cinfos - if (ret == IPC_ERROR_CLOSED_RECIPIENT) { - ret = ipc_close (pc); - if (ret != IPC_ERROR_NONE) { - handle_err( "ipc_wait_event", "ipc_close"); - } - - ret = ipc_del (cinfos, pc); - if (ret != IPC_ERROR_NONE) { - handle_err( "ipc_wait_event", "ipc_del"); - } - ipc_message_empty (m); - free (m); - - IPC_EVENT_SET(event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc); - - // warning: do not forget to free the ipc_client structure - return IPC_ERROR_NONE; - } - - IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc); - return IPC_ERROR_NONE; - } - } - } - } - } - - return IPC_ERROR_NONE; +enum ipc_errors ipc_wait_event (struct ipc_connection_infos *cinfos + , struct ipc_connection_info *cinfo // NULL for clients + , struct ipc_event *event) +{ + return ipc_wait_event_networkd (cinfos, cinfo, event, NULL); } // store and remove only pointers on allocated structures enum ipc_errors ipc_add (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p) { - assert(cinfos != NULL); - assert(p != NULL); - - if (cinfos == NULL) { - return IPC_ERROR_ADD__NO_PARAM_CLIENTS; - } - - if (p == NULL) { - return IPC_ERROR_ADD__NO_PARAM_CLIENT; - } + T_R ((cinfos == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS); + T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT); cinfos->size++; - if (cinfos->size == 1 && cinfos->cinfos == NULL) { - // first allocation - cinfos->cinfos = malloc (sizeof(struct ipc_connection_info)); - } - else { - cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * cinfos->size); - } - - - if (cinfos->cinfos == NULL) { - return IPC_ERROR_ADD__EMPTY_LIST; + if (cinfos->size == 1 && cinfos->cinfos == NULL) { + // first allocation + SECURE_BUFFER_HEAP_ALLOCATION_R (cinfos->cinfos, sizeof(struct ipc_connection_info), , IPC_ERROR_ADD__MALLOC); } + else { + cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * cinfos->size); + } + + T_R ((cinfos->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST); cinfos->cinfos[cinfos->size - 1] = p; return IPC_ERROR_NONE; @@ -380,25 +468,14 @@ enum ipc_errors ipc_add (struct ipc_connection_infos *cinfos, struct ipc_connect enum ipc_errors ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p) { - assert(cinfos != NULL); - assert(p != NULL); + T_R ((cinfos == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM); + T_R ((p == NULL), IPC_ERROR_DEL__NO_CLIENT_PARAM); + T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL__EMPTY_LIST); - if (cinfos == NULL) { - return IPC_ERROR_DEL__NO_CLIENTS_PARAM; - } - - if (p == NULL) { - return IPC_ERROR_DEL__NO_CLIENT_PARAM; - } - - if (cinfos->cinfos == NULL) { - return IPC_ERROR_DEL__EMPTY_LIST; - } - - int32_t i; + size_t i; for (i = 0; i < cinfos->size; i++) { if (cinfos->cinfos[i] == p) { - // TODO: possible memory leak if the ipc_connection_info is not free'ed + // TODO: possible memory leak if the ipc_connection_info is not free'ed cinfos->cinfos[i] = cinfos->cinfos[cinfos->size-1]; cinfos->size--; if (cinfos->size == 0) { @@ -419,12 +496,25 @@ enum ipc_errors ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connect return IPC_ERROR_DEL__CANNOT_FIND_CLIENT; } +void ipc_connections_close (struct ipc_connection_infos *cinfos) +{ + if (cinfos->cinfos != NULL) { + for (size_t i = 0; i < cinfos->size ; i++) { + ipc_close (cinfos->cinfos[i]); + free (cinfos->cinfos[i]); + } + free (cinfos->cinfos); + cinfos->cinfos = NULL; + } + cinfos->size = 0; +} + void ipc_connections_free (struct ipc_connection_infos *cinfos) { if (cinfos->cinfos != NULL) { - for (size_t i = 0; i < cinfos->size ; i++) { - free (cinfos->cinfos[i]); - } + for (size_t i = 0; i < cinfos->size ; i++) { + free (cinfos->cinfos[i]); + } free (cinfos->cinfos); cinfos->cinfos = NULL; } @@ -433,15 +523,11 @@ void ipc_connections_free (struct ipc_connection_infos *cinfos) struct ipc_connection_info * ipc_connection_copy (const struct ipc_connection_info *p) { - if (p == NULL) - return NULL; + T_R ((p == NULL), NULL); - struct ipc_connection_info * copy = malloc (sizeof(struct ipc_connection_info)); - - if (copy == NULL) - return NULL; - - memset (copy, 0, sizeof (struct ipc_connection_info)); + struct ipc_connection_info * copy = NULL; + + SECURE_BUFFER_HEAP_ALLOCATION_R (copy, sizeof(struct ipc_connection_info), , NULL); memcpy (copy, p, sizeof (struct ipc_connection_info)); return copy; @@ -454,64 +540,49 @@ int8_t ipc_connection_eq (const struct ipc_connection_info *p1, const struct ipc // create the client service structure enum ipc_errors ipc_connection_gen (struct ipc_connection_info *cinfo - , uint32_t index, uint32_t version, int fd, char type) + , uint32_t index, uint32_t version, int fd, char type) { - if (cinfo == NULL) { - return IPC_ERROR_CONNECTION_GEN__NO_CINFO; - } + T_R ((cinfo == NULL), IPC_ERROR_CONNECTION_GEN__NO_CINFO); - cinfo->type = type; + cinfo->type = type; cinfo->version = version; cinfo->index = index; - cinfo->fd = fd; + cinfo->fd = fd; - return IPC_ERROR_NONE; + return IPC_ERROR_NONE; } // add an arbitrary file descriptor to read enum ipc_errors ipc_add_fd (struct ipc_connection_infos *cinfos, int fd) { - if (cinfos == NULL) { - return IPC_ERROR_ADD_FD__NO_PARAM_CINFOS; - } + T_R ((cinfos == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS); - struct ipc_connection_info *cinfo = NULL; + struct ipc_connection_info *cinfo = NULL; - cinfo = malloc (sizeof(struct ipc_connection_info)); - if (cinfo == NULL) { - return IPC_ERROR_NOT_ENOUGH_MEMORY; - } - memset (cinfo, 0, sizeof(struct ipc_connection_info)); + SECURE_BUFFER_HEAP_ALLOCATION_R (cinfo, sizeof(struct ipc_connection_info), , IPC_ERROR_NOT_ENOUGH_MEMORY); - enum ipc_errors ret; - ipc_connection_gen (cinfo, 0, 0, fd, IPC_CONNECTION_TYPE_EXTERNAL); + ipc_connection_gen (cinfo, 0, 0, fd, IPC_CONNECTION_TYPE_EXTERNAL); - return ipc_add (cinfos, cinfo); + return ipc_add (cinfos, cinfo); } // remove a connection from its file descriptor enum ipc_errors ipc_del_fd (struct ipc_connection_infos *cinfos, int fd) { - assert(cinfos != NULL); - if (cinfos == NULL) { - return IPC_ERROR_DEL_FD__NO_PARAM_CINFOS; - } + T_R ((cinfos == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS); + T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST); - if (cinfos->cinfos == NULL) { - return IPC_ERROR_DEL_FD__EMPTY_LIST; - } - - int32_t i; + size_t i; for (i = 0; i < cinfos->size; i++) { if (cinfos->cinfos[i]->fd == fd) { - free (cinfos->cinfos[i]); + free (cinfos->cinfos[i]); cinfos->size--; if (cinfos->size == 0) { - // free cinfos->cinfos + // free cinfos->cinfos ipc_connections_free (cinfos); } else { - cinfos->cinfos[i] = cinfos->cinfos[cinfos->size]; + cinfos->cinfos[i] = cinfos->cinfos[cinfos->size]; cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * cinfos->size); if (cinfos->cinfos == NULL) { @@ -528,26 +599,16 @@ enum ipc_errors ipc_del_fd (struct ipc_connection_infos *cinfos, int fd) void ipc_connection_print (struct ipc_connection_info *cinfo) { - if (cinfo == NULL) { - return; - } + T_R ((cinfo == NULL), ); - printf ("fd %d: index %d, version %d, type %c" - , cinfo->fd, cinfo->index, cinfo->version, cinfo->type); - - if (cinfo->spath != NULL) { - printf (", path %s\n", cinfo->spath); - } - else { - printf ("\n"); - } + LOG_DEBUG ("fd %d: index %d, version %d, type %c, path %s" + , cinfo->fd, cinfo->index, cinfo->version, cinfo->type + , (cinfo->spath == NULL) ? "-" : cinfo->spath); } void ipc_connections_print (struct ipc_connection_infos *cinfos) { - int32_t i; - for (i = 0; i < cinfos->size; i++) { - printf("[%d] : ", i); + for (size_t i = 0; i < cinfos->size; i++) { ipc_connection_print(cinfos->cinfos[i]); } } diff --git a/src/error.c b/src/error.c index 553ea97..5a4d14e 100644 --- a/src/error.c +++ b/src/error.c @@ -10,102 +10,113 @@ struct ipc_errors_verbose { static struct ipc_errors_verbose ipc_errors_verbose [] = { /* general errors */ - IPC_ERROR_NONE, "no error" - , IPC_ERROR_NOT_ENOUGH_MEMORY, "not enough memory" - , IPC_ERROR_CLOSED_RECIPIENT, "closed recipient" + { IPC_ERROR_NONE, "no error" } + , { IPC_ERROR_NOT_ENOUGH_MEMORY, "not enough memory" } + , { IPC_ERROR_CLOSED_RECIPIENT, "closed recipient" } - , IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM, "ipc_server_init: no environment param" - , IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM, "ipc_server_init: no service param" - , IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM, "ipc_server_init: no server name param" - , IPC_ERROR_SERVER_INIT__MALLOC, "ipc_server_init: error on malloc function" + , { IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM, "ipc_server_init: no environment param" } + , { IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM, "ipc_server_init: no service param" } + , { IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM, "ipc_server_init: no server name param" } + , { IPC_ERROR_SERVER_INIT__MALLOC, "ipc_server_init: error on malloc function" } - , IPC_ERROR_CONNECTION__NO_SERVER, "ipc_connection: no server parameter" - , IPC_ERROR_CONNECTION__NO_SERVICE_NAME, "ipc_connection: no service name parameter" - , IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM, "ipc_connection: no environment param" - , IPC_ERROR_USOCK_CONNECT__CONNECT, "ipc_connection: error on the connect function" + , { IPC_ERROR_CONNECTION__NO_SERVER, "ipc_connection: no server parameter" } + , { IPC_ERROR_CONNECTION__NO_SERVICE_NAME, "ipc_connection: no service name parameter" } + , { IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM, "ipc_connection: no environment param" } + , { IPC_ERROR_USOCK_CONNECT__CONNECT, "ipc_connection: error on the connect function" } - , IPC_ERROR_CONNECTION_GEN__NO_CINFO, "ipc_connection_gen: no cinfo" + , { IPC_ERROR_CONNECTION_GEN__NO_CINFO, "ipc_connection_gen: no cinfo" } - , IPC_ERROR_ACCEPT__NO_SERVICE_PARAM, "ipc_accept: no service param" - , IPC_ERROR_ACCEPT__NO_CLIENT_PARAM, "ipc_accept: no client param" - , IPC_ERROR_ACCEPT, "ipc_accept: error on accept function" + , { IPC_ERROR_ACCEPT__NO_SERVICE_PARAM, "ipc_accept: no service param" } + , { IPC_ERROR_ACCEPT__NO_CLIENT_PARAM, "ipc_accept: no client param" } + , { IPC_ERROR_ACCEPT, "ipc_accept: error on accept function" } - , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM, "ipc_handle_new_connection: no cinfo param" - , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM, "ipc_handle_new_connection: no cinfos param" + , { IPC_ERROR_RECEIVE_FD__RECVMSG, "ipc_receive_fd: recvmsg function" } + , { IPC_ERROR_RECEIVE_FD__NO_PARAM_FD, "ipc_receive_fd: no fd param" } + , { IPC_ERROR_PROVIDE_FD__SENDMSG, "ipc_provide_fd: sendmsg function" } - , IPC_ERROR_WAIT_EVENT__SELECT, "ipc_wait_event: error on the select function" - , IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM, "ipc_wait_event: no clients param" - , IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM, "ipc_wait_event: no event param" + , { IPC_ERROR_WRITE__NO_MESSAGE_PARAM, "ipc_write: no message param" } + , { IPC_ERROR_WRITE__NOT_ENOUGH_DATA, "ipc_write: no enough data sent" } + , { IPC_ERROR_READ__NO_MESSAGE_PARAM, "ipc_read: no message param" } - , IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC, "ipc_handle_new_connection: error on malloc function" + , { IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM, "ipc_handle_new_connection: no cinfo param" } + , { IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM, "ipc_handle_new_connection: no cinfos param" } - , IPC_ERROR_ADD__EMPTY_LIST, "ipc_clients_add: empty list: realloc failed" - , IPC_ERROR_ADD__NO_PARAM_CLIENTS, "ipc_clients_add: no param client list" - , IPC_ERROR_ADD__NO_PARAM_CLIENT, "ipc_clients_add: no param client" + , { IPC_ERROR_WAIT_EVENT__SELECT, "ipc_wait_event: error on the select function" } + , { IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM, "ipc_wait_event: no clients param" } + , { IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM, "ipc_wait_event: no event param" } - , IPC_ERROR_ADD_FD__NO_PARAM_CINFOS, "ipc_add_fd: no cinfos param" - , IPC_ERROR_ADD_FD__EMPTY_LIST, "ipc_add_fd: empty list after realloc (memory problem)" + , { IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM, "ipc_contact_networkd: no service name param"} + , { IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM, "ipc_contact_networkd: no server param"} + , { IPC_ERROR_CONTACT_NETWORKD__NETWORKD, "ipc_contact_networkd: cannot retrieve fd"} - , IPC_ERROR_DEL_FD__NO_PARAM_CINFOS, "ipc_del_fd: no cinfos param" - , IPC_ERROR_DEL_FD__EMPTIED_LIST, "ipc_del_fd: empty list after realloc (memory problem)" - , IPC_ERROR_DEL_FD__EMPTY_LIST, "ipc_del_fd: empty list" - , IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT, "ipc_del_fd: cannot find user" + , { IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC, "ipc_handle_new_connection: error on malloc function" } + + , { IPC_ERROR_ADD__MALLOC, "ipc_add: first memory allocation failed" } + , { IPC_ERROR_ADD__EMPTY_LIST, "ipc_add: empty list: realloc failed" } + , { IPC_ERROR_ADD__NO_PARAM_CLIENTS, "ipc_add: no param client list" } + , { IPC_ERROR_ADD__NO_PARAM_CLIENT, "ipc_add: no param client" } + + , { IPC_ERROR_ADD_FD__NO_PARAM_CINFOS, "ipc_add_fd: no cinfos param" } + , { IPC_ERROR_ADD_FD__EMPTY_LIST, "ipc_add_fd: empty list after realloc (memory problem)" } + + , { IPC_ERROR_DEL_FD__NO_PARAM_CINFOS, "ipc_del_fd: no cinfos param" } + , { IPC_ERROR_DEL_FD__EMPTIED_LIST, "ipc_del_fd: empty list after realloc (memory problem)" } + , { IPC_ERROR_DEL_FD__EMPTY_LIST, "ipc_del_fd: empty list" } + , { IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT, "ipc_del_fd: cannot find user" } + + , { IPC_ERROR_DEL__EMPTY_LIST, "ipc_del: empty list" } + , { IPC_ERROR_DEL__EMPTIED_LIST, "ipc_del: cannot realloc" } + , { IPC_ERROR_DEL__CANNOT_FIND_CLIENT, "ipc_del: cannot find client" } + , { IPC_ERROR_DEL__NO_CLIENTS_PARAM, "ipc_del: no clients param" } + , { IPC_ERROR_DEL__NO_CLIENT_PARAM, "ipc_del: no client param" } - , IPC_ERROR_DEL__EMPTY_LIST, "ipc_clients_del: empty list" - , IPC_ERROR_DEL__EMPTIED_LIST, "ipc_clients_del: cannot realloc" - , IPC_ERROR_DEL__CANNOT_FIND_CLIENT, "ipc_clients_del: cannot find client" - , IPC_ERROR_DEL__NO_CLIENTS_PARAM, "ipc_clients_del: no clients param" - , IPC_ERROR_DEL__NO_CLIENT_PARAM, "ipc_clients_del: no client param" - /* unix socket */ - , IPC_ERROR_USOCK_SEND, "usock_send: cannot send message" + , { IPC_ERROR_USOCK_SEND, "usock_send: cannot send message" } - , IPC_ERROR_USOCK_CONNECT__SOCKET, "usock_connect: error on socket function" - , IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR, "usock_connect: wrong file descriptor" - , IPC_ERROR_USOCK_CONNECT__EMPTY_PATH, "usock_connect: empty path" + , { IPC_ERROR_USOCK_CONNECT__SOCKET, "usock_connect: error on socket function" } + , { IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR, "usock_connect: wrong file descriptor" } + , { IPC_ERROR_USOCK_CONNECT__EMPTY_PATH, "usock_connect: empty path" } - , IPC_ERROR_USOCK_CLOSE, "usock_close: close function" + , { IPC_ERROR_USOCK_CLOSE, "usock_close: close function" } - , IPC_ERROR_USOCK_REMOVE__UNLINK, "usock_remove: unlink function" - , IPC_ERROR_USOCK_REMOVE__NO_FILE, "usock_remove: file not found" + , { IPC_ERROR_USOCK_REMOVE__UNLINK, "usock_remove: unlink function" } + , { IPC_ERROR_USOCK_REMOVE__NO_FILE, "usock_remove: file not found" } - , IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR, "usock_init: no file descriptor" - , IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR, "usock_init: wrong file descriptor" - , IPC_ERROR_USOCK_INIT__EMPTY_PATH, "usock_init: empty path" - , IPC_ERROR_USOCK_INIT__BIND, "usock_init: error on bind function" - , IPC_ERROR_USOCK_INIT__LISTEN, "usock_init: error on listen function" + , { IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR, "usock_init: no file descriptor" } + , { IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR, "usock_init: wrong file descriptor" } + , { IPC_ERROR_USOCK_INIT__EMPTY_PATH, "usock_init: empty path" } + , { IPC_ERROR_USOCK_INIT__BIND, "usock_init: error on bind function" } + , { IPC_ERROR_USOCK_INIT__LISTEN, "usock_init: error on listen function" } - , IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR, "ipc_usock_accept: no path file descriptor" - , IPC_ERROR_USOCK_ACCEPT, "ipc_usock_accept: error on accept function" + , { IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR, "ipc_usock_accept: no path file descriptor" } + , { IPC_ERROR_USOCK_ACCEPT, "ipc_usock_accept: error on accept function" } - , IPC_ERROR_USOCK_RECV__NO_BUFFER, "ipc_usock_recv: no buffer in usock_recv" - , IPC_ERROR_USOCK_RECV__NO_LENGTH, "ipc_usock_recv: no length in usock_recv" - , IPC_ERROR_USOCK_RECV, "ipc_usock_recv: cannot receive message in usock_recv" + , { IPC_ERROR_USOCK_RECV__NO_BUFFER, "ipc_usock_recv: no buffer in usock_recv" } + , { IPC_ERROR_USOCK_RECV__NO_LENGTH, "ipc_usock_recv: no length in usock_recv" } + , { IPC_ERROR_USOCK_RECV, "ipc_usock_recv: cannot receive message in usock_recv" } + , { IPC_ERROR_USOCK_RECV__MESSAGE_SIZE, "ipc_usock_recv: message length > maximum allowed" } /* message function errors */ - , IPC_ERROR_MESSAGE_NEW__NO_MESSAGE_PARAM, "ipc_message_new: no message param" - , IPC_ERROR_MESSAGE_READ__NO_MESSAGE_PARAM, "ipc_message_read: no message param" + , { IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH, "ipc_message_write: message is longer than accepted" } - , IPC_ERROR_MESSAGE_WRITE__NO_MESSAGE_PARAM, "ipc_message_write: no message param" - , IPC_ERROR_MESSAGE_WRITE__NOT_ENOUGH_DATA, "ipc_message_write: no enough data sent" + , { IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM, "ipc_message_format: no message param" } + , { IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS, "ipc_message_format: inconsistent params" } + , { IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE, "ipc_message_format: length param > maximum allowed" } + , { IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE, "ipc_message_format: read message size > maximum allowed" } - , IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM, "ipc_message_format: no message param" - , IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS, "ipc_message_format: inconsistent params" - , IPC_ERROR_MESSAGE_FORMAT__LENGTH, "ipc_message_format: length param > maximum allowed" + , { IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE, "ipc_message_format_write: empty message" } + , { IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE, "ipc_message_format_write: empty message size" } + , { IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER, "ipc_message_format_write: empty buffer" } - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE, "ipc_message_format_write: empty message" - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE, "ipc_message_format_write: empty message size" - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER, "ipc_message_format_write: empty buffer" + , { IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE, "ipc_message_format_read: empty message" } + , { IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER, "ipc_message_format_read: empty buffer" } + , { IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE, "ipc_message_format_read: message size > maximum allowed" } - , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE, "ipc_message_format_read: empty message" - , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER, "ipc_message_format_read: empty buffer" - , IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE, "ipc_message_format_read: message size > maximum allowed" - - , IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST, "ipc_message_empty: empty message list" + , { IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST, "ipc_message_empty: empty message list" } }; const char * ipc_errors_get (enum ipc_errors e) diff --git a/src/ipc.h b/src/ipc.h index e43326b..8ad07bb 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -9,133 +9,206 @@ #include // error numbers #include +/*** + * global defaults + **/ + #define RUNDIR "/run/ipc/" #define PATH_MAX 4096 #define IPC_HEADER_SIZE 6 #define IPC_MAX_MESSAGE_SIZE 8000000-IPC_HEADER_SIZE -// #define IPC_MAX_MESSAGE_SIZE 100-IPC_HEADER_SIZE -// #include "queue.h" - -#define SECURE_DECLARATION(t,v) t v; memset(&v,0,sizeof(t)); #define IPC_VERSION 1 +#if ! defined(IPC_WITHOUT_ERRORS) && ! defined(IPC_WITH_ERRORS) +#define IPC_WITH_ERRORS 2 +#endif +#define IPC_WITH_UNIX_SOCKETS + +#ifdef IPC_WITH_UNIX_SOCKETS +#include "usocket.h" +#endif + +/*** + * grooming macros + **/ + +#define SECURE_DECLARATION(t,v) t v; memset(&v,0,sizeof(t)); +#define SECURE_BUFFER_DECLARATION(type,name,size) type name[size]; memset(&name, 0, sizeof(type) * size); +#define SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr,r) { p = malloc (len); if (p == NULL) { instr; r; } ; memset(p, 0, len); } +#define SECURE_BUFFER_HEAP_ALLOCATION_R(p,len,instr,r) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, return r ) +#define SECURE_BUFFER_HEAP_ALLOCATION_Q(p,len,instr,r) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, exit(r)) + +#if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 +// print error string +#define PRINT_ERR(code) const char *estr = ipc_errors_get (code); LOG_ERROR ("%s", estr); +#define PRINT_ERR_STR(code,err) { const char *estr = ipc_errors_get (code); LOG_ERROR ("%s - %s", err, estr); } +#else +#define PRINT_ERR(code) +#define PRINT_ERR_STR(code,err) +#endif + +// Test macros, requiring the variable `enum ipc_errors ret` + +// one macro to rule them all! +// 1. function to test +// 2. Test IPC error based (test itself) +// 3. Print error (then ipc-error message) +// 4. Instructions to exec on failure +// 5. Return something +#define TIPC_T_P_I_R(f, t, err, instr, r) { enum ipc_errors ret = f;\ + if (t) {\ + PRINT_ERR_STR(ret, err); \ + instr;\ + r;\ + } } + +// P = print somehting with LOG_ERROR +// NP = no LOG_ERROR print +// R = return r param +// RR = return "ret" variable +// RV = return void +// Q = quit +// I = additionnal instructions before returning on error + +#define TIPC_P_I_R(f, t, err, instr, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, instr, return r) +#define TIPC_P_I_Q(f, t, err, instr, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, instr, quit(r)) +#define TIPC_P_Q(f, err,r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, ;, exit(r)) +#define TIPC_P_R(f, err,r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, ;, return r) +#define TIPC_P_RR(f, err) TIPC_P_R(f,err,ret) +#define TIPC_F_RR(f, format) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", LOG_ERROR format ;, return ret) +#define TIPC_F_Q(f, format, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", LOG_ERROR format ;, exit(r)) +#define TIPC_F_R(f, format, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", LOG_ERROR format ;, return r) +#define TIPC_P_RV(f, err) TIPC_P_R(f,err,;) +#define TIPC_P(f, err) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, ;, ;) +#define TIPC_T_I_P_Q(f,t,instr,err,r) TIPC_T_P_I_R(f, t, err, instr, exit(r)) +#define TIPC_T_I_RR(f,t,instr) TIPC_T_P_I_R(f, t, "", instr, return ret) +#define TIPC_I_RR(f,instr) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", instr, return ret) +#define TIPC_RR(f) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", ;, return ret) +#define TIPC_NP_RR(f) { enum ipc_errors ret = f; if (ret != IPC_ERROR_NONE) { return ret; } } + +// Tests macros, do not require `enum ipc_errors ret` variable +// test => return error code +#define T_R(t,r) if t { return r; } +// test => perror, formatted message then return (for system functions) +#define T_PERROR_F_R(t,m,fmt,r) if t { perror(m); LOG_ERROR fmt; return r; } +// test => perror then return (for system functions) +#define T_PERROR_R(t,m,r) if t { perror(m); return r; } +// test => perror then exit (for system functions) +#define T_PERROR_Q(t,m,r) if t { perror(m); exit(r); } + + +// Switch cases macros +// print on error +#define ERROR_CASE(e,f,m) case e : { LOG_ERROR ("function %s: %s", f, m); } break; + + +/*** + * structures and enumerations + **/ enum msg_types { - MSG_TYPE_SERVER_CLOSE = 0 - , MSG_TYPE_ERR - , MSG_TYPE_DATA + MSG_TYPE_SERVER_CLOSE = 0 + , MSG_TYPE_ERR = 1 + , MSG_TYPE_DATA = 2 + , MSG_TYPE_NETWORK_LOOKUP = 3 } message_types; enum ipc_event_type { - IPC_EVENT_TYPE_NOT_SET - , IPC_EVENT_TYPE_ERROR - - , IPC_EVENT_TYPE_EXTRA_SOCKET - - , IPC_EVENT_TYPE_CONNECTION - , IPC_EVENT_TYPE_DISCONNECTION - , IPC_EVENT_TYPE_MESSAGE + IPC_EVENT_TYPE_NOT_SET = 0 + , IPC_EVENT_TYPE_ERROR = 1 + , IPC_EVENT_TYPE_EXTRA_SOCKET = 2 + , IPC_EVENT_TYPE_SWITCH = 3 + , IPC_EVENT_TYPE_CONNECTION = 4 + , IPC_EVENT_TYPE_DISCONNECTION = 5 + , IPC_EVENT_TYPE_MESSAGE = 6 + , IPC_EVENT_TYPE_LOOKUP = 7 }; enum ipc_errors { + /* general errors */ - IPC_ERROR_NONE - , IPC_ERROR_NOT_ENOUGH_MEMORY - , IPC_ERROR_CLOSED_RECIPIENT - - , IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM - , IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM - , IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM - , IPC_ERROR_SERVER_INIT__MALLOC - - , IPC_ERROR_CONNECTION__NO_SERVER - , IPC_ERROR_CONNECTION__NO_SERVICE_NAME - , IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM - - , IPC_ERROR_CONNECTION_GEN__NO_CINFO - - , IPC_ERROR_ACCEPT__NO_SERVICE_PARAM - , IPC_ERROR_ACCEPT__NO_CLIENT_PARAM - , IPC_ERROR_ACCEPT - - , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM - , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM - - , IPC_ERROR_WAIT_EVENT__SELECT - , IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM - , IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM - - , IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC - - , IPC_ERROR_ADD__EMPTY_LIST - , IPC_ERROR_ADD__NO_PARAM_CLIENTS - , IPC_ERROR_ADD__NO_PARAM_CLIENT - - , IPC_ERROR_ADD_FD__NO_PARAM_CINFOS - , IPC_ERROR_ADD_FD__EMPTY_LIST - - , IPC_ERROR_DEL_FD__NO_PARAM_CINFOS - , IPC_ERROR_DEL_FD__EMPTIED_LIST - , IPC_ERROR_DEL_FD__EMPTY_LIST - , IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT - - , IPC_ERROR_DEL__EMPTY_LIST - , IPC_ERROR_DEL__EMPTIED_LIST - , IPC_ERROR_DEL__CANNOT_FIND_CLIENT - , IPC_ERROR_DEL__NO_CLIENTS_PARAM - , IPC_ERROR_DEL__NO_CLIENT_PARAM + IPC_ERROR_NONE = 0 + , IPC_ERROR_NOT_ENOUGH_MEMORY = 1 + , IPC_ERROR_CLOSED_RECIPIENT = 2 + , IPC_ERROR_SERVICE_PATH__NO_PATH = 3 + , IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME = 4 + , IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM = 5 + , IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM = 6 + , IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM = 7 + , IPC_ERROR_SERVER_INIT__MALLOC = 8 + , IPC_ERROR_WRITE__NO_MESSAGE_PARAM = 9 + , IPC_ERROR_WRITE__NOT_ENOUGH_DATA = 10 + , IPC_ERROR_READ__NO_MESSAGE_PARAM = 11 + , IPC_ERROR_CONNECTION__NO_SERVER = 12 + , IPC_ERROR_CONNECTION__NO_SERVICE_NAME = 13 + , IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM = 14 + , IPC_ERROR_CONNECTION_GEN__NO_CINFO = 15 + , IPC_ERROR_ACCEPT__NO_SERVICE_PARAM = 16 + , IPC_ERROR_ACCEPT__NO_CLIENT_PARAM = 17 + , IPC_ERROR_ACCEPT = 18 + , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM = 19 + , IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM = 20 + , IPC_ERROR_WAIT_EVENT__SELECT = 21 + , IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM = 22 + , IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM = 23 + , IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC = 24 + , IPC_ERROR_ADD__EMPTY_LIST = 25 + , IPC_ERROR_ADD__NO_PARAM_CLIENTS = 26 + , IPC_ERROR_ADD__NO_PARAM_CLIENT = 27 + , IPC_ERROR_ADD__MALLOC = 28 + , IPC_ERROR_ADD_FD__NO_PARAM_CINFOS = 29 + , IPC_ERROR_ADD_FD__EMPTY_LIST = 30 + , IPC_ERROR_DEL_FD__NO_PARAM_CINFOS = 31 + , IPC_ERROR_DEL_FD__EMPTIED_LIST = 32 + , IPC_ERROR_DEL_FD__EMPTY_LIST = 33 + , IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT = 34 + , IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM = 35 + , IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM = 36 + , IPC_ERROR_CONTACT_NETWORKD__NETWORKD = 37 + , IPC_ERROR_DEL__EMPTY_LIST = 38 + , IPC_ERROR_DEL__EMPTIED_LIST = 39 + , IPC_ERROR_DEL__CANNOT_FIND_CLIENT = 40 + , IPC_ERROR_DEL__NO_CLIENTS_PARAM = 41 + , IPC_ERROR_DEL__NO_CLIENT_PARAM = 42 - /* unix socket */ - - , IPC_ERROR_USOCK_SEND - - , IPC_ERROR_USOCK_CONNECT__SOCKET - , IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR - , IPC_ERROR_USOCK_CONNECT__EMPTY_PATH - , IPC_ERROR_USOCK_CONNECT__CONNECT - - , IPC_ERROR_USOCK_CLOSE - - , IPC_ERROR_USOCK_REMOVE__UNLINK - , IPC_ERROR_USOCK_REMOVE__NO_FILE - - , IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR - , IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR - , IPC_ERROR_USOCK_INIT__EMPTY_PATH - , IPC_ERROR_USOCK_INIT__BIND - , IPC_ERROR_USOCK_INIT__LISTEN - - , IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR - , IPC_ERROR_USOCK_ACCEPT - - , IPC_ERROR_USOCK_RECV__NO_BUFFER - , IPC_ERROR_USOCK_RECV__NO_LENGTH - , IPC_ERROR_USOCK_RECV - + , IPC_ERROR_USOCK_SEND = 1 + , IPC_ERROR_USOCK_CONNECT__SOCKET = 43 + , IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR = 44 + , IPC_ERROR_USOCK_CONNECT__EMPTY_PATH = 45 + , IPC_ERROR_USOCK_CONNECT__CONNECT = 46 + , IPC_ERROR_USOCK_CLOSE = 47 + , IPC_ERROR_USOCK_REMOVE__UNLINK = 48 + , IPC_ERROR_USOCK_REMOVE__NO_FILE = 49 + , IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR = 50 + , IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR = 51 + , IPC_ERROR_USOCK_INIT__EMPTY_PATH = 52 + , IPC_ERROR_USOCK_INIT__BIND = 53 + , IPC_ERROR_USOCK_INIT__LISTEN = 54 + , IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR = 55 + , IPC_ERROR_USOCK_ACCEPT = 56 + , IPC_ERROR_USOCK_RECV__NO_BUFFER = 57 + , IPC_ERROR_USOCK_RECV__NO_LENGTH = 58 + , IPC_ERROR_USOCK_RECV = 59 + , IPC_ERROR_USOCK_RECV__MESSAGE_SIZE = 60 + , IPC_ERROR_RECEIVE_FD__NO_PARAM_FD = 61 + , IPC_ERROR_RECEIVE_FD__RECVMSG = 62 + , IPC_ERROR_PROVIDE_FD__SENDMSG = 63 /* message function errors */ - - , IPC_ERROR_MESSAGE_NEW__NO_MESSAGE_PARAM - , IPC_ERROR_MESSAGE_READ__NO_MESSAGE_PARAM - - , IPC_ERROR_MESSAGE_WRITE__NO_MESSAGE_PARAM - , IPC_ERROR_MESSAGE_WRITE__NOT_ENOUGH_DATA - - , IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM - , IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS - , IPC_ERROR_MESSAGE_FORMAT__LENGTH - - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE - , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER - - , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE - , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER - , IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE - - , IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST + , IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH = 64 + , IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE = 65 + , IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM = 66 + , IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS = 67 + , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE = 68 + , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE = 69 + , IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER = 70 + , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE = 71 + , IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER = 72 + , IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE = 73 + , IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE = 74 + , IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST = 75 }; @@ -149,7 +222,7 @@ struct ipc_connection_info { struct ipc_connection_infos { struct ipc_connection_info ** cinfos; - int32_t size; + size_t size; }; @@ -167,27 +240,42 @@ struct ipc_event { }; -/** - * MACROS +/*** + * logging macros **/ -// #define IPC_WITH_ERRORS 3 - #ifdef IPC_WITH_ERRORS #include "logger.h" -#define handle_err(fun,msg)\ - do { log_error ("%s: file %s line %d %s", fun, __FILE__, __LINE__, msg); } while (0) +// XXX: ##__VA_ARGS__ is a GNU extension to avoid requiring more arguments +#define LOG_ERROR(format, ...) log_error ( __FILE__ ":%d:" format, __LINE__, ##__VA_ARGS__ ) +#define LOG_INFO(format, ...) log_info ( __FILE__ ":%d:" format, __LINE__, ##__VA_ARGS__ ) #else -#define handle_err(fun,msg) +#define LOG_ERROR(format, ...) +#define LOG_INFO(format, ...) #endif +#if IPC_WITH_ERRORS > 2 +#define LOG_DEBUG(format, ...) log_debug ( __FILE__ ":%d:" format, __LINE__, ##__VA_ARGS__ ) +#else +#define LOG_DEBUG(format, ...) +#endif + +/*** + * ipc event macros + **/ + #define IPC_EVENT_SET(pevent,type_,message_,origin_) {\ pevent->type = type_; \ pevent->m = message_; \ pevent->origin = origin_; \ }; +enum ipc_connection_types { + IPC_CONNECTION_TYPE_IPC = 0 + , IPC_CONNECTION_TYPE_EXTERNAL = 1 +}; + #define IPC_EVENT_CLEAN(pevent) {\ pevent->type = IPC_EVENT_TYPE_NOT_SET;\ if (pevent->m != NULL) {\ @@ -197,21 +285,19 @@ struct ipc_event { }\ }; -#define IPC_WITH_UNIX_SOCKETS -#ifdef IPC_WITH_UNIX_SOCKETS -#include "usocket.h" -#endif - -#define LOG +/*** + * logging functions + **/ void log_error (const char* message, ...); void log_info (const char* message, ...); void log_debug (const char* message, ...); + /** * main public functions - */ + **/ enum ipc_errors ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname); enum ipc_errors ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname); @@ -243,40 +329,78 @@ int8_t ipc_connection_eq (const struct ipc_connection_info *p1, const struct ipc enum ipc_errors ipc_connection_gen (struct ipc_connection_info *cinfo , uint32_t index, uint32_t version, int fd, char type); -void ipc_connection_print (struct ipc_connection_info *cinfo); -void ipc_connections_print (struct ipc_connection_infos *cinfos); +void ipc_connection_print (struct ipc_connection_info *cinfo); +void ipc_connections_print (struct ipc_connection_infos *cinfos); +void ipc_connections_close (struct ipc_connection_infos *cinfos); // get explanation about an error const char * ipc_errors_get (enum ipc_errors e); -/** +/*** * message functions **/ -// used to create msg structure with a certain payload length (0 for no payload memory allocation) -enum ipc_errors ipc_message_new (struct ipc_message **m, ssize_t paylen); +uint32_t ipc_message_raw_serialize (char *buffer, char type, char user_type, char * message, uint32_t message_size); + // used to create msg structure from buffer -enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, ssize_t msize); +enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, size_t msize); // used to create buffer from msg structure -enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **buf, ssize_t *msize); +enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **buf, size_t *msize); -// read a structure msg from fd -enum ipc_errors ipc_message_read (int32_t fd, struct ipc_message *m); -// write a structure msg to fd -enum ipc_errors ipc_message_write (int32_t fd, const struct ipc_message *m); - -enum ipc_errors ipc_message_format (struct ipc_message *m - , char type, char utype, const char *payload, ssize_t length); -enum ipc_errors ipc_message_format_data (struct ipc_message *m - , char utype, const char *payload, ssize_t length); +enum ipc_errors ipc_message_format (struct ipc_message *m, char type, char utype, const char *payload, size_t length); +enum ipc_errors ipc_message_format_data (struct ipc_message *m, char utype, const char *payload, size_t length); enum ipc_errors ipc_message_format_server_close (struct ipc_message *m); - enum ipc_errors ipc_message_empty (struct ipc_message *m); +/*** + * non public functions + **/ -// non public functions -void service_path (char *path, const char *sname, int32_t index, int32_t version); + +enum ipc_errors ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p); +enum ipc_errors ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname); +enum ipc_errors service_path (char *path, const char *sname, int32_t index, int32_t version); +char * log_get_logfile_dir (char *buf, size_t size); +void log_get_logfile_name (char *buf, size_t size); + + +/*** + * networkd enumerations, structures and functions + **/ + +struct ipc_switching { + int orig; + int dest; +}; + +struct ipc_switchings { + struct ipc_switching *collection; + size_t size; +}; + +struct networkd { + int cpt; + struct ipc_connection_info *srv; + struct ipc_connection_infos *clients; + struct ipc_switchings * TCP_TO_IPC; +}; + +enum ipc_errors ipc_wait_event_networkd (struct ipc_connection_infos *cinfos + , struct ipc_connection_info *cinfo // NULL for clients + , struct ipc_event *event + , struct ipc_switchings *switchdb); + + +void ipc_switching_add (struct ipc_switchings *is, int orig, int dest); +int ipc_switching_del (struct ipc_switchings *is, int fd); +int ipc_switching_get (struct ipc_switchings *is, int fd); +void ipc_switching_free (struct ipc_switchings *is); +void ipc_switching_print (struct ipc_switchings *is); + + +enum ipc_errors ipc_receive_fd (int sock, int *fd); +enum ipc_errors ipc_provide_fd (int sock, int fd); #endif diff --git a/src/logger.c b/src/logger.c index 5fda936..1962a93 100644 --- a/src/logger.c +++ b/src/logger.c @@ -3,18 +3,86 @@ #include #include #include +#include +#include +#include +#include + +#include "ipc.h" + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_GNU_SOURCE) +#else +extern char *__progname; +#endif + +char * log_get_logfile_dir (char *buf, size_t size) +{ + char * datadir = getenv ("XDG_DATA_HOME"); + if (datadir == NULL) { + datadir = getenv ("HOME"); + if (datadir == NULL) { + return buf + snprintf (buf, size, "./ipc/"); + } + else { + return buf + snprintf (buf, size, "%s/.local/share/ipc/", datadir); + } + } + return buf + snprintf (buf, size, "%s/ipc/", datadir); +} + +void log_get_logfile_name (char *buf, size_t size) { + char *logfile = getenv ("IPC_LOGFILE"); + if (logfile == NULL) { + char *buf_after_dir; + buf_after_dir = log_get_logfile_dir (buf, size); + pid_t pid = getpid(); + +#if defined(__APPLE__) || defined(__FreeBSD__) + const char * appname = getprogname(); +#elif defined(_GNU_SOURCE) + const char * appname = program_invocation_name; +#elif defined(__linux__) + const char * appname = __progname; +#else +#error "cannot know the application name for this environment" +#endif + + snprintf (buf_after_dir, size - (buf_after_dir - buf), "%s-%d.log", appname, pid); + return; + } + + snprintf (buf, size, "%s", logfile); +} void log_format (const char* tag, const char* message, va_list args) { time_t now; time(&now); - char * date =ctime(&now); - date[strlen(date) - 1] = '\0'; - printf("%s:%s: ", date, tag); - vprintf(message, args); + struct tm *t = localtime (&now); - printf("\n"); + SECURE_BUFFER_DECLARATION (char, date, 200); + + snprintf (date, 200, "%d-%02d-%02d_%02d-%02d-%02d" + , t->tm_year+1900, t->tm_mon +1, t->tm_mday + , t->tm_hour, t->tm_min, t->tm_sec); + + SECURE_BUFFER_DECLARATION (char, logfile, BUFSIZ); + log_get_logfile_name (logfile, BUFSIZ); + + FILE * logfd = fopen (logfile, "a"); + if (logfd == NULL) { + fprintf (stderr, "something gone horribly wrong: cannot open logfile: %s\n", logfile); + return; + } + + fprintf (logfd, "%s:%s:", date, tag); + vfprintf(logfd, message, args); + fprintf (logfd, "\n"); + + fflush (logfd); + + fclose (logfd); } void log_error (const char* message, ...) { diff --git a/src/message.c b/src/message.c index 850ad52..8626555 100644 --- a/src/message.c +++ b/src/message.c @@ -9,70 +9,55 @@ #include "message.h" #include "usocket.h" -#include +// #define IPC_WITH_ERRORS 3 + +uint32_t ipc_message_raw_serialize (char *buffer, char type, char user_type, char * message, uint32_t message_size) +{ + uint32_t msize = 6 + message_size; + buffer[0] = type; + + uint32_t msize_n = htonl (message_size); + uint32_t index = 1; + + memcpy (buffer + index, &msize_n, sizeof (uint32_t)); + index += sizeof (uint32_t); + buffer[index] = user_type; + index += 1; + memcpy (buffer + index, message, message_size); + + return msize; +} -#define IPC_WITH_ERRORS 3 void ipc_message_print (const struct ipc_message *m) { - assert (m != NULL); + if (m == NULL) return; + #if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 - printf ("msg: type %d len %d\n", m->type, m->length); + LOG_INFO ("msg: type %d len %d\n", m->type, m->length); #endif } - -enum ipc_errors ipc_message_new (struct ipc_message **m, ssize_t paylen) +enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, size_t msize) { - m = malloc (sizeof(struct ipc_message)); - if (m == NULL) { - return IPC_ERROR_MESSAGE_NEW__NO_MESSAGE_PARAM; - } - - memset (*m, 0, sizeof (struct ipc_message)); - - if (paylen != 0) { - ((struct ipc_message *)m)->payload = malloc (paylen); - if (((struct ipc_message *)m)->payload == NULL) { - free (*m); - return IPC_ERROR_NOT_ENOUGH_MEMORY; - } - } - - return IPC_ERROR_NONE; -} - -enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, ssize_t msize) -{ - assert (m != NULL); - assert (buf != NULL); - assert (msize <= IPC_MAX_MESSAGE_SIZE); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE; - } - - if (buf == NULL) { - return IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER; - } - - if (msize > IPC_MAX_MESSAGE_SIZE) { - return IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE; - } + T_R ((m == NULL), IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE); + T_R ((buf == NULL), IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER); + T_R ((msize > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE); // message format: // Type (1 B) | Length (4 B) | UserType (1 B) | Payload (Length B) m->type = buf[0]; - size_t unformated_size = 0; - memcpy (&unformated_size, buf+1, sizeof(size_t)); + uint32_t unformated_size = 0; + memcpy (&unformated_size, buf+1, sizeof(uint32_t)); m->length = ntohl (unformated_size); m->user_type = buf[1 + sizeof m->length]; - assert (m->length <= IPC_MAX_MESSAGE_SIZE); + T_R ((m->length > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE); #if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 - printf ("receiving msg:\ttype %d, paylen %u, total %lu\n", m->type, m->length, msize); + LOG_INFO ("receiving msg: type %d, paylen %u, total %lu", m->type, m->length, msize); #endif - assert (m->length == msize - IPC_HEADER_SIZE || m->length == 0); + T_R ((m->length != msize - IPC_HEADER_SIZE && m->length != 0) + , IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE); if (m->payload != NULL) { free (m->payload); @@ -90,24 +75,12 @@ enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, return IPC_ERROR_NONE; } -enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **buf, ssize_t *msize) +enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **buf, size_t *msize) { - assert (m != NULL); - assert (buf != NULL); - assert (msize != NULL); - assert (m->length <= IPC_MAX_MESSAGE_SIZE); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE; - } - - if (buf == NULL) { - return IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER; - } - - if (msize == NULL) { - return IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE; - } + T_R ((m == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE); + T_R ((buf == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER); + T_R ((msize == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE); + T_R ((m->length > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH); if (*buf == NULL) { *buf = malloc (IPC_HEADER_SIZE + m->length); @@ -115,10 +88,9 @@ enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **bu } char *buffer = *buf; - uint32_t paylen = htonl(m->length); + uint32_t net_paylen = htonl(m->length); buffer[0] = m->type; - uint32_t net_paylen = htonl(m->length); memcpy (buffer + 1, &net_paylen, sizeof(uint32_t)); buffer[1 + sizeof m->length] = m->user_type; if (m->payload != NULL && m->length > 0) { @@ -128,96 +100,21 @@ enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **bu *msize = IPC_HEADER_SIZE + m->length; #if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 - printf ("sending msg:\ttype %u, paylen %u, msize %lu\n", m->type, m->length, *msize); + LOG_INFO ("sending msg: type %u, paylen %u, msize %lu", m->type, m->length, *msize); #endif return IPC_ERROR_NONE; } -// IPC_ERROR_CLOSED_RECIPIENT on closed recipient -enum ipc_errors ipc_message_read (int32_t fd, struct ipc_message *m) -{ - assert (m != NULL); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_READ__NO_MESSAGE_PARAM; - } - - char *buf = NULL; - ssize_t msize = IPC_MAX_MESSAGE_SIZE; - - enum ipc_errors ret = usock_recv (fd, &buf, &msize); - if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) { - handle_err ("msg_read", "usock_recv"); - return ret; - } - - // closed recipient, buffer already freed - if (ret == IPC_ERROR_CLOSED_RECIPIENT) { - return IPC_ERROR_CLOSED_RECIPIENT; - } - - if (buf != NULL) { - ret = ipc_message_format_read (m, buf, msize); - free (buf); - } - return ret; // propagates ipc_message_format return -} - -enum ipc_errors ipc_message_write (int32_t fd, const struct ipc_message *m) -{ - assert (m != NULL); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_WRITE__NO_MESSAGE_PARAM; - } - - char *buf = NULL; - ssize_t msize = 0; - ipc_message_format_write (m, &buf, &msize); - - ssize_t nbytes_sent = 0; - enum ipc_errors ret = usock_send (fd, buf, msize, &nbytes_sent); - if (buf != NULL) { - free (buf); - } - - if (ret != IPC_ERROR_NONE) { - handle_err ("msg_write", "usock_send"); - return ret; - } - - // what was sent != what should have been sent - if (nbytes_sent != msize) { - handle_err ("msg_write", "usock_send did not send enough data"); - return IPC_ERROR_MESSAGE_WRITE__NOT_ENOUGH_DATA; - } - - return IPC_ERROR_NONE; -} - // MSG FORMAT enum ipc_errors ipc_message_format (struct ipc_message *m - , char type, char utype, const char *payload, ssize_t length) + , char type, char utype, const char *payload, size_t length) { - assert (m != NULL); - assert (length <= IPC_MAX_MESSAGE_SIZE); - assert ((length == 0 && payload == NULL) || (length > 0 && payload != NULL)); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM; - } - - if ((length == 0 && payload != NULL) || (length > 0 && payload == NULL)) { - return IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS; - } - - if (length > IPC_MAX_MESSAGE_SIZE) { - handle_err ("msg_format_con", "msgsize > BUFSIZ"); - printf ("msg to format: %ld B)\n", length); - return IPC_ERROR_MESSAGE_FORMAT__LENGTH; - } + T_R ((m == NULL), IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM); + T_R ((length > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE); + T_R (((length == 0 && payload != NULL) || (length > 0 && payload == NULL)) + , IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS); m->type = type; m->user_type = utype; @@ -228,11 +125,7 @@ enum ipc_errors ipc_message_format (struct ipc_message *m free (m->payload); } - m->payload = malloc (length); - if (m->payload == NULL) { - return IPC_ERROR_NOT_ENOUGH_MEMORY; - } - memset (m->payload, 0, length); + SECURE_BUFFER_HEAP_ALLOCATION_R (m->payload, length, , IPC_ERROR_NOT_ENOUGH_MEMORY); } if (payload != NULL) { @@ -241,7 +134,7 @@ enum ipc_errors ipc_message_format (struct ipc_message *m return IPC_ERROR_NONE; } -enum ipc_errors ipc_message_format_data (struct ipc_message *m, char utype, const char *payload, ssize_t length) +enum ipc_errors ipc_message_format_data (struct ipc_message *m, char utype, const char *payload, size_t length) { return ipc_message_format (m, MSG_TYPE_DATA, utype, payload, length); } @@ -253,11 +146,7 @@ enum ipc_errors ipc_message_format_server_close (struct ipc_message *m) enum ipc_errors ipc_message_empty (struct ipc_message *m) { - assert (m != NULL); - - if (m == NULL) { - return IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST; - } + T_R ((m == NULL), IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST); if (m->payload != NULL) { free (m->payload); diff --git a/src/network.c b/src/network.c new file mode 100644 index 0000000..943f3f7 --- /dev/null +++ b/src/network.c @@ -0,0 +1,163 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ipc.h" + +/** + * TODO: + * describe a protocol to get this working into networkd + * asking networkd for a fd with an URI + * URI should contain: who (the service name), where (destination), how (protocol) + * networkd initiates a communication with the requested service + * networkd sends the fd + * get a networkd working with this + */ + + + +enum ipc_errors ipc_receive_fd (int sock, int *fd) +{ + T_R ((fd == NULL), IPC_ERROR_RECEIVE_FD__NO_PARAM_FD); + *fd = -1; + + SECURE_DECLARATION (struct msghdr, msg); + SECURE_BUFFER_DECLARATION (char, c_buffer, 256); + + /* On Mac OS X, the struct iovec is needed, even if it points to minimal data */ + char m_buffer[1]; + struct iovec io = { .iov_base = m_buffer, .iov_len = sizeof(m_buffer) }; + msg.msg_iov = &io; + msg.msg_iovlen = 1; + + msg.msg_control = c_buffer; + msg.msg_controllen = sizeof(c_buffer); + + T_PERROR_R ((recvmsg(sock, &msg, 0) <= 0), "recvmsg", IPC_ERROR_RECEIVE_FD__RECVMSG); + + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); + + memmove(fd, CMSG_DATA(cmsg), sizeof(*fd)); + + return IPC_ERROR_NONE; +} + +enum ipc_errors ipc_provide_fd (int sock, int fd) +{ + SECURE_DECLARATION (struct msghdr, msg); + SECURE_BUFFER_DECLARATION (char, buf, CMSG_SPACE(sizeof(fd))); + + /* On Mac OS X, the struct iovec is needed, even if it points to minimal data */ + struct iovec io = { .iov_base = "", .iov_len = 1 }; + + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + + struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + + memmove(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + msg.msg_controllen = cmsg->cmsg_len; + + T_PERROR_R ((sendmsg(sock, &msg, 0) < 0), "sendmsg", IPC_ERROR_PROVIDE_FD__SENDMSG); + + return IPC_ERROR_NONE; +} + +void ipc_switching_add (struct ipc_switchings *is, int orig, int dest) +{ + is->collection = realloc(is->collection, sizeof(struct ipc_switching) * (is->size+1)); + if (is->collection == NULL) { + LOG_ERROR ("error realloc"); + exit (EXIT_FAILURE); + } + + is->size++; + + is->collection[is->size-1].orig = orig; + is->collection[is->size-1].dest = dest; +} + +int ipc_switching_del (struct ipc_switchings *is, int fd) +{ + for (size_t i = 0; i < is->size; i++) { + if (is->collection[i].orig == fd || is->collection[i].dest == fd) { + int ret; + + if (fd == is->collection[i].orig) { + ret = is->collection[i].dest; + } + else { + ret = is->collection[i].orig; + } + + is->collection[i].orig = is->collection[is->size-1].orig; + is->collection[i].dest = is->collection[is->size-1].dest; + + size_t s = (is->size - 1) > 0 ? (is->size - 1) : 1; + + is->collection = realloc(is->collection, sizeof(struct ipc_switching) * s); + if (is->collection == NULL) { + LOG_ERROR ("error realloc"); + exit (EXIT_FAILURE); + } + + is->size--; + return ret; + } + } + + return -1; +} + +int ipc_switching_get (struct ipc_switchings *is, int fd) +{ + for (size_t i = 0; i < is->size; i++) { + if (is->collection[i].orig == fd) { + return is->collection[i].dest; + } + else if (is->collection[i].dest == fd) { + return is->collection[i].orig; + } + } + + return -1; +} + +void ipc_switching_free (struct ipc_switchings *is) +{ + if (is == NULL) + return; + + if (is->collection != NULL) { + free (is->collection); + is->collection = NULL; + } + is->size = 0; +} + +void ipc_switching_print (struct ipc_switchings *is) +{ + for (size_t i = 0; i < is->size; i++) { + LOG_DEBUG ("client %d - %d", is->collection[i].orig, is->collection[i].dest); + } +} diff --git a/src/usocket.c b/src/usocket.c index 33eb794..8f65ea1 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -9,59 +9,45 @@ #include #include #include -#include #include #include "usocket.h" #include "utils.h" -#define IPC_DEBUG - -#undef handle_err -#define handle_err(a,b) fprintf (stderr, "FUNCTION %s LINE %d ERROR %s\n", a, __LINE__, b); +// #define IPC_DEBUG 3 /** * TODO: non blocking read */ -enum ipc_errors usock_send (const int32_t fd, const char *buf, ssize_t len, ssize_t *sent) +enum ipc_errors usock_send (const int32_t fd, const char *buf, size_t len, size_t *sent) { ssize_t ret = 0; ret = send (fd, buf, len, MSG_NOSIGNAL); - if (ret <= 0) { - handle_err ("usock_send", "send ret <= 0"); - return IPC_ERROR_USOCK_SEND; - } + T_R ((ret <= 0), IPC_ERROR_USOCK_SEND); *sent = ret; return IPC_ERROR_NONE; } // *len is changed to the total message size read (header + payload) -enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) +enum ipc_errors usock_recv (const int32_t fd, char **buf, size_t *len) { - assert(buf != NULL); - assert(len != NULL); + T_R ((buf == NULL), IPC_ERROR_USOCK_RECV__NO_BUFFER); + T_R ((len == NULL), IPC_ERROR_USOCK_RECV__NO_LENGTH); int32_t ret_recv = 0; - if (buf == NULL) { - handle_err ("usock_recv", "buf == NULL"); - return IPC_ERROR_USOCK_RECV__NO_BUFFER; - } - - if (len == NULL) { - handle_err ("usock_recv", "len == NULL"); - return IPC_ERROR_USOCK_RECV__NO_LENGTH; - } + if (*len == 0) + *len = IPC_MAX_MESSAGE_SIZE; if (*buf == NULL) { // do not allocate too much memory if (*len > IPC_MAX_MESSAGE_SIZE) { - handle_err ("usock_recv", "len > IPC_MAX_MESSAGE_SIZE"); + LOG_ERROR ("usock_recv: len > IPC_MAX_MESSAGE_SIZE"); *len = IPC_MAX_MESSAGE_SIZE; } - *buf = malloc (*len + IPC_HEADER_SIZE); + SECURE_BUFFER_HEAP_ALLOCATION (*buf,*len + IPC_HEADER_SIZE, , return (IPC_ERROR_NOT_ENOUGH_MEMORY)); } uint32_t msize = 0; @@ -69,99 +55,78 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) do { ret_recv = recv (fd, *buf, *len, 0); +#ifdef IPC_DEBUG + if (ret_recv > 0) { + print_hexa ("msg recv", (uint8_t *)*buf, ret_recv); + fflush(stdout); + } +#endif + if (ret_recv > 0) { if (msize == 0) { memcpy (&msize, *buf + 1, sizeof msize); } - else { - printf ("pas la première boucle, msize == %u\n", msize); - } msize = ntohl (msize); if (msize >= IPC_MAX_MESSAGE_SIZE) { #ifdef IPC_DEBUG - printf ("lecture bien passée : %d octets\n", ret_recv); print_hexa ("msg recv", (uint8_t *)*buf, ret_recv); fflush(stdout); #endif } - assert (msize < IPC_MAX_MESSAGE_SIZE); + T_R ((msize > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_USOCK_RECV__MESSAGE_SIZE); msize_read += ret_recv - IPC_HEADER_SIZE; - } else if (ret_recv < 0) { - if (*buf != NULL) + if (*buf != NULL) { free (*buf); + *buf = NULL; + } *len = 0; switch (errno) { // The receive buffer pointer(s) point outside the process's address space. - case EFAULT: - handle_err ("usock_recv", "critical error: use of unallocated memory, quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: EFAULT\n"); - break; + ERROR_CASE (EFAULT, "usock_recv", "critical error: use of unallocated memory, quitting..."); // Invalid argument passed. - case EINVAL: - handle_err ("usock_recv", "critical error: invalid arguments to read(2), quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: EINVAL\n"); - break; + ERROR_CASE (EINVAL, "usock_recv", "critical error: invalid arguments to read(2), quitting..."); // Could not allocate memory for recvmsg(). - case ENOMEM: - handle_err ("usock_recv", "critical error: cannot allocate memory, quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: ENOMEM\n"); - break; + ERROR_CASE (ENOMEM, "usock_recv", "critical error: cannot allocate memory, quitting..."); // The argument sockfd is an invalid descriptor. - case EBADF: - handle_err ("usock_recv", "critical error: invalid descriptor, quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: EBADF\n"); - break; + ERROR_CASE (EBADF, "usock_recv", "critical error: invalid descriptor, quitting..."); // The file descriptor sockfd does not refer to a socket. - case ENOTSOCK: - handle_err ("usock_recv", "critical error: fd is not a socket, quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: ENOTSOCK\n"); - break; + ERROR_CASE (ENOTSOCK, "usock_recv", "critical error: fd is not a socket, quitting..."); // The socket is associated with a connection-oriented protocol and has not // been connected (see connect(2) and accept(2)). - case ENOTCONN: - handle_err ("usock_recv", "critical error: read(2) on a non connected socket, quitting..."); - fprintf (stderr, "ERROR WHILE RECEIVING: ENOTCONN\n"); - break; + ERROR_CASE (ENOTCONN, "usock_recv", "critical error: read(2) on a non connected socket, quitting..."); - case EAGAIN: - fprintf (stderr, "ERROR WHILE RECEIVING: EAGAIN / EWOULDBLOCK\n"); - break; + ERROR_CASE (EAGAIN, "usock_recv", "ERROR WHILE RECEIVING: EAGAIN / EWOULDBLOCK"); // A remote host refused to allow the network connection // (typically because it is not running the requested service). - case ECONNREFUSED: - fprintf (stderr, "ERROR WHILE RECEIVING: ECONNREFUSED\n"); - break; + ERROR_CASE (ECONNREFUSED, "usock_recv", "ERROR WHILE RECEIVING: ECONNREFUSED"); // The receive was interrupted by delivery of a signal before // any data were available; see signal(7). - case EINTR: - handle_err ("usock_recv", "unsupported error"); - break; + ERROR_CASE (EINTR, "usock_recv", "unsupported error"); default: - printf ("usock_recv unsupported error : %d\n", errno); - handle_err ("usock_recv", "unsupported error"); + LOG_ERROR ("usock_recv: unsupported error"); } - handle_err ("usock_recv", "recv < 0"); - perror("recv"); - + LOG_ERROR ("usock_recv: recv < 0"); return IPC_ERROR_USOCK_RECV; } +#if 0 #if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2 - printf ("fragmentation: message size read %u, should read %u\n", msize_read, msize); + LOG_ERROR ("fragmentation: message size read %u, should read %u", msize_read, msize); +#endif #endif } while (msize > msize_read); @@ -173,6 +138,7 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) free (*buf); *buf = NULL; } + *len = 0; return IPC_ERROR_CLOSED_RECIPIENT; } @@ -183,41 +149,24 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, ssize_t *len) enum ipc_errors usock_connect (int32_t *fd, const char *path) { - assert (fd != NULL); - assert (path != NULL); + T_R ((fd == NULL), IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR); + T_R ((path == NULL), IPC_ERROR_USOCK_CONNECT__EMPTY_PATH); - if (fd == NULL) { - handle_err ("usock_connect", "fd == NULL"); - return IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR; - } - - if (path == NULL) { - handle_err ("usock_connect", "path == NULL"); - return IPC_ERROR_USOCK_CONNECT__EMPTY_PATH; - } + SECURE_DECLARATION (struct sockaddr_un, my_addr); + my_addr.sun_family = AF_UNIX; int32_t sfd; - struct sockaddr_un my_addr; - socklen_t peer_addr_size; + socklen_t peer_addr_size = sizeof(struct sockaddr_un); - sfd = socket (AF_UNIX, SOCK_STREAM, 0); - if (sfd == -1) { - handle_err ("usock_connect", "sfd == -1"); - return IPC_ERROR_USOCK_CONNECT__SOCKET; - } - - // clear structure - memset(&my_addr, 0, sizeof(struct sockaddr_un)); - - my_addr.sun_family = AF_UNIX; + T_PERROR_R (((sfd = socket (AF_UNIX, SOCK_STREAM, 0)) == -1), "socket", IPC_ERROR_USOCK_CONNECT__SOCKET); strncpy(my_addr.sun_path, path, (strlen (path) < PATH_MAX) ? strlen(path) : PATH_MAX); - peer_addr_size = sizeof(struct sockaddr_un); - if(connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) { - handle_err ("usock_connect", "connect == -1"); - perror("connect"); - return IPC_ERROR_USOCK_CONNECT__CONNECT; - } + /** TODO: massive series of tests */ + T_PERROR_F_R ( + /** test */ (connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) + , /** perror */ "connect" + , /** log error */ ("unix socket connection to the path %s not possible", path) + , /** return value */ IPC_ERROR_USOCK_CONNECT__CONNECT); *fd = sfd; @@ -226,52 +175,26 @@ enum ipc_errors usock_connect (int32_t *fd, const char *path) enum ipc_errors usock_init (int32_t *fd, const char *path) { - assert (fd != NULL); - assert (path != NULL); - - if (fd == NULL) { - handle_err ("usock_init", "fd == NULL"); - return IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR; - } - - if (path == NULL) { - handle_err ("usock_init", "path == NULL"); - return IPC_ERROR_USOCK_INIT__EMPTY_PATH; - } - - int32_t sfd; - struct sockaddr_un my_addr; - socklen_t peer_addr_size; - - sfd = socket (AF_UNIX, SOCK_STREAM, 0); - if (sfd == -1) { - handle_err ("usock_init", "sfd == -1"); - return IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR; - } - - // clear structure - memset(&my_addr, 0, sizeof(struct sockaddr_un)); + T_R ((fd == NULL), IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR); + T_R ((path == NULL), IPC_ERROR_USOCK_INIT__EMPTY_PATH); + SECURE_DECLARATION (struct sockaddr_un, my_addr); my_addr.sun_family = AF_UNIX; strncpy(my_addr.sun_path, path, strlen (path)); + int32_t sfd; + socklen_t peer_addr_size; + + T_PERROR_R (((sfd = socket (AF_UNIX, SOCK_STREAM, 0)) == -1), "socket", IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR); + // delete the unix socket if already created // ignore otherwise usock_remove (path); peer_addr_size = sizeof(struct sockaddr_un); - if (bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) { - handle_err ("usock_init", "bind == -1"); - perror("bind"); - return IPC_ERROR_USOCK_INIT__BIND; - } - - if (listen (sfd, LISTEN_BACKLOG) == -1) { - handle_err ("usock_init", "listen == -1"); - perror("listen"); - return IPC_ERROR_USOCK_INIT__LISTEN; - } + T_PERROR_R ((bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1), "bind", IPC_ERROR_USOCK_INIT__BIND); + T_PERROR_R ((listen (sfd, LISTEN_BACKLOG) == -1), "listen", IPC_ERROR_USOCK_INIT__LISTEN); *fd = sfd; @@ -280,54 +203,29 @@ enum ipc_errors usock_init (int32_t *fd, const char *path) enum ipc_errors usock_accept (int32_t fd, int32_t *pfd) { - assert (pfd != NULL); + T_R ((pfd == NULL), IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR); - if (pfd == NULL) { - handle_err ("usock_accept", "pfd == NULL"); - return IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR; - } - - struct sockaddr_un peer_addr; - memset (&peer_addr, 0, sizeof (struct sockaddr_un)); + SECURE_DECLARATION (struct sockaddr_un, peer_addr); socklen_t peer_addr_size = 0; - *pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size); - if (*pfd < 0) { - handle_err ("usock_accept", "accept < 0"); - perror("listen"); - return IPC_ERROR_USOCK_ACCEPT; - } + T_PERROR_R (((*pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size)) < 0), "accept", IPC_ERROR_USOCK_ACCEPT); return IPC_ERROR_NONE; } enum ipc_errors usock_close (int32_t fd) { - int32_t ret = 0; - - ret = close (fd); - if (ret < 0) { - handle_err ("usock_close", "close ret < 0"); - perror ("closing"); - return IPC_ERROR_USOCK_CLOSE; - } + T_PERROR_R ((close (fd) < 0), "close", IPC_ERROR_USOCK_CLOSE); return IPC_ERROR_NONE; } enum ipc_errors usock_remove (const char *path) { - struct stat file_state; - memset (&file_state, 0, sizeof (struct stat)); + SECURE_DECLARATION(struct stat, file_state); // if file exists, remove it - int ret = stat (path, &file_state); - if (ret == 0) { - ret = unlink (path); - if (ret != 0) { - return IPC_ERROR_USOCK_REMOVE__UNLINK; - } - return IPC_ERROR_NONE; - } + T_R ((stat (path, &file_state) != 0), IPC_ERROR_USOCK_REMOVE__NO_FILE); + T_R ((unlink (path) != 0), IPC_ERROR_USOCK_REMOVE__UNLINK); - return IPC_ERROR_USOCK_REMOVE__NO_FILE; + return IPC_ERROR_NONE; } diff --git a/src/usocket.h b/src/usocket.h index 79bb3c2..df06027 100644 --- a/src/usocket.h +++ b/src/usocket.h @@ -7,12 +7,12 @@ // input: len = max buf size // output: *sent = nb received bytes -enum ipc_errors usock_send (const int32_t fd, const char *buf, ssize_t len, ssize_t *sent); +enum ipc_errors usock_send (const int32_t fd, const char *buf, size_t len, size_t *sent); // allocation of *len bytes on *buf == NULL // // output: *len = nb sent bytes -enum ipc_errors usock_recv (int32_t fd, char **buf, ssize_t *len); +enum ipc_errors usock_recv (int32_t fd, char **buf, size_t *len); enum ipc_errors usock_close (int32_t fd); diff --git a/src/utils.c b/src/utils.c index d6c5f37..bd4d2fe 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,22 +1,36 @@ #include "utils.h" +#include "ipc.h" void print_hexa (const char *prefix, uint8_t *payload, size_t size) { - if (! payload) + if (payload == NULL) return ; + SECURE_BUFFER_DECLARATION (char, buffer, BUFSIZ); + + char *cur = buffer, * const end = buffer + sizeof buffer; + size_t i; - for(i = 0; i < size; i++) - { - if(! (i % 4)) - printf("\n%s (%ld) ", prefix, size); - printf("%2x ", payload[i]); + size_t linenum = 0; + for(i = 0; i < size; i++) { + if (i == 0) { + cur += snprintf(cur, end-cur, "\033[32m[%2ld/%2ld]\033[00m \033[36m%s\033[00m (%ld) ", linenum +1, (size / 16) +1, prefix, size); + linenum ++; + } + else if(! (i % 16)) { + LOG_DEBUG ("%s", buffer); + memset (buffer, 0, BUFSIZ); + cur = buffer; + cur += snprintf(cur, end-cur, "\033[32m[%2ld/%2ld]\033[00m \033[36m%s\033[00m (%ld) ", linenum +1, (size / 16) +1, prefix, size); + linenum ++; + } + else if (! (i % 4)) { + cur += snprintf(cur, end-cur, " "); + } + cur += snprintf(cur, end-cur, "%2x ", payload[i]); } - printf("\n"); -} - -void mprint_hexa (char *prefix, uint8_t *buf, size_t length) -{ - print_hexa (prefix, buf, length); + if ((i % 16)) { + LOG_DEBUG ("%s", buffer); + } } diff --git a/src/utils.h b/src/utils.h index 352b78f..6d3c0e3 100644 --- a/src/utils.h +++ b/src/utils.h @@ -8,6 +8,5 @@ #include void print_hexa (const char *prefix, uint8_t *payload, size_t size); -void mprint_hexa (char *prefix, uint8_t *buf, size_t length); #endif