Compare commits

...

49 Commits

Author SHA1 Message Date
Karchnu 282cc59c18 version bump 2020-07-12 22:00:18 +02:00
Karchnu 045b1433f5 closing sockets (but not the client in a switch) 2020-07-12 20:35:55 +02:00
Karchnu 2813bd2695 fixed segfault 2020-07-11 10:44:47 +02:00
Karchnu 02c25c150d fixing a memory leak 2020-07-10 23:43:11 +02:00
Karchnu ff21ff42cb almost usable version 2020-07-10 20:18:17 +02:00
Karchnu c897edf9e7 a lot of printf 2020-07-10 12:19:03 +02:00
Karchnu 58aab88dbf callbacks kinda ok 2020-07-08 18:51:25 +02:00
Karchnu 553a550d97 default cb_out OK 2020-07-08 13:51:32 +02:00
Karchnu 0a8680a7e8 usock doesn't handle memory allocation anymore 2020-07-08 13:38:48 +02:00
Karchnu 8ccefcc40f lacking default cb_out 2020-07-08 12:40:24 +02:00
Karchnu 74fea778f7 more consistant connection types (and their use) 2020-07-08 09:57:33 +02:00
Karchnu 12427217c6 Compilation fixed for examples. 2020-07-08 01:15:18 +02:00
Karchnu 90a51a7ed7 buffers don't require malloc anymore 2020-07-08 01:08:00 +02:00
Karchnu 98a1389376 callbacks 2020-07-08 00:07:49 +02:00
Karchnu ff9d6ed2b8 Correction examples. 2020-07-06 14:38:06 +02:00
Karchnu 47408ef653 fixed 2020-07-06 09:02:13 +02:00
Karchnu 4c45fb7d12 s/events_loop/wait_event/ 2020-07-06 08:43:06 +02:00
Karchnu 8439cc0f18 Things. 2020-07-06 08:42:05 +02:00
Karchnu f1790cf314 switching ok 2020-07-04 19:29:59 +02:00
Karchnu 6243b818f1 corrections 2020-07-04 19:03:21 +02:00
Karchnu bef3b28656 simple-tcp: corrections and debug print 2020-07-04 19:02:43 +02:00
Karchnu 9a83993795 better ipcd 2020-07-04 14:41:21 +02:00
Karchnu e8cd339622 better simple-tcpd 2020-07-04 14:40:55 +02:00
Karchnu df373aea6a simple-tcp: improvments. 2020-07-04 14:21:02 +02:00
Karchnu fe87f31c34 pongspam OK 2020-07-04 14:06:51 +02:00
Karchnu e98b544539 pongd OK 2020-07-04 11:45:09 +02:00
Karchnu 1377e6fd28 pongd 2020-07-04 11:38:11 +02:00
Karchnu 36cdda36e0 pong client OK 2020-07-04 11:12:12 +02:00
Karchnu fbb7394f31 tests now compile again 2020-07-04 11:01:24 +02:00
Karchnu f89ab91917 timer works as expected 2020-07-04 10:11:19 +02:00
Karchnu 3b1aaf36c2 timer 2020-07-03 22:27:56 +02:00
Karchnu 0f46858e78 print context 2020-07-02 21:33:59 +02:00
Karchnu b6f32819e5 networkd -> ipcd 2020-07-01 14:24:45 +02:00
Karchnu 2bba5cb232 Removing printf. 2020-07-01 13:26:22 +02:00
Karchnu 71db43802e Multiple clients: ok. 2020-07-01 12:47:04 +02:00
Karchnu a5877101eb WIP: no mem leaks on simple use. switch still to test. 2020-07-01 09:53:24 +02:00
Karchnu f4ffd7386f No leaks, no error whatsoever so far. 2020-06-30 13:49:21 +02:00
Karchnu 292cca45e0 WIP: messages are sent and received OK 2020-06-30 12:59:05 +02:00
Karchnu a6ca358847 WIP!! 2020-06-29 21:07:19 +02:00
Karchnu 2a8e9a3707 WIP: connection OK, timer OK 2020-06-29 19:35:52 +02:00
Karchnu 9cdf868755 WIP 2020-06-29 16:49:54 +02:00
Karchnu 9429be80b3 Buffered writings: WIP. 2020-06-29 16:22:14 +02:00
Karchnu 0cd6f5bebd Compiles, not tested and no write buffer. 2020-06-29 00:53:40 +02:00
Karchnu 89d8881a40 Compile again, but lacks poll(2) call. 2020-06-28 18:05:28 +02:00
Karchnu 1dc5b4bcbe WIP 2020-06-28 17:22:58 +02:00
Karchnu 44992e940c WIP 2020-06-28 15:40:02 +02:00
Karchnu 05d483a712 WIP 2020-06-28 01:13:48 +02:00
Karchnu 91793c45cc WIP 2020-06-27 19:16:07 +02:00
Karchnu 85b54b0db6 poll(2): WIP. 2020-06-27 04:45:43 +02:00
30 changed files with 1544 additions and 959 deletions

View File

@ -45,9 +45,9 @@ man/libipc.7.uninstall:
@echo ' RM > $(MANDIR)/man7/libipc.7'
$(Q)rm -f '$(DESTDIR)$(MANDIR)/man7/libipc.7'
libipc.so: src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o src/fs.h src/ipc.h src/message.h src/usocket.h src/utils.h
libipc.so: src/communication.o src/context.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/service_path.o src/usocket.o src/utils.o src/fs.h src/ipc.h src/message.h src/usocket.h src/utils.h
@echo ' LD > libipc.so'
$(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o
$(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/communication.o src/context.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/service_path.o src/usocket.o src/utils.o
libipc.so.install: libipc.so
@echo ' IN > $(LIBDIR)/libipc.so.0.6.0'
@ -74,9 +74,9 @@ libipc.so.uninstall:
@echo ' RM > $(LIBDIR)/libipc.so'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so'
libipc.a: src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o src/fs.h src/ipc.h src/message.h src/usocket.h src/utils.h
libipc.a: src/communication.o src/context.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/service_path.o src/usocket.o src/utils.o src/fs.h src/ipc.h src/message.h src/usocket.h src/utils.h
@echo ' LD > libipc.a'
$(Q)$(AR) rc 'libipc.a' src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o
$(Q)$(AR) rc 'libipc.a' src/communication.o src/context.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/service_path.o src/usocket.o src/utils.o
libipc.a.install: libipc.a
@echo ' IN > $(LIBDIR)/libipc.a'
@ -103,6 +103,18 @@ src/communication.o.clean:
src/communication.o.uninstall:
src/context.o: src/context.c src/ipc.h
@echo ' CC > src/context.o'
$(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/context.c -fPIC -std=c11 -o src/context.o
src/context.o.install:
src/context.o.clean:
@echo ' RM > src/context.o'
$(Q)rm -f src/context.o
src/context.o.uninstall:
src/error.o: src/error.c src/ipc.h
@echo ' CC > src/error.o'
$(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/error.c -fPIC -std=c11 -o src/error.o
@ -163,6 +175,18 @@ src/print.o.clean:
src/print.o.uninstall:
src/service_path.o: src/service_path.c src/ipc.h
@echo ' CC > src/service_path.o'
$(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/service_path.c -fPIC -std=c11 -o src/service_path.o
src/service_path.o.install:
src/service_path.o.clean:
@echo ' RM > src/service_path.o'
$(Q)rm -f src/service_path.o
src/service_path.o.uninstall:
src/usocket.o: src/usocket.c src/usocket.h src/utils.h src/fs.h
@echo ' CC > src/usocket.o'
$(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/usocket.c -fPIC -std=c11 -o src/usocket.o
@ -209,13 +233,13 @@ $(DESTDIR)$(INCLUDEDIR):
$(DESTDIR)$(MANDIR):
@echo ' DIR > $(MANDIR)'
$(Q)mkdir -p $(DESTDIR)$(MANDIR)
install: libipc.install man/libipc.7.install libipc.so.install libipc.a.install src/communication.o.install src/error.o.install src/fs.o.install src/message.o.install src/network.o.install src/print.o.install src/usocket.o.install src/utils.o.install src/communication.o.install src/error.o.install src/fs.o.install src/message.o.install src/network.o.install src/print.o.install src/usocket.o.install src/utils.o.install
install: libipc.install man/libipc.7.install libipc.so.install libipc.a.install src/communication.o.install src/context.o.install src/error.o.install src/fs.o.install src/message.o.install src/network.o.install src/print.o.install src/service_path.o.install src/usocket.o.install src/utils.o.install src/communication.o.install src/context.o.install src/error.o.install src/fs.o.install src/message.o.install src/network.o.install src/print.o.install src/service_path.o.install src/usocket.o.install src/utils.o.install
@:
uninstall: libipc.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/communication.o.uninstall src/error.o.uninstall src/fs.o.uninstall src/message.o.uninstall src/network.o.uninstall src/print.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/communication.o.uninstall src/error.o.uninstall src/fs.o.uninstall src/message.o.uninstall src/network.o.uninstall src/print.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall
uninstall: libipc.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/communication.o.uninstall src/context.o.uninstall src/error.o.uninstall src/fs.o.uninstall src/message.o.uninstall src/network.o.uninstall src/print.o.uninstall src/service_path.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/communication.o.uninstall src/context.o.uninstall src/error.o.uninstall src/fs.o.uninstall src/message.o.uninstall src/network.o.uninstall src/print.o.uninstall src/service_path.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall
@:
clean: libipc.clean man/libipc.7.clean libipc.so.clean libipc.a.clean src/communication.o.clean src/error.o.clean src/fs.o.clean src/message.o.clean src/network.o.clean src/print.o.clean src/usocket.o.clean src/utils.o.clean src/communication.o.clean src/error.o.clean src/fs.o.clean src/message.o.clean src/network.o.clean src/print.o.clean src/usocket.o.clean src/utils.o.clean
clean: libipc.clean man/libipc.7.clean libipc.so.clean libipc.a.clean src/communication.o.clean src/context.o.clean src/error.o.clean src/fs.o.clean src/message.o.clean src/network.o.clean src/print.o.clean src/service_path.o.clean src/usocket.o.clean src/utils.o.clean src/communication.o.clean src/context.o.clean src/error.o.clean src/fs.o.clean src/message.o.clean src/network.o.clean src/print.o.clean src/service_path.o.clean src/usocket.o.clean src/utils.o.clean
distclean: clean
dist: dist-gz dist-xz dist-bz2
$(Q)rm -- $(PACKAGE)-$(VERSION)
@ -235,11 +259,13 @@ $(PACKAGE)-$(VERSION).tar.gz: distdir
$(PACKAGE)-$(VERSION)/Makefile \
$(PACKAGE)-$(VERSION)/project.zsh \
$(PACKAGE)-$(VERSION)/src/communication.c \
$(PACKAGE)-$(VERSION)/src/context.c \
$(PACKAGE)-$(VERSION)/src/error.c \
$(PACKAGE)-$(VERSION)/src/fs.c \
$(PACKAGE)-$(VERSION)/src/message.c \
$(PACKAGE)-$(VERSION)/src/network.c \
$(PACKAGE)-$(VERSION)/src/print.c \
$(PACKAGE)-$(VERSION)/src/service_path.c \
$(PACKAGE)-$(VERSION)/src/usocket.c \
$(PACKAGE)-$(VERSION)/src/utils.c \
$(PACKAGE)-$(VERSION)/src/ipc.h \
@ -259,11 +285,13 @@ $(PACKAGE)-$(VERSION).tar.xz: distdir
$(PACKAGE)-$(VERSION)/Makefile \
$(PACKAGE)-$(VERSION)/project.zsh \
$(PACKAGE)-$(VERSION)/src/communication.c \
$(PACKAGE)-$(VERSION)/src/context.c \
$(PACKAGE)-$(VERSION)/src/error.c \
$(PACKAGE)-$(VERSION)/src/fs.c \
$(PACKAGE)-$(VERSION)/src/message.c \
$(PACKAGE)-$(VERSION)/src/network.c \
$(PACKAGE)-$(VERSION)/src/print.c \
$(PACKAGE)-$(VERSION)/src/service_path.c \
$(PACKAGE)-$(VERSION)/src/usocket.c \
$(PACKAGE)-$(VERSION)/src/utils.c \
$(PACKAGE)-$(VERSION)/src/ipc.h \
@ -283,11 +311,13 @@ $(PACKAGE)-$(VERSION).tar.bz2: distdir
$(PACKAGE)-$(VERSION)/Makefile \
$(PACKAGE)-$(VERSION)/project.zsh \
$(PACKAGE)-$(VERSION)/src/communication.c \
$(PACKAGE)-$(VERSION)/src/context.c \
$(PACKAGE)-$(VERSION)/src/error.c \
$(PACKAGE)-$(VERSION)/src/fs.c \
$(PACKAGE)-$(VERSION)/src/message.c \
$(PACKAGE)-$(VERSION)/src/network.c \
$(PACKAGE)-$(VERSION)/src/print.c \
$(PACKAGE)-$(VERSION)/src/service_path.c \
$(PACKAGE)-$(VERSION)/src/usocket.c \
$(PACKAGE)-$(VERSION)/src/utils.c \
$(PACKAGE)-$(VERSION)/src/ipc.h \

View File

@ -16,3 +16,32 @@ Logs are in one of the following directories: `$XDG_DATA_HOME/ipc/` or `$HOME/.l
The log file can be indicated with the `IPC_LOGFILE` environment variable, too.
To remove logs: `make LDFLAGS=-DIPC_WITHOUT_ERRORS`
# Since 0.7
- `libipc` have callbacks to use along with switching capabilities, making easier to implement proxies for different communication protocols
# Planning for 0.8
For performance improvements within `libipc`:
- `libipc` shouldn't use realloc for each event (new client, new message, etc.) but by batch of a few thousand elements
- `libipc` should use better internal structures, unrequiring the use of loops (over the whole list of messages or connections) for each action
# Planning for 0.9
- `libipc` should use `libevent` for performance improvments
- `libipc` should be thread-safe
# Planning for 1.0
- `libipc` *may* be written in Zig
- `libipc` should have usable bindings in several languages
# Implementation design
## Memory management
1. Prefer stack over mallocs.
2. Basic functions (such as *usock_*) should not handle memory allocation.

View File

@ -23,14 +23,14 @@ void chomp (char *str, ssize_t len)
}
}
struct ipc_connection_info *srv;
struct ipc_ctx *ctx = NULL;
void non_interactive (int verbosity, size_t nb_msg, char *msg_str, char *env[])
void non_interactive (int verbosity, size_t nb_msg, char *msg_str)
{
SECURE_DECLARATION (struct ipc_message, m);
// init service
TEST_IPC_QUIT_ON_ERROR (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_QUIT_ON_ERROR (ipc_connection (ctx, SERVICE_NAME), EXIT_FAILURE);
if (verbosity > 1) {
printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen (MSG) + 1, (int)strlen (MSG), MSG);
@ -38,9 +38,9 @@ void non_interactive (int verbosity, size_t nb_msg, char *msg_str, char *env[])
for (size_t i = 0 ; i < nb_msg ; i++) {
TEST_IPC_QUIT_ON_ERROR (ipc_message_format_data (&m, 42, msg_str, (ssize_t) strlen (msg_str) + 1), EXIT_FAILURE);
TEST_IPC_QUIT_ON_ERROR (ipc_write (srv, &m), EXIT_FAILURE);
TEST_IPC_QUIT_ON_ERROR (ipc_write_fd (ctx->pollfd[0].fd, &m), EXIT_FAILURE);
ipc_message_empty (&m);
TEST_IPC_QUIT_ON_ERROR (ipc_read (srv, &m), EXIT_FAILURE);
TEST_IPC_QUIT_ON_ERROR (ipc_read (ctx, 0 /* read from the only valid index */, &m), EXIT_FAILURE);
if (verbosity > 1) {
printf ("msg recv (type: %u): %s\n", m.user_type, m.payload);
@ -48,30 +48,28 @@ void non_interactive (int verbosity, size_t nb_msg, char *msg_str, char *env[])
ipc_message_empty (&m);
}
TEST_IPC_QUIT_ON_ERROR (ipc_close (srv), EXIT_FAILURE);
TEST_IPC_QUIT_ON_ERROR (ipc_close_all (ctx), EXIT_FAILURE);
}
void interactive (char *env[])
void interactive ()
{
// init service
TEST_IPC_QUIT_ON_ERROR (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_QUIT_ON_ERROR (ipc_connection (ctx, SERVICE_NAME), EXIT_FAILURE);
SECURE_DECLARATION (struct ipc_error, ret);
SECURE_DECLARATION (struct ipc_event, event);
SECURE_DECLARATION (struct ipc_connection_infos, services);
ipc_add (&services, srv);
ipc_add_fd (&services, 0); // add STDIN
ipc_add_fd (ctx, 0); // add STDIN
ipc_connections_print (&services);
ipc_ctx_print (ctx);
long timer = 10;
int timer = 10000;
while (1) {
printf ("msg to send: ");
fflush (stdout);
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE);
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (ctx, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_EXTRA_SOCKET:
{
@ -80,7 +78,7 @@ void interactive (char *env[])
char buf[4096];
memset (buf, 0, 4096);
len = read (event.origin->fd, buf, 4096);
len = read (event.origin, buf, 4096);
buf[len - 1] = '\0';
chomp (buf, len);
@ -93,13 +91,13 @@ void interactive (char *env[])
// in case we want to quit the program
if (len == 0 || strncmp (buf, "quit", 4) == 0 || strncmp (buf, "exit", 4) == 0) {
struct ipc_error ret = ipc_close (srv);
struct ipc_error ret = ipc_close_all (ctx);
if (ret.error_code != IPC_ERROR_NONE) {
fprintf (stderr, "%s", ret.error_message);
exit (EXIT_FAILURE);
}
ipc_connections_free (&services);
ipc_ctx_free (ctx);
exit (EXIT_SUCCESS);
}
@ -116,7 +114,7 @@ void interactive (char *env[])
printf ("\n");
printf ("right before sending a message\n");
#endif
ret = ipc_write (srv, m);
ret = ipc_write (ctx, m);
if (ret.error_code != IPC_ERROR_NONE) {
fprintf (stderr, "%s", ret.error_message);
exit (EXIT_FAILURE);
@ -145,24 +143,17 @@ void interactive (char *env[])
}
}
int main (int argc, char *argv[], char *env[])
int main (int argc, char *argv[])
{
printf("usage: %s [verbosity #messages message]", argv[0]);
// $0:
argv = argv; // warnings
srv = malloc (sizeof (struct ipc_connection_info));
memset (srv, 0, sizeof (struct ipc_connection_info));
// index and version should be filled
srv->index = 0;
srv->version = 0;
ctx = malloc (sizeof (struct ipc_ctx));
memset (ctx, 0, sizeof (struct ipc_ctx));
if (argc == 4)
non_interactive (atoi(argv[1]), (size_t) atoi(argv[2]), argv[3], env);
non_interactive (atoi(argv[1]), (size_t) atoi(argv[2]), argv[3]);
else
interactive (env);
interactive ();
return EXIT_SUCCESS;
}

View File

@ -12,36 +12,47 @@
fprintf(stderr, "error while %s: %s\n", msg, ret.error_message);\
}
/**
* ipc_ctx:
* cinfos: array of ipc_connection_info
* pollfd: array of `pollfd` structure
* Both arrays share the same indices.
*/
/**
******************************************************************************
* Overview of the main loop:
* 1. "ctx" pointer declaration (struct ipc_ctx).
* 1. ipc_server_init (ctx, SERVICE_NAME)
******************************************************************************
*/
int cpt = 0;
int verbosity = 1;
struct ipc_connection_info *srv = NULL;
struct ipc_connection_infos *clients = NULL;
struct ipc_ctx *ctx = NULL;
void main_loop ()
{
double base_timer = 0;
double timer = base_timer;
int base_timer = 10000;
int timer = base_timer;
SECURE_DECLARATION (struct ipc_error, ret);
clients = malloc (sizeof (struct ipc_connection_infos));
memset (clients, 0, sizeof (struct ipc_connection_infos));
SECURE_DECLARATION (struct ipc_event, event);
event.type = IPC_EVENT_TYPE_NOT_SET;
while (1) {
// ipc_service_poll_event provides one event at a time
// ipc_wait_event provides one event at a time
// warning: event->m is free'ed if not NULL
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (clients, srv, &event, &timer), EXIT_FAILURE);
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (ctx, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_CONNECTION:
{
cpt++;
if (verbosity > 1) {
printf ("connection: %d clients connected, new client is %d\n", cpt, (event.origin)->fd);
printf ("connection: %d ctx connected, new client is %d\n", cpt, event.origin);
}
};
break;
@ -49,11 +60,8 @@ void main_loop ()
{
cpt--;
if (verbosity > 1) {
printf ("disconnection: %d clients remaining\n", cpt);
printf ("disconnection: %d ctx remaining\n", cpt);
}
// free the ipc_client structure
free (event.origin);
};
break;
case IPC_EVENT_TYPE_MESSAGE:
@ -68,13 +76,10 @@ void main_loop ()
}
}
ret = ipc_write (event.origin, m);
ret = ipc_write (ctx, m);
if (ret.error_code != IPC_ERROR_NONE) {
PRINTERR (ret, "server write");
}
if (verbosity > 1) {
printf ("message sent\n");
}
};
break;
case IPC_EVENT_TYPE_TIMER:{
@ -86,13 +91,17 @@ void main_loop ()
case IPC_EVENT_TYPE_ERROR:
{
cpt--;
fprintf (stderr, "a problem happened with client %d (now disconnected)", (event.origin)->fd);
fprintf (stderr, ", %d clients remaining\n", cpt);
// free the ipc_client structure
free (event.origin);
fprintf (stderr, "a problem happened with client %d (now disconnected)", event.origin);
fprintf (stderr, ", %d ctx remaining\n", cpt);
};
break;
case IPC_EVENT_TYPE_TX:
{
if (verbosity > 1) {
printf ("a message was sent\n");
}
}
break;
default:
{
fprintf (stderr, "there must be a problem, event not set\n");
@ -108,70 +117,49 @@ void exit_program (int signal)
{
printf ("Quitting, signal: %d\n", signal);
// free remaining clients
for (size_t i = 0; i < clients->size; i++) {
struct ipc_connection_info *cli = clients->cinfos[i];
if (cli != NULL) {
free (cli);
}
clients->cinfos[i] = NULL;
}
ipc_connections_free (clients);
free (clients);
// the application will shut down, and close the service
struct ipc_error ret = ipc_server_close (srv);
struct ipc_error ret = ipc_close_all (ctx);
if (ret.error_code != IPC_ERROR_NONE) {
PRINTERR (ret, "server close");
}
free (srv);
ipc_ctx_free (ctx);
free (ctx);
exit (EXIT_SUCCESS);
}
/*
* service ping-pong: send back everything sent by the clients
* service ping-pong: send back everything sent by the ctx
* stop the program on SIG{TERM,INT,ALRM,USR{1,2},HUP} signals
*/
int main (int argc, char *argv[], char **env)
int main (int argc, char *argv[])
{
argc = argc; // warnings
argv = argv; // warnings
if (argc > 1) {
verbosity = atoi(argv[1]);
}
printf ("pid = %d\n", getpid ());
srv = malloc (sizeof (struct ipc_connection_info));
if (srv == NULL) {
exit (EXIT_FAILURE);
}
memset (srv, 0, sizeof (struct ipc_connection_info));
srv->type = '\0';
srv->index = 0;
srv->version = 0;
srv->fd = 0;
srv->spath = NULL;
ctx = malloc (sizeof (struct ipc_ctx));
memset (ctx, 0, sizeof (struct ipc_ctx));
struct ipc_error ret = ipc_server_init (env, srv, PONGD_SERVICE_NAME);
struct ipc_error ret = ipc_server_init (ctx, PONGD_SERVICE_NAME);
if (ret.error_code != IPC_ERROR_NONE) {
PRINTERR (ret, "server init");
return EXIT_FAILURE;
}
printf ("Listening on %s.\n", srv->spath);
printf ("Listening on %s.\n", ctx->cinfos[0].spath);
printf ("MAIN: server created\n");
signal (SIGHUP, exit_program);
signal (SIGHUP, exit_program);
signal (SIGALRM, exit_program);
signal (SIGUSR1, exit_program);
signal (SIGUSR2, exit_program);
signal (SIGTERM, exit_program);
signal (SIGINT, exit_program);
signal (SIGINT, exit_program);
// the service will loop until the end of time, or a signal
main_loop ();

View File

@ -23,52 +23,51 @@ void chomp (char *str, ssize_t len)
}
}
struct ipc_connection_info *srv;
struct ipc_ctx *ctx = NULL;
void non_interactive (char *env[])
void non_interactive ()
{
SECURE_DECLARATION (struct ipc_message, m);
// init service
TEST_IPC_Q (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q (ipc_connection (ctx, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q (ipc_message_format_data (&m, 42, MSG, (ssize_t) strlen (MSG) + 1), EXIT_FAILURE);
printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen (MSG) + 1, (int)strlen (MSG), MSG);
TEST_IPC_Q (ipc_write (srv, &m), EXIT_FAILURE);
// ipc_write fd: write a message without fd availability check.
TEST_IPC_Q (ipc_write_fd (ctx->pollfd[0].fd, &m), EXIT_FAILURE);
ipc_message_empty (&m);
TEST_IPC_Q (ipc_read (srv, &m), EXIT_FAILURE);
TEST_IPC_Q (ipc_read (ctx, 0 /* only valid index */, &m), EXIT_FAILURE);
printf ("msg recv (type: %u): %s\n", m.user_type, m.payload);
ipc_message_empty (&m);
TEST_IPC_Q (ipc_close (srv), EXIT_FAILURE);
TEST_IPC_Q (ipc_close_all (ctx), EXIT_FAILURE);
}
void interactive (char *env[])
void interactive ()
{
// init service
TEST_IPC_Q (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q (ipc_connection (ctx, SERVICE_NAME), EXIT_FAILURE);
SECURE_DECLARATION (struct ipc_event, event);
SECURE_DECLARATION (struct ipc_connection_infos, services);
ipc_add (&services, srv);
ipc_add_fd (&services, 0); // add STDIN
ipc_add_fd (ctx, 0); // add STDIN
ipc_connections_print (&services);
ipc_ctx_print (ctx);
long timer = 10;
int timer = 10000;
while (1) {
printf ("msg to send: ");
fflush (stdout);
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE);
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (ctx, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_TIMER:{
printf ("time up!\n");
timer = 10;
timer = 10000;
};
break;
case IPC_EVENT_TYPE_EXTRA_SOCKET:
@ -78,7 +77,7 @@ void interactive (char *env[])
char buf[4096];
memset (buf, 0, 4096);
len = read (event.origin->fd, buf, 4096);
len = read (event.origin, buf, 4096);
buf[len - 1] = '\0';
chomp (buf, len);
@ -91,9 +90,9 @@ void interactive (char *env[])
// in case we want to quit the program
if (len == 0 || strncmp (buf, "quit", 4) == 0 || strncmp (buf, "exit", 4) == 0) {
TEST_IPC_Q (ipc_close (srv), EXIT_FAILURE);
TEST_IPC_Q (ipc_close_all (ctx), EXIT_FAILURE);
ipc_connections_free (&services);
ipc_ctx_free (ctx);
exit (EXIT_SUCCESS);
}
@ -107,6 +106,7 @@ void interactive (char *env[])
len = strlen (buf);
printf ("message %lu, buffer %.*s\n", i, (int)len, buf);
TEST_IPC_Q (ipc_message_format_data (m, 42, buf, len), EXIT_FAILURE);
m->fd = ctx->pollfd[0].fd;
printf ("message from structure: %.*s\n", m->length, m->payload);
@ -114,7 +114,7 @@ void interactive (char *env[])
printf ("\n");
printf ("right before sending a message\n");
#endif
TEST_IPC_Q (ipc_write (srv, m), EXIT_FAILURE);
TEST_IPC_Q (ipc_write (ctx, m), EXIT_FAILURE);
#if 0
printf ("right after sending a message\n");
#endif
@ -125,6 +125,11 @@ void interactive (char *env[])
free (m);
}
break;
case IPC_EVENT_TYPE_TX:
{
printf ("a message was sent\n");
}
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
@ -141,22 +146,18 @@ void interactive (char *env[])
}
}
int main (int argc, char *argv[], char *env[])
int main (int argc, char **argv)
{
argc = argc; // warnings
argv = argv; // warnings
// Compilers fuckery.
argv = argv;
srv = malloc (sizeof (struct ipc_connection_info));
memset (srv, 0, sizeof (struct ipc_connection_info));
// index and version should be filled
srv->index = 0;
srv->version = 0;
ctx = malloc (sizeof (struct ipc_ctx));
memset (ctx, 0, sizeof (struct ipc_ctx));
if (argc == 1)
non_interactive (env);
non_interactive ();
else
interactive (env);
interactive ();
return EXIT_SUCCESS;
}

View File

@ -64,7 +64,9 @@ void send_receive (int sockfd)
// 2 | 6 | 0 | "coucou"
// 1 B | 4 B | 1 | 6 B
ipc_message_raw_serialize ((char *)buf, MSG_TYPE_DATA, 42, "coucou", 6);
print_hexa ("WAITING 10 seconds then message to send", buf, 12);
printf("\n");
print_hexa ("message to send", buf, 12);
printf("\n");
// sleep (1);
T_PERROR_Q ((send (sockfd, buf, 12, 0) == -1), "sending a message", EXIT_FAILURE);
printf ("message 'coucou' sent\n");
@ -72,6 +74,7 @@ void send_receive (int sockfd)
// receiving a message
T_PERROR_Q (((paylen = recv (sockfd, buf, BUFSIZ, 0)) < 0), "receiving a message", EXIT_FAILURE);
printf("\n");
if (paylen == 0) {
fprintf (stderr, "error: disconnection from the server\n");
@ -96,7 +99,7 @@ int main (int argc, char *argv[])
send_receive (sockfd);
printf ("Disconnection\n");
printf ("\nDisconnection\n");
// close the socket
close (sockfd);

View File

@ -42,7 +42,7 @@ void chomp (char *str, size_t len)
else
connection from the client:
1. client sends service name
2. networkd establishes a connection to the service
2. ipcd establishes a connection to the service
3. ack
else
lolwat shouldn't happen :(
@ -52,26 +52,26 @@ void chomp (char *str, size_t len)
#define SERVICE_NAME "simpletcp"
struct networkd *ctx;
struct ipc_ctx *ctx = NULL;
void handle_disconnection (int fd)
{
int delfd;
delfd = ipc_switching_del (ctx->TCP_TO_IPC, fd);
delfd = ipc_switching_del (&ctx->switchdb, fd);
if (delfd >= 0) {
close (delfd);
ipc_del_fd (ctx->clients, delfd);
ipc_del_fd (ctx, delfd);
}
close (fd);
ipc_del_fd (ctx->clients, fd);
ipc_del_fd (ctx, fd);
// printf ("TCP_TO_IPC\n");
ipc_switching_print (ctx->TCP_TO_IPC);
// printf ("ctx.switchdb\n");
ipc_switching_print (&ctx->switchdb);
}
void tcp_connection (char **env, int fd)
void tcp_connection (int fd)
{
SECURE_BUFFER_DECLARATION (char, buf, BUFSIZ);
@ -89,16 +89,15 @@ void tcp_connection (char **env, int fd)
// TODO: tests
T_PERROR_Q ((send (fd, "OK", 2, 0) <= 0), "sending a message", EXIT_FAILURE);
SECURE_DECLARATION (struct ipc_connection_info, tcp_to_ipc_ci);
struct ipc_error ret = ipc_connection (env, &tcp_to_ipc_ci, buf);
printf ("connection to %s\n", buf);
struct ipc_error ret = ipc_connection_switched (ctx, buf);
if (ret.error_code != IPC_ERROR_NONE) {
fprintf (stderr, "%s\n", ret.error_message);
exit (EXIT_FAILURE);
}
ipc_switching_add (ctx->TCP_TO_IPC, fd, tcp_to_ipc_ci.fd);
ipc_add_fd (ctx->clients, tcp_to_ipc_ci.fd);
ipc_switching_add (&ctx->switchdb, fd, ctx->pollfd[ctx->size-1].fd);
ipc_ctx_fd_type (ctx, fd, IPC_CONNECTION_TYPE_SWITCHED);
}
int accept_new_client (int serverfd)
@ -111,13 +110,14 @@ int accept_new_client (int serverfd)
accept (serverfd, (struct sockaddr *)&client, &addrlen)) == -1), "accept new client",
EXIT_FAILURE);
// adding a client
ipc_add_fd (ctx->clients, sock_fd_client);
// adding a client, for now not switched:
// tcpd should handle the first message (getting the service name)
ipc_add_fd (ctx, sock_fd_client);
return sock_fd_client;
}
void main_loop (int argc, char **argv, char **env)
void main_loop (int argc, char **argv)
{
argc = argc; // FIXME: useless
int serverfd;
@ -155,80 +155,89 @@ void main_loop (int argc, char **argv, char **env)
return;
}
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->clients, sizeof (struct ipc_connection_infos),, EXIT_FAILURE);
SECURE_DECLARATION (struct ipc_event, event);
ipc_add_fd (ctx->clients, serverfd);
ipc_add_fd (ctx, serverfd);
int cpt = 0;
int timer = 10000;
while (1) {
// ipc_wait_event provides one event at a time
// warning: event->m is free'ed if not NULL
long timer = 10;
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event_networkd (ctx->clients, ctx->srv, &event, ctx->TCP_TO_IPC, &timer)
, EXIT_FAILURE);
ipc_ctx_print (ctx);
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (ctx, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_TIMER:{
printf ("timed out!\n");
timer = 10;
timer = 10000;
}
break;
case IPC_EVENT_TYPE_SWITCH:{
printf ("switch happened\n");
printf ("switch happened, from %d\n", event.origin);
}
break;
case IPC_EVENT_TYPE_EXTRA_SOCKET:
{
// NEW CLIENT
if (event.origin->fd == serverfd) {
if (event.origin == serverfd) {
int sock_fd_client = accept_new_client (serverfd);
ctx->cpt++;
printf ("TCP connection: %d clients connected\n", ctx->cpt);
cpt++;
printf ("TCP connection: %d ctx connected\n", cpt);
printf ("new TCP client has the fd %d\n", sock_fd_client);
}
// CLIENT IS TALKING
else {
tcp_connection (env, event.origin->fd);
// Test: if the socket already is in the switch, this means we can just switch the packet.
// Is the socket in the switch db?
tcp_connection (event.origin);
}
}
break;
case IPC_EVENT_TYPE_CONNECTION:
{
ctx->cpt++;
printf ("connection: %d clients connected\n", ctx->cpt);
printf ("new client has the fd %d\n", (event.origin)->fd);
cpt++;
printf ("connection: %d ctx connected\n", cpt);
printf ("new client has the fd %d\n", event.origin);
};
break;
case IPC_EVENT_TYPE_DISCONNECTION:
{
ctx->cpt--;
printf ("disconnection: %d clients remaining\n", ctx->cpt);
// free the ipc_client structure
// if (event.origin != NULL)
// free (event.origin);
cpt--;
printf ("disconnection: %d ctx remaining\n", cpt);
};
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
if (m->length > 0) {
printf ("message received (type %d): %.*s\n", m->type, m->length, m->payload);
}
TEST_IPC_P (ipc_write (event.origin, m), "server write");
// m->fd = 3;
TEST_IPC_P (ipc_write (ctx, m), "server write");
};
break;
case IPC_EVENT_TYPE_ERROR:
fprintf (stderr, "a problem happened with client %d\n", (event.origin)->fd);
case IPC_EVENT_TYPE_TX:
{
printf ("a message was sent\n");
}
break;
case IPC_EVENT_TYPE_ERROR:
fprintf (stderr, "a problem happened with client %d\n", event.origin);
break;
default:
fprintf (stderr, "there must be a problem, event not set\n");
fprintf (stderr, "there must be a problem, event not set: %d\n", event.type);
exit(1);
}
}
@ -240,36 +249,22 @@ void exit_program (int signal)
{
printf ("Quitting, signal: %d\n", signal);
// free remaining clients
for (size_t i = 0; i < ctx->clients->size; i++) {
struct ipc_connection_info *cli = ctx->clients->cinfos[i];
if (cli != NULL) {
free (cli);
}
ctx->clients->cinfos[i] = NULL;
}
ipc_connections_free (ctx->clients);
// the application will shut down, and close the service
TEST_IPC_P (ipc_server_close (ctx->srv), "server close");
// Close then free remaining ctx.
ipc_close_all (ctx);
ipc_ctx_free (ctx);
// free, free everything!
free (ctx->clients);
free (ctx->srv);
free (ctx->TCP_TO_IPC->collection);
free (ctx->TCP_TO_IPC);
free (ctx);
exit (EXIT_SUCCESS);
}
/*
* service ping-pong: send back everything sent by the clients
* service ping-pong: send back everything sent by the ctx
* stop the program on SIG{TERM,INT,ALRM,USR{1,2},HUP} signals
*/
int main (int argc, char *argv[], char **env)
int main (int argc, char *argv[])
{
// check the number of args on command line
if (argc != 2) {
@ -279,17 +274,15 @@ int main (int argc, char *argv[], char **env)
printf ("pid = %d\n", getpid ());
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx, sizeof (struct networkd) ,, EXIT_FAILURE);
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->TCP_TO_IPC, sizeof (struct ipc_switchings) ,, EXIT_FAILURE);
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->TCP_TO_IPC->collection, sizeof (struct ipc_switching) ,, EXIT_FAILURE);
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->srv, sizeof (struct ipc_connection_info),, EXIT_FAILURE);
ctx = malloc (sizeof (struct ipc_ctx));
memset(ctx, 0, sizeof (struct ipc_ctx));
struct ipc_error ret = ipc_server_init (env, ctx->srv, SERVICE_NAME);
struct ipc_error ret = ipc_server_init (ctx, SERVICE_NAME);
if (ret.error_code != IPC_ERROR_NONE) {
fprintf (stderr, "%s\n", ret.error_message);
return EXIT_FAILURE;
}
printf ("Listening on [%s].\n", ctx->srv->spath);
printf ("Listening on [%s].\n", ctx->cinfos[0].spath);
printf ("MAIN: server created\n");
@ -301,7 +294,7 @@ int main (int argc, char *argv[], char **env)
signal (SIGINT , exit_program);
// the service will loop until the end of time, or a signal
main_loop (argc, argv, env);
main_loop (argc, argv);
// main_loop should not return
return EXIT_FAILURE;

View File

@ -6,30 +6,27 @@
int main (int argc, char *argv[])
{
(void)argc;
(void)argv;
SECURE_DECLARATION (struct ipc_error, ret);
SECURE_DECLARATION (struct ipc_connection_info, srv);
if (argc != 2) {
fprintf (stderr, "usage: %s service_name\n", argv[0]);
exit (1);
}
SECURE_DECLARATION (struct ipc_error, ret);
int fd = 0;
char *service_name = argv[1];
ret = ipc_contact_networkd (&srv, service_name);
ret = ipc_contact_ipcd (&fd, service_name);
printf ("ret = %d\n", ret.error_code);
if (ret.error_code == IPC_ERROR_NONE && srv.fd != 0) {
if (ret.error_code == IPC_ERROR_NONE && fd > 0) {
printf ("Success\n");
} else {
printf ("Ow. :(\n");
}
usock_close (srv.fd);
usock_close (fd);
return EXIT_SUCCESS;
}

View File

@ -4,35 +4,32 @@
#include "../src/ipc.h"
int main (int argc, char *argv[], char *env[])
int main (void)
{
(void)argc;
(void)argv;
SECURE_DECLARATION (struct ipc_error, ret);
SECURE_DECLARATION (struct ipc_connection_info, srv);
SECURE_DECLARATION (struct ipc_connection_info, client);
SECURE_DECLARATION (struct ipc_connection_info, contacted_service);
SECURE_DECLARATION (struct ipc_ctx, ctx);
SECURE_DECLARATION (struct ipc_event, event);
// service start
TEST_IPC_Q (ipc_server_init (env, &srv, "network"), EXIT_FAILURE);
TEST_IPC_Q (ipc_server_init (&ctx, "ipcd"), EXIT_FAILURE);
printf ("service initialized, waiting for a client\n");
// accept a new client
TEST_IPC_Q (ipc_accept (&srv, &client), EXIT_FAILURE);
TEST_IPC_Q (ipc_accept_add (&event, &ctx, 0 /* the only valid index right now */), EXIT_FAILURE);
int client_fd = ctx.pollfd[ctx.size-1].fd;
// TODO: read a message to know the requested service
SECURE_DECLARATION (struct ipc_message, msg);
TEST_IPC_Q (ipc_read (&client, &msg), EXIT_FAILURE);
TEST_IPC_Q (ipc_read (&ctx, 1 /* 1 = our client */, &msg), EXIT_FAILURE);
printf ("received message: %s\n", msg.payload);
/** TODO: contact the service */
printf ("WARNING: currently this program only ask for pong service %d\n", ret.error_code);
TEST_IPC_Q (ipc_connection (env, &contacted_service, "pong"), EXIT_FAILURE);
TEST_IPC_Q (ipc_connection (&ctx, "pong"), EXIT_FAILURE);
ipc_provide_fd (client.fd, contacted_service.fd);
ipc_provide_fd (client_fd, ctx.pollfd[ctx.size-1].fd);
TEST_IPC_Q (ipc_server_close (&srv), EXIT_FAILURE);
TEST_IPC_Q (ipc_close_all (&ctx), EXIT_FAILURE);
return EXIT_SUCCESS;
}

View File

@ -19,12 +19,13 @@ void chomp (char *str, ssize_t len)
}
}
struct ipc_connection_info *srv;
struct ipc_ctx *ctx;
void interactive (char *env[])
void interactive ()
{
long timer = 10;
int timer = 10000; // 10 seconds
SECURE_DECLARATION (struct ipc_event, event);
SECURE_BUFFER_DECLARATION (char, service_name, 100);
char *sn = getenv ("PATH_TRANSLATED");
@ -37,21 +38,17 @@ void interactive (char *env[])
}
// init service
TEST_IPC_Q (ipc_connection (env, srv, service_name), EXIT_FAILURE);
TEST_IPC_Q (ipc_connection (ctx, service_name), EXIT_FAILURE);
SECURE_DECLARATION (struct ipc_event, event);
SECURE_DECLARATION (struct ipc_connection_infos, services);
ipc_add (&services, srv);
ipc_add_fd (&services, 0); // add STDIN
ipc_add_fd (ctx, 0); // add STDIN
while (1) {
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE);
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (ctx, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_TIMER:{
fprintf (stderr, "time up!\n");
timer = 10;
timer = 10000;
};
break;
case IPC_EVENT_TYPE_EXTRA_SOCKET:
@ -60,19 +57,19 @@ void interactive (char *env[])
SECURE_BUFFER_DECLARATION (char, buf, 4096);
ssize_t len;
len = read (event.origin->fd, buf, 4096);
len = read (event.origin, buf, 4096);
// in case we want to quit the program
if (len == 0 || strncmp (buf, "quit", 4) == 0 || strncmp (buf, "exit", 4) == 0) {
TEST_IPC_Q (ipc_close (srv), EXIT_FAILURE);
TEST_IPC_Q (ipc_close_all (ctx), EXIT_FAILURE);
ipc_connections_free (&services);
ipc_ctx_free (ctx);
exit (EXIT_SUCCESS);
}
// send the message read on STDIN
ssize_t len_sent = write (srv->fd, buf, len);
ssize_t len_sent = write (ctx->pollfd[0].fd, buf, len);
if (len_sent != len) {
fprintf (stderr, "cannot send the message %lu-byte message, sent %lu bytes",
len, len_sent);
@ -94,6 +91,10 @@ void interactive (char *env[])
fflush (stdout);
};
break;
case IPC_EVENT_TYPE_TX: {
printf ("Message sent\n");
}
break;
ERROR_CASE (IPC_EVENT_TYPE_DISCONNECTION, "main loop", "disconnection: should not happen");
ERROR_CASE (IPC_EVENT_TYPE_NOT_SET , "main loop", "not set: should not happen");
ERROR_CASE (IPC_EVENT_TYPE_CONNECTION , "main loop", "connection: should not happen");
@ -104,19 +105,12 @@ void interactive (char *env[])
}
}
int main (int argc, char *argv[], char *env[])
int main (void)
{
argc = argc; // warnings
argv = argv; // warnings
ctx = malloc (sizeof (struct ipc_ctx));
memset (ctx, 0, sizeof (struct ipc_ctx));
srv = malloc (sizeof (struct ipc_connection_info));
memset (srv, 0, sizeof (struct ipc_connection_info));
// index and version should be filled
srv->index = 0;
srv->version = 0;
interactive (env);
interactive ();
return EXIT_SUCCESS;
}

View File

@ -34,17 +34,17 @@ _enum ipc_errors_ **ipc_accept** (*struct ipc_connection_info* \*srv, *struct ip
_enum ipc_errors_ **ipc_read** (*const struct ipc_connection_info* \*, *struct ipc_message* \*m);++
_enum ipc_errors_ **ipc_write** (*const struct ipc_connection_info* \*, *const struct ipc_message* \*m);++
_enum ipc_errors_ **ipc_wait_event** (*struct ipc_connection_infos* \*clients, *struct ipc_connection_info* \*srv, *struct ipc_event* \*event);
_enum ipc_errors_ **ipc_wait_event** (*struct ipc_ctx* \*clients, *struct ipc_connection_info* \*srv, *struct ipc_event* \*event);
// store and remove only pointers on allocated structures
_enum ipc_errors_ **ipc_add** (*struct ipc_connection_infos* \*cinfos, *struct ipc_connection_info* \*cinfo);++
_enum ipc_errors_ **ipc_del** (*struct ipc_connection_infos* \*cinfos, *struct ipc_connection_info* \*cinfo);
_enum ipc_errors_ **ipc_add** (*struct ipc_ctx* \*cinfos, *struct ipc_connection_info* \*cinfo);++
_enum ipc_errors_ **ipc_del** (*struct ipc_ctx* \*cinfos, *struct ipc_connection_info* \*cinfo);
// add an arbitrary file descriptor to read
_enum ipc_errors_ **ipc_add_fd** (*struct ipc_connection_infos* \*cinfos, *int* fd);
_enum ipc_errors_ **ipc_add_fd** (*struct ipc_ctx* \*cinfos, *int* fd);
## Message functions
@ -75,7 +75,7 @@ _enum ipc_errors_ **ipc_message_empty** (*struct ipc_message* \*m);
char *spath; // max size: PATH_MAX, used to store unix socket path
};
struct ipc_connection_infos {
struct ipc_ctx {
struct ipc_connection_info ** cinfos;
int32_t size;
};
@ -106,7 +106,7 @@ _enum ipc_errors_ **ipc_message_empty** (*struct ipc_message* \*m);
Function **ipc_wait_event** returns an *event type* structure.\
The event may be a (dis)connection, received data or an error.\
It also can be *IPC_EVENT_TYPE_EXTRA_SOCKET* since an arbitrary file descriptor can be added to the *ipc_connection_infos* structure with **ipc_add_fd**.
It also can be *IPC_EVENT_TYPE_EXTRA_SOCKET* since an arbitrary file descriptor can be added to the *ipc_ctx* structure with **ipc_add_fd**.
```
enum ipc_event_type {

View File

@ -1,6 +1,6 @@
package=libipc # Package name.
version=0.6.0 # Package version.
version=0.7.0 # Package version.
# Our targets are the library and its documentation.
targets=(libipc man/libipc.7)

View File

@ -1,4 +1,5 @@
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
@ -13,86 +14,53 @@
// print structures
#include "message.h"
struct ipc_error service_path (char *path, const char *sname, int32_t index, int32_t version)
#include <fcntl.h>
int fd_is_valid(int fd)
{
T_R ((path == NULL), IPC_ERROR_SERVICE_PATH__NO_PATH);
T_R ((sname == NULL), IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME);
memset (path, 0, PATH_MAX);
char *rundir = getenv ("IPC_RUNDIR");
if (rundir == NULL)
rundir = RUNDIR;
snprintf (path, PATH_MAX - 1, "%s/%s-%d-%d", rundir, sname, index, version);
IPC_RETURN_NO_ERROR;
return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}
static int32_t get_max_fd (struct ipc_connection_infos *cinfos)
struct ipc_error ipc_server_init (struct ipc_ctx *ctx, const char *sname)
{
size_t i;
int32_t max = 0;
for (i = 0; i < cinfos->size; i++) {
if (cinfos->cinfos[i]->fd > max) {
max = cinfos->cinfos[i]->fd;
}
}
return max;
}
struct ipc_error ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname)
{
T_R ((env == NULL), IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM);
T_R ((srv == NULL), IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM);
T_R ((sname == NULL), IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM);
#if 0
// For server init, no need for networkd evaluation
// Declaration and instanciation of the new connection (ipc_connection_info + pollfd).
SECURE_DECLARATION (struct ipc_connection_info, srv);
srv.type = IPC_CONNECTION_TYPE_SERVER;
SECURE_DECLARATION(struct pollfd, pollfd);
pollfd.events = POLLIN;
// TODO: loop over environment variables
// any IPC_NETWORK_* should be shared with the network service
// in order to route requests over any chosen protocol stack
// ex: IPC_NETWORK_AUDIO="tor://some.example.com/"
for (size_t i = 0; env[i] != NULL; i++) {
// TODO: check for every IPC_NETWORK_* environment variable
}
#endif
// gets the service path
// Get the service path.
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TEST_IPC_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path");
// gets the service path
if (srv->spath != NULL) {
free (srv->spath);
srv->spath = NULL;
}
TEST_IPC_RR (service_path (buf, sname), "cannot get server path");
size_t s = strlen (buf);
if (s > PATH_MAX)
s = PATH_MAX;
SECURE_BUFFER_HEAP_ALLOCATION_R (srv.spath, s + 1,, IPC_ERROR_SERVER_INIT__MALLOC);
memcpy (srv.spath, buf, s);
srv.spath[s] = '\0'; // to be sure
SECURE_BUFFER_HEAP_ALLOCATION_R (srv->spath, s + 1,, IPC_ERROR_SERVER_INIT__MALLOC);
memcpy (srv->spath, buf, s);
srv->spath[s] = '\0'; // to be sure
// Socket initialisation for the service.
TEST_IPC_RETURN_ON_ERROR (usock_init (&pollfd.fd, srv.spath));
TEST_IPC_RETURN_ON_ERROR (usock_init (&srv->fd, srv->spath));
// Add the server to the listened file descriptors.
// ipc_add allocate memory then copy the data of srv and pollfd in ctx.
TEST_IPC_RR (ipc_add (ctx, &srv, &pollfd), "cannot add the server in the context");
IPC_RETURN_NO_ERROR;
}
struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m);
// when networkd is not working properly (or do not retrieve the service): srv->fd = 0
struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname)
// when ipcd is not working properly (or do not retrieve the service): srv->fd = 0
struct ipc_error ipc_contact_ipcd (int *pfd, const char *sname)
{
T_R ((srv == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM);
T_R ((sname == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM);
T_R ((pfd == NULL), IPC_ERROR_CONTACT_IPCD__NO_FD_PARAM);
T_R ((sname == NULL), IPC_ERROR_CONTACT_IPCD__NO_SERVICE_NAME_PARAM);
char *networkvar = getenv ("IPC_NETWORK");
if (networkvar == NULL) {
srv->fd = 0;
char *ipcd_var = getenv ("IPC_NETWORK");
if (ipcd_var == NULL) {
*pfd = 0;
IPC_RETURN_NO_ERROR;
}
// TODO: is there another, more interesting way to do this?
@ -100,488 +68,524 @@ struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const ch
// in order to route requests over any chosen protocol stack
// ex: IPC_NETWORK="audio tor://some.example.com/audio ;pong tls://pong.example.com/pong"
// printf ("IPC_NETWORK: %s\n", networkvar);
SECURE_BUFFER_DECLARATION (char, columnthensname, BUFSIZ);
columnthensname[0] = ';';
memcpy (columnthensname + 1, sname, strlen (sname));
if (strncmp (networkvar, sname, strlen (sname)) != 0 && strstr (networkvar, columnthensname) == NULL) {
// printf ("sname %s not found\n", sname);
srv->fd = 0;
if (strncmp (ipcd_var, sname, strlen (sname)) != 0 && strstr (ipcd_var, columnthensname) == NULL) {
*pfd = 0;
IPC_RETURN_NO_ERROR;
}
// printf ("(;)sname %s found\n", sname);
// gets the service path
// Get the service path.
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TEST_IPC_RR (service_path (buf, "network", 0, 0), "cannot get network service path");
TEST_IPC_RR (service_path (buf, "network"), "cannot get network service path");
int networkdfd = 0;
int ipcd_fd = 0;
TEST_IPC_RETURN_ON_ERROR (usock_connect (&networkdfd, buf));
TEST_IPC_RETURN_ON_ERROR (usock_connect (&ipcd_fd, buf));
SECURE_DECLARATION (struct ipc_message, msg);
msg.type = MSG_TYPE_NETWORK_LOOKUP;
msg.user_type = MSG_TYPE_NETWORK_LOOKUP;
SECURE_BUFFER_DECLARATION (char, content, BUFSIZ);
snprintf (content, BUFSIZ, "%s;%s", sname, networkvar);
snprintf (content, BUFSIZ, "%s;%s", sname, ipcd_var);
msg.length = strlen (content);
msg.payload = content;
TEST_IPC_RR (ipc_write_fd (networkdfd, &msg), "cannot send a message to networkd");
TEST_IPC_RR (ipc_write_fd (ipcd_fd, &msg), "cannot send a message to networkd");
struct ipc_error ret = ipc_receive_fd (networkdfd, &srv->fd);
struct ipc_error ret = ipc_receive_fd (ipcd_fd, pfd);
if (ret.error_code == IPC_ERROR_NONE) {
usock_close (networkdfd);
usock_close (ipcd_fd);
}
return ret;
}
struct ipc_error ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname)
// Create context, contact ipcd, connects to the service.
struct ipc_error ipc_connection_ (struct ipc_ctx *ctx, const char *sname, enum ipc_connection_type type, int *serverfd)
{
T_R ((env == NULL), IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM);
T_R ((srv == NULL), IPC_ERROR_CONNECTION__NO_SERVER);
T_R ((ctx == NULL), IPC_ERROR_CONNECTION__NO_CTX);
T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME);
TEST_IPC_P (ipc_contact_networkd (srv, sname), "error during networkd connection");
SECURE_DECLARATION(struct ipc_connection_info, srv);
srv.type = type;
SECURE_DECLARATION(struct pollfd, pollfd);
pollfd.events = POLLIN;
// if networkd did not initiate the connection
if (srv->fd <= 0) {
TEST_IPC_P (ipc_contact_ipcd (&pollfd.fd, sname), "error during networkd connection");
// if ipcd did not initiate the connection
if (pollfd.fd <= 0) {
// gets the service path
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TEST_IPC_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path");
TEST_IPC_RETURN_ON_ERROR (usock_connect (&srv->fd, buf));
TEST_IPC_RR (service_path (buf, sname), "cannot get server path");
TEST_IPC_RETURN_ON_ERROR (usock_connect (&pollfd.fd, buf));
}
// Add the server to the listened file descriptors.
TEST_IPC_RR (ipc_add (ctx, &srv, &pollfd), "cannot add the server in the context");
if (serverfd != NULL) {
*serverfd = pollfd.fd;
}
IPC_RETURN_NO_ERROR;
}
struct ipc_error ipc_server_close (struct ipc_connection_info *srv)
int ipc_ctx_fd_type (struct ipc_ctx *ctx, int fd, enum ipc_connection_type type)
{
usock_close (srv->fd);
struct ipc_error ret = usock_remove (srv->spath);
if (srv->spath != NULL) {
free (srv->spath);
srv->spath = NULL;
if (ctx == NULL) {
return -1;
}
for (size_t i = 0; i < ctx->size; i++) {
if (ctx->pollfd[i].fd == fd) {
ctx->cinfos[i].type = type;
return 0;
}
}
return -1;
}
struct ipc_error ipc_connection (struct ipc_ctx *ctx, const char *sname)
{
// Data received on the socket = messages, not new clients, and not switched (no callbacks).
return ipc_connection_ (ctx, sname, IPC_CONNECTION_TYPE_IPC, NULL);
}
struct ipc_error ipc_connection_switched (struct ipc_ctx *ctx, const char *sname, int clientfd, int *serverfd)
{
int sfd = 0;
// Data received are for switched fd (callbacks should be used).
struct ipc_error ret = ipc_connection_ (ctx
, sname
, IPC_CONNECTION_TYPE_SWITCHED
, &sfd);
if (ret.error_code != IPC_ERROR_NONE) {
return ret;
}
if (serverfd != NULL) {
*serverfd = sfd;
}
ipc_add_fd_switched (ctx, clientfd);
// ipc_ctx_fd_type (ctx, clientfd, IPC_CONNECTION_TYPE_SWITCHED);
ipc_ctx_switching_add (ctx, clientfd, sfd);
return ret;
}
struct ipc_error ipc_close (struct ipc_connection_info *p)
struct ipc_error ipc_close_all (struct ipc_ctx *ctx)
{
return usock_close (p->fd);
T_R ((ctx == NULL), IPC_ERROR_CLOSE_ALL__NO_CTX_PARAM);
for (size_t i = 0 ; i < ctx->size ; i++) {
TEST_IPC_P (ipc_close (ctx, i), "cannot close a connection in handle_message");
}
IPC_RETURN_NO_ERROR;
}
struct ipc_error ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p)
struct ipc_error ipc_close (struct ipc_ctx *ctx, uint32_t index)
{
T_R ((srv == NULL), IPC_ERROR_ACCEPT__NO_SERVICE_PARAM);
T_R ((p == NULL), IPC_ERROR_ACCEPT__NO_CLIENT_PARAM);
T_R ((ctx == NULL), IPC_ERROR_CLOSE__NO_CTX_PARAM);
TEST_IPC_RR (usock_accept (srv->fd, &p->fd), "cannot accept IPC connection");
p->type = IPC_CONNECTION_TYPE_IPC;
SECURE_DECLARATION (struct ipc_error, ret);
int fd = ctx->pollfd[index].fd;
#if 0
if (fd_is_valid (fd)) {
printf ("ipc_close: fd is valid ==> %d\n", fd);
if (ctx->cinfos[index].type == IPC_CONNECTION_TYPE_EXTERNAL) {
printf ("=== === === external fd: not closing %d\n", fd);
}
else {
ret = usock_close (fd);
}
}
else {
printf ("!!!!!!!!!!! !! !! !! IPC_CLOSE: fd is not valid!! ==> %d\n", fd);
}
#else
// Closing the file descriptor only if it is not an external connection,
// this should be handled by the libipc user application.
if (ctx->cinfos[index].type != IPC_CONNECTION_TYPE_EXTERNAL) {
ret = usock_close (fd);
}
#endif
// Verify that the close was OK.
if (ret.error_code != IPC_ERROR_NONE) {
return ret;
}
if (ctx->cinfos[index].type == IPC_CONNECTION_TYPE_SERVER) {
ret = usock_remove (ctx->cinfos[index].spath);
if (ctx->cinfos[index].spath != NULL) {
free (ctx->cinfos[index].spath);
ctx->cinfos[index].spath = NULL;
}
}
return ret;
}
// New connection from a client.
struct ipc_error ipc_accept_add (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index)
{
T_R ((ctx == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM);
T_R ((index >= ctx->size), IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX);
// Memory reallocation.
ipc_ctx_new_alloc (ctx);
int server_fd = ctx->pollfd[index].fd;
int *client_fd = &ctx->pollfd[ctx->size -1].fd;
TEST_IPC_RR (usock_accept (server_fd, client_fd), "cannot accept IPC connection");
ctx->pollfd[ctx->size -1].events = POLLIN; // Tell to poll(2) to watch for incoming data from this fd.
ctx->cinfos[ctx->size -1].type = IPC_CONNECTION_TYPE_IPC;
// Set the event structure.
uint32_t client_index = ctx->size - 1;
IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, client_index, *client_fd, NULL);
IPC_RETURN_NO_ERROR;
}
// receive then format in an ipc_message structure
struct ipc_error ipc_read (const struct ipc_connection_info *p, struct ipc_message *m)
struct ipc_error ipc_read (const struct ipc_ctx *ctx, uint32_t index, struct ipc_message *m)
{
T_R ((m == NULL), IPC_ERROR_READ__NO_MESSAGE_PARAM);
char *buf = NULL;
size_t msize = IPC_MAX_MESSAGE_SIZE;
SECURE_BUFFER_DECLARATION (char, buf, msize);
char *pbuf = buf;
// on error or closed recipient, the buffer already freed
TEST_IPC_RETURN_ON_ERROR (usock_recv (p->fd, &buf, &msize));
TEST_IPC_RETURN_ON_ERROR_FREE (ipc_message_format_read (m, buf, msize), buf);
free (buf);
// On error or closed recipient, the buffer already freed.
TEST_IPC_RETURN_ON_ERROR (usock_recv (ctx->pollfd[index].fd, &pbuf, &msize));
TEST_IPC_RETURN_ON_ERROR (ipc_message_format_read (m, buf, msize));
IPC_RETURN_NO_ERROR; // propagates ipc_message_format return
}
struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m)
{
T_R ((m == NULL), IPC_ERROR_WRITE__NO_MESSAGE_PARAM);
char *buf = NULL;
size_t msize = 0;
ipc_message_format_write (m, &buf, &msize);
SECURE_BUFFER_DECLARATION (char, buf, IPC_MAX_MESSAGE_SIZE);
char *pbuf = buf;
ipc_message_format_write (m, &pbuf, &msize);
size_t nbytes_sent = 0;
TEST_IPC_RETURN_ON_ERROR_FREE (usock_send (fd, buf, msize, &nbytes_sent), buf);
TEST_IPC_RETURN_ON_ERROR (usock_send (fd, buf, msize, &nbytes_sent));
if (buf != NULL) {
free (buf);
}
// what was sent != what should have been sent
T_R ((nbytes_sent != msize), IPC_ERROR_WRITE__NOT_ENOUGH_DATA);
T_R ((nbytes_sent != msize), IPC_ERROR_WRITE_FD__NOT_ENOUGH_DATA);
IPC_RETURN_NO_ERROR;
}
struct ipc_error ipc_write (const struct ipc_connection_info *p, const struct ipc_message *m)
// Put the message in the list of messages to send.
struct ipc_error ipc_write (struct ipc_ctx *ctx, const struct ipc_message *m)
{
return ipc_write_fd (p->fd, m);
}
struct ipc_error handle_new_connection (struct ipc_connection_info *cinfo, struct ipc_connection_infos *cinfos
, struct ipc_connection_info **new_client)
{
T_R ((cinfo == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM);
T_R ((cinfos == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM);
SECURE_BUFFER_HEAP_ALLOCATION_R (*new_client, sizeof (struct ipc_connection_info),,
IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC);
TEST_IPC_RR (ipc_accept (cinfo, *new_client), "cannot accept the client during handle_new_connection");
TEST_IPC_RR (ipc_add (cinfos, *new_client), "cannot add the new accepted client");
IPC_RETURN_NO_ERROR;
}
// new connection from a client
struct ipc_error handle_connection (struct ipc_event *event, struct ipc_connection_infos *cinfos
, struct ipc_connection_info *cinfo)
{
// connection
struct ipc_connection_info *new_client = NULL;
TEST_IPC_RR (handle_new_connection (cinfo, cinfos, &new_client), "cannot add new client");
IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client);
IPC_RETURN_NO_ERROR;
}
// new message
struct ipc_error handle_message (struct ipc_event *event, struct ipc_connection_infos *cinfos
, struct ipc_connection_info *pc, struct ipc_switchings *switchdb)
{
// if the socket is associated to another one for networkd
// read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch
if (switchdb != NULL) {
int talkingfd = pc->fd;
int correspondingfd = ipc_switching_get (switchdb, talkingfd);
if (correspondingfd != -1) {
char *buf = NULL;
size_t msize = 0;
TEST_IPC_T_P_I_R (
/* function to test */ usock_recv (talkingfd, &buf, &msize)
, /* error condition */ ret.error_code != IPC_ERROR_NONE
&& ret.error_code != IPC_ERROR_CLOSED_RECIPIENT
, /* to do on error */ if (buf != NULL) free (buf);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc)
, /* return function */ return (ret)) ;
/** TODO: there is a message, send it to the corresponding fd **/
if (msize > 0) {
size_t nbytes_sent = 0;
TEST_IPC_RETURN_ON_ERROR_FREE (usock_send (correspondingfd, buf, msize, &nbytes_sent), buf);
if (nbytes_sent != msize) {
// LOG_ERROR ("wrote not enough data from %d to fd %d", talkingfd, correspondingfd);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc);
IPC_RETURN_NO_ERROR; // FIXME: return something else, maybe?
}
// LOG_DEBUG ("received a message on fd %d => switch to fd %d", talkingfd, correspondingfd);
if (buf != NULL)
free (buf);
// everything is OK: inform networkd of a successful transfer
IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, NULL, pc);
IPC_RETURN_NO_ERROR;
} else if (msize == 0) {
int delfd;
delfd = ipc_switching_del (switchdb, talkingfd);
if (delfd >= 0) {
close (delfd);
ipc_del_fd (cinfos, delfd);
}
close (talkingfd);
ipc_del_fd (cinfos, talkingfd);
#if 0
if (delfd >= 0) {
LOG_DEBUG ("disconnection of %d (and related fd %d)", talkingfd, delfd);
} else {
LOG_DEBUG ("disconnection of %d", talkingfd);
}
#endif
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc);
IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT);
}
int found = 0;
for (size_t i = 0; i < ctx->size; i++) {
if (ctx->pollfd[i].fd == m->fd) {
ctx->pollfd[i].events |= POLLOUT;
found = 1;
}
}
// no treatment of the socket if external socket
if (pc->type == IPC_CONNECTION_TYPE_EXTERNAL) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, NULL, pc);
T_R ((found == 0), IPC_ERROR_WRITE__FD_NOT_FOUND);
// Performs a deep copy of the structure.
return ipc_messages_add (&ctx->tx, m);
}
/**
* Allocate memory then add a new connection to the context.
*/
struct ipc_error ipc_add (struct ipc_ctx *ctx, struct ipc_connection_info *p, struct pollfd *pollfd)
{
T_R ((ctx == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS);
T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT);
T_R ((pollfd == NULL), IPC_ERROR_ADD__NO_PARAM_POLLFD);
// Memory reallocation.
ipc_ctx_new_alloc (ctx);
T_R ((ctx->size <= 0), IPC_ERROR_ADD__NOT_ENOUGH_MEMORY);
ctx->cinfos[ctx->size - 1] = *p;
ctx->pollfd[ctx->size - 1] = *pollfd;
IPC_RETURN_NO_ERROR;
}
struct ipc_error ipc_del (struct ipc_ctx *ctx, uint32_t index)
{
T_R ((ctx == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM);
T_R ((ctx->cinfos == NULL || ctx->pollfd == NULL), IPC_ERROR_DEL__EMPTY_LIST);
T_R ((index >= ctx->size), IPC_ERROR_DEL__CANNOT_FIND_CLIENT);
if (ctx->cinfos[index].spath != NULL) {
free (ctx->cinfos[index].spath);
ctx->cinfos[index].spath = NULL;
}
ctx->size--;
if (ctx->size == 0) {
// free ctx->cinfos and ctx->pollfd
ipc_ctx_free (ctx);
IPC_RETURN_NO_ERROR;
}
// listen to what they have to say (disconnection or message)
// then add a client to `event`, the ipc_event structure
SECURE_DECLARATION (struct ipc_error, ret);
struct ipc_message *m = NULL;
// The last element in the array replaces the removed one.
ctx->cinfos[index] = ctx->cinfos[ctx->size];
ctx->pollfd[index] = ctx->pollfd[ctx->size];
// Reallocation of the arrays. TODO: should be optimised someday.
ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size);
ctx->pollfd = realloc (ctx->pollfd, sizeof (struct pollfd ) * ctx->size);
if (ctx->cinfos == NULL || ctx->pollfd == NULL) {
IPC_RETURN_ERROR (IPC_ERROR_DEL__EMPTIED_LIST);
}
IPC_RETURN_NO_ERROR;
}
struct ipc_error ipc_add_fd_ (struct ipc_ctx *ctx, int fd, enum ipc_connection_type type)
{
T_R ((ctx == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS);
SECURE_DECLARATION (struct ipc_connection_info, cinfo);
cinfo.type = type;
SECURE_DECLARATION (struct pollfd, pollfd);
pollfd.fd = fd;
pollfd.events = POLLIN;
return ipc_add (ctx, &cinfo, &pollfd);
}
// add a switched file descriptor to read
struct ipc_error ipc_add_fd_switched (struct ipc_ctx *ctx, int fd)
{
return ipc_add_fd_ (ctx, fd, IPC_CONNECTION_TYPE_SWITCHED);
}
// add an arbitrary file descriptor to read
struct ipc_error ipc_add_fd (struct ipc_ctx *ctx, int fd)
{
return ipc_add_fd_ (ctx, fd, IPC_CONNECTION_TYPE_EXTERNAL);
}
// remove a connection from its file descriptor
struct ipc_error ipc_del_fd (struct ipc_ctx *ctx, int fd)
{
T_R ((ctx == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS);
T_R ((ctx->cinfos == NULL || ctx->pollfd == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST);
for (size_t i = 0; i < ctx->size; i++) {
if (ctx->pollfd[i].fd == fd) {
return ipc_del (ctx, i);
}
}
IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT);
}
struct ipc_error handle_writing_message (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index)
{
int txfd = ctx->pollfd[index].fd;
int mfd;
struct ipc_message *m;
for (size_t i = 0; ctx->tx.size ; i++) {
m = &ctx->tx.messages[i];
mfd = m->fd;
if (txfd == mfd) {
TEST_IPC_RR (ipc_write_fd (txfd, m), "cannot send a message to the client");
// Freeing the message structure.
ipc_message_empty (m);
// Removing the message from the context.
ipc_messages_del (&ctx->tx, i); // remove the message indexed by i
break; // The message has been sent
}
}
IPC_EVENT_SET (event, IPC_EVENT_TYPE_TX, index, ctx->pollfd[index].fd, NULL);
IPC_RETURN_NO_ERROR;
}
struct ipc_error handle_new_message (struct ipc_event *event, struct ipc_ctx *ctx, int index)
{
SECURE_DECLARATION (struct ipc_error, ret);
// Listen to what they have to say (disconnection or message)
// then add a client to `event`, the ipc_event structure.
struct ipc_message *m = NULL;
SECURE_BUFFER_HEAP_ALLOCATION_R (m, sizeof (struct ipc_message),, IPC_ERROR_HANDLE_MESSAGE__NOT_ENOUGH_MEMORY);
// current talking client
ret = ipc_read (pc, m);
ret = ipc_read (ctx, index, m);
if (ret.error_code != IPC_ERROR_NONE && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) {
struct ipc_error rvalue = ret; // store the final return value
ipc_message_empty (m);
free (m);
// if there is a problem, just remove the client
TEST_IPC_P (ipc_close (pc), "cannot close a connection in handle_message");
TEST_IPC_P (ipc_del (cinfos, pc), "cannot delete a connection in handle_message");
TEST_IPC_P (ipc_close (ctx, index), "cannot close a connection in handle_message");
TEST_IPC_P (ipc_del (ctx, index), "cannot delete a connection in handle_message");
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, ctx->pollfd[index].fd, NULL);
return rvalue;
}
// disconnection: close the client then delete it from cinfos
// disconnection: close the client then delete it from ctx
if (ret.error_code == IPC_ERROR_CLOSED_RECIPIENT) {
TEST_IPC_P (ipc_close (pc), "cannot close a connection on closed recipient in handle_message");
TEST_IPC_P (ipc_del (cinfos, pc), "cannot delete a connection on closed recipient in handle_message");
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, ctx->pollfd[index].fd, NULL);
TEST_IPC_P (ipc_close (ctx, index), "cannot close a connection on closed recipient in handle_message");
TEST_IPC_P (ipc_del (ctx, index), "cannot delete a connection on closed recipient in handle_message");
ipc_message_empty (m);
free (m);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc);
// warning: do not forget to free the ipc_client structure
IPC_RETURN_NO_ERROR;
}
IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc);
// The message carries the fd it was received on.
m->fd = ctx->pollfd[index].fd;
IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, index, ctx->pollfd[index].fd, m);
IPC_RETURN_NO_ERROR;
}
struct ipc_error ipc_wait_event_networkd (struct ipc_connection_infos *cinfos
, struct ipc_connection_info *cinfo // NULL for clients
, struct ipc_event *event, struct ipc_switchings *switchdb
, double *timer)
struct ipc_error
handle_writing_switched_message (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index)
{
T_R ((cinfos == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM);
T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM);
return fd_switching_write (event, ctx, index);
}
struct ipc_error
handle_switched_message(struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index)
{
return fd_switching_read (event, ctx, index);
}
/* timer is in ms */
struct ipc_error ipc_wait_event (struct ipc_ctx *ctx, struct ipc_event *event, int *timer)
{
T_R ((ctx == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM);
T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM);
IPC_EVENT_CLEAN (event);
size_t i, j;
/* master file descriptor list */
fd_set master;
fd_set readf;
int32_t n;
/* clear the master and temp sets */
FD_ZERO (&master);
FD_ZERO (&readf);
/* maximum file descriptor number */
/* keep track of the biggest file descriptor */
int32_t fdmax = get_max_fd (cinfos);
/* listening socket descriptor */
int32_t listener;
if (cinfo != NULL) {
listener = cinfo->fd;
/* add the listener to the master set */
FD_SET (listener, &master);
/* if listener is max fd */
if (fdmax < listener)
fdmax = listener;
}
for (i = 0; i < cinfos->size; i++) {
FD_SET (cinfos->cinfos[i]->fd, &master);
}
readf = master;
struct timeval *ptimeout = NULL;
SECURE_DECLARATION (struct timeval, timeout);
if (timer != NULL && *timer > 0.0) {
timeout.tv_sec = (long) *timer;
timeout.tv_usec = (long) ((long)((*timer) * 1000000) % 1000000);
ptimeout = &timeout;
}
T_PERROR_RIPC ((select (fdmax + 1, &readf, NULL, NULL, ptimeout) == -1), "select", IPC_ERROR_WAIT_EVENT__SELECT);
if (ptimeout != NULL) {
*timer = (double) timeout.tv_sec + (timeout.tv_usec / 1000000.0);
if (*timer == 0) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_TIMER, NULL, NULL);
IPC_RETURN_NO_ERROR;
}
}
for (i = 0; i <= (size_t) fdmax; i++) {
if (FD_ISSET (i, &readf)) {
if (cinfo != NULL && i == (size_t) listener) {
return handle_connection (event, cinfos, cinfo);
} else {
for (j = 0; j < cinfos->size; j++) {
if (i == (size_t) cinfos->cinfos[j]->fd) {
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
}
}
for (size_t i = 0; i < ctx->tx.size; i++) {
for (size_t y = 0; y < ctx->size; y++) {
if (ctx->pollfd[y].fd == ctx->tx.messages[i].fd) {
ctx->pollfd[y].events |= POLLOUT;
break;
}
}
}
IPC_RETURN_NO_ERROR;
}
struct timeval tv_1;
memset (&tv_1, 0, sizeof(struct timeval));
struct ipc_error ipc_wait_event (struct ipc_connection_infos *cinfos
, struct ipc_connection_info *cinfo // NULL for clients
, struct ipc_event *event, double *timer)
{
return ipc_wait_event_networkd (cinfos, cinfo, event, NULL, timer);
}
struct timeval tv_2;
memset (&tv_2, 0, sizeof(struct timeval));
// store and remove only pointers on allocated structures
struct ipc_error ipc_add (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p)
{
T_R ((cinfos == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS);
T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT);
gettimeofday(&tv_1, NULL);
cinfos->size++;
if (cinfos->size == 1 && cinfos->cinfos == NULL) {
// first allocation
SECURE_BUFFER_HEAP_ALLOCATION_R (cinfos->cinfos, sizeof (struct ipc_connection_info),,
IPC_ERROR_ADD__MALLOC);
} else {
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
if ((n = poll(ctx->pollfd, ctx->size, *timer)) < 0) {
IPC_RETURN_ERROR (IPC_ERROR_WAIT_EVENT__POLL);
}
T_R ((cinfos->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST);
gettimeofday(&tv_2, NULL);
cinfos->cinfos[cinfos->size - 1] = p;
IPC_RETURN_NO_ERROR;
}
int nb_sec_ms = (tv_2.tv_sec - tv_1.tv_sec) * 1000;
int nb_usec_ms = (tv_2.tv_usec - tv_1.tv_usec) / 1000;
int time_elapsed_ms = (nb_sec_ms + nb_usec_ms);
struct ipc_error ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p)
{
T_R ((cinfos == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM);
T_R ((p == NULL), IPC_ERROR_DEL__NO_CLIENT_PARAM);
T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL__EMPTY_LIST);
// Handle memory fuckery, 'cause low level programming is fun.
if (time_elapsed_ms >= *timer) {
*timer = 0;
}
else {
*timer -= time_elapsed_ms;
}
size_t i;
for (i = 0; i < cinfos->size; i++) {
if (cinfos->cinfos[i] == p) {
// TODO: possible memory leak if the ipc_connection_info is not free'ed
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size - 1];
cinfos->size--;
if (cinfos->size == 0) {
ipc_connections_free (cinfos);
} else {
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
// Timeout.
if (n == 0) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_TIMER, 0, 0, NULL);
IPC_RETURN_NO_ERROR;
}
if (cinfos->cinfos == NULL) {
IPC_RETURN_ERROR (IPC_ERROR_DEL__EMPTIED_LIST);
}
for (size_t i = 0; i <= ctx->size; i++) {
// Something to read or connection.
if (ctx->pollfd[i].revents & POLLIN) {
// In case there is something to read for the server socket: new client.
if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SERVER) {
return ipc_accept_add (event, ctx, i);
}
IPC_RETURN_NO_ERROR;
// fd is switched: using callbacks for IO operations.
if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SWITCHED) {
#if 0
int fd_validity = fd_is_valid (ctx->pollfd[i].fd);
if (! fd_validity) {
printf ("switch happening in C: %d FD IS INVALID:::::::::: IM BROKEN INSIIIIIIIDE\n", ctx->pollfd[i].fd);
}
#endif
return handle_switched_message (event, ctx, i);
}
// No treatment of the socket if external socket: the libipc user should handle IO operations.
if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_EXTERNAL) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, i, ctx->pollfd[i].fd, NULL);
IPC_RETURN_NO_ERROR;
}
return handle_new_message (event, ctx, i);
}
}
IPC_RETURN_ERROR (IPC_ERROR_DEL__CANNOT_FIND_CLIENT);
}
// Something can be sent.
if (ctx->pollfd[i].revents & POLLOUT) {
ctx->pollfd[i].events &= ~POLLOUT;
void ipc_connections_close (struct ipc_connection_infos *cinfos)
{
if (cinfos->cinfos != NULL) {
for (size_t i = 0; i < cinfos->size; i++) {
ipc_close (cinfos->cinfos[i]);
free (cinfos->cinfos[i]);
// fd is switched: using callbacks for IO operations.
if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SWITCHED) {
return handle_writing_switched_message (event, ctx, i);
}
return handle_writing_message (event, ctx, i);
}
free (cinfos->cinfos);
cinfos->cinfos = NULL;
}
cinfos->size = 0;
}
void ipc_connections_free (struct ipc_connection_infos *cinfos)
{
if (cinfos->cinfos != NULL) {
for (size_t i = 0; i < cinfos->size; i++) {
free (cinfos->cinfos[i]);
// Disconnection.
if (ctx->pollfd[i].revents & POLLHUP) {
/** IPC_EVENT_SET: event, type, index, fd, message */
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, i, ctx->pollfd[i].fd, NULL);
return ipc_close (ctx, i);
}
free (cinfos->cinfos);
cinfos->cinfos = NULL;
}
cinfos->size = 0;
}
// create the client service structure
struct ipc_error ipc_connection_gen (struct ipc_connection_info *cinfo
, uint32_t index, uint32_t version
, int fd, char type)
{
T_R ((cinfo == NULL), IPC_ERROR_CONNECTION_GEN__NO_CINFO);
cinfo->type = type;
cinfo->version = version;
cinfo->index = index;
cinfo->fd = fd;
} /** for loop: end of the message handling */
IPC_RETURN_NO_ERROR;
}
// add an arbitrary file descriptor to read
struct ipc_error ipc_add_fd (struct ipc_connection_infos *cinfos, int fd)
{
T_R ((cinfos == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS);
struct ipc_connection_info *cinfo = NULL;
SECURE_BUFFER_HEAP_ALLOCATION_R (cinfo, sizeof (struct ipc_connection_info),,
IPC_ERROR_ADD_FD__NOT_ENOUGH_MEMORY);
ipc_connection_gen (cinfo, 0, 0, fd, IPC_CONNECTION_TYPE_EXTERNAL);
return ipc_add (cinfos, cinfo);
}
// remove a connection from its file descriptor
struct ipc_error ipc_del_fd (struct ipc_connection_infos *cinfos, int fd)
{
T_R ((cinfos == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS);
T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST);
size_t i;
for (i = 0; i < cinfos->size; i++) {
if (cinfos->cinfos[i]->fd == fd) {
cinfos->cinfos[i]->fd = -1;
free (cinfos->cinfos[i]);
cinfos->size--;
if (cinfos->size == 0) {
// free cinfos->cinfos
ipc_connections_free (cinfos);
} else {
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size];
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
if (cinfos->cinfos == NULL) {
IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__EMPTIED_LIST);
}
}
IPC_RETURN_NO_ERROR;
}
}
IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT);
}

48
src/context.c Normal file
View File

@ -0,0 +1,48 @@
#include "ipc.h"
/**
* PERFORMANCE POINT:
* Realloc is performed at each new user. There is plenty of room for improvement,
* for example by managing allocations of thousands of structures at once.
* WARNING: Store and remove only pointers on allocated structures.
*/
struct ipc_error ipc_ctx_new_alloc (struct ipc_ctx *ctx)
{
ctx->size++;
// Memory could be not allocated, yet.
if (ctx->size == 1 && ctx->cinfos == NULL && ctx->pollfd == NULL) {
SECURE_BUFFER_HEAP_ALLOCATION_R (ctx->cinfos, sizeof (struct ipc_connection_info),,
IPC_ERROR_ADD__MALLOC);
SECURE_BUFFER_HEAP_ALLOCATION_R (ctx->pollfd, sizeof (struct pollfd),, IPC_ERROR_ADD__MALLOC_POLLFD);
} else {
ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size);
ctx->pollfd = realloc (ctx->pollfd, sizeof (struct pollfd ) * ctx->size);
}
T_R ((ctx->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST);
T_R ((ctx->pollfd == NULL), IPC_ERROR_ADD__EMPTY_LIST);
// Clean the last entry.
memset (&ctx->cinfos[ctx->size -1], 0, sizeof (struct ipc_connection_info));
memset (&ctx->pollfd[ctx->size -1], 0, sizeof (struct pollfd));
IPC_RETURN_NO_ERROR;
}
void ipc_ctx_free (struct ipc_ctx *ctx)
{
if (ctx->cinfos != NULL) {
free (ctx->cinfos);
ctx->cinfos = NULL;
}
if (ctx->pollfd != NULL) {
free (ctx->pollfd);
ctx->pollfd = NULL;
}
ctx->size = 0;
ipc_switching_free(&ctx->switchdb);
ipc_messages_free (&ctx->tx);
}

View File

@ -12,22 +12,15 @@ static struct ipc_errors_verbose ipc_errors_verbose[] = {
{IPC_ERROR_NONE, "no error"}
, {IPC_ERROR_CLOSED_RECIPIENT, "closed recipient"}
, {IPC_ERROR_SERVER_INIT__NO_DIR_CANNOT_CREATE_IT,
"ipc_server_init: no directory for ipc and cannot to create it"}
, {IPC_ERROR_SERVER_INIT__NON_WRITABLE_DIR, "ipc_server_init: non writable directory for ipc"}
, {IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM, "ipc_server_init: no environment param"}
, {IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM , "ipc_server_init: no service param"}
, {IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM, "ipc_server_init: no server name param"}
, {IPC_ERROR_SERVER_INIT__MALLOC , "ipc_server_init: error on malloc function"}
, {IPC_ERROR_CONNECTION__NO_SERVER, "ipc_connection: no server parameter"}
, {IPC_ERROR_CONNECTION__NO_SERVICE_NAME, "ipc_connection: no service name parameter"}
, {IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM, "ipc_connection: no environment param"}
, {IPC_ERROR_USOCK_CONNECT__CONNECT, "ipc_connection: error on the connect function"}
, {IPC_ERROR_CONNECTION_GEN__NO_CINFO, "ipc_connection_gen: no cinfo"}
, {IPC_ERROR_ACCEPT__NO_SERVICE_PARAM, "ipc_accept: no service param"}
, {IPC_ERROR_ACCEPT__NO_CLIENT_PARAM , "ipc_accept: no client param"}
@ -36,7 +29,7 @@ static struct ipc_errors_verbose ipc_errors_verbose[] = {
, {IPC_ERROR_PROVIDE_FD__SENDMSG , "ipc_provide_fd: sendmsg function"}
, {IPC_ERROR_WRITE__NO_MESSAGE_PARAM, "ipc_write: no message param"}
, {IPC_ERROR_WRITE__NOT_ENOUGH_DATA , "ipc_write: no enough data sent"}
, {IPC_ERROR_WRITE_FD__NOT_ENOUGH_DATA , "ipc_write: no enough data sent"}
, {IPC_ERROR_READ__NO_MESSAGE_PARAM , "ipc_read: no message param"}
, {IPC_ERROR_HANDLE_MESSAGE__NOT_ENOUGH_MEMORY , "handle_message: not enough memory"}
@ -47,8 +40,8 @@ static struct ipc_errors_verbose ipc_errors_verbose[] = {
, {IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM, "ipc_wait_event: no clients param"}
, {IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM , "ipc_wait_event: no event param"}
, {IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM, "ipc_contact_networkd: no service name param"}
, {IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM , "ipc_contact_networkd: no server param"}
, {IPC_ERROR_CONTACT_IPCD__NO_SERVICE_NAME_PARAM, "ipc_contact_ipcd: no service name param"}
, {IPC_ERROR_CONTACT_IPCD__NO_SERVER_PARAM , "ipc_contact_ipcd: no server param"}
, {IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC, "ipc_handle_new_connection: error on malloc function"}
@ -127,6 +120,29 @@ static struct ipc_errors_verbose ipc_errors_verbose[] = {
, {IPC_ERROR_DIR_SETUP__DIRECTORY_NOT_WRITABLE, "directory_setup_: directory not writable"}
, {IPC_ERROR_DIRECTORY_SETUP__PATH_PARAM , "directory_setup_: no path param"}
, {IPC_ERROR_SERVER_INIT__NOT_ENOUGH_MEMORY, "IPC_ERROR_SERVER_INIT__NOT_ENOUGH_MEMORY"}
, {IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY, "IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY"}
, {IPC_ERROR_CTX_INIT__NO_CONTEXT_PARAM, "IPC_ERROR_CTX_INIT__NO_CONTEXT_PARAM"}
, {IPC_ERROR_CTX_INIT__CONTEXT_ALREADY_INIT, "IPC_ERROR_CTX_INIT__CONTEXT_ALREADY_INIT"}
, {IPC_ERROR_ADD__MALLOC_POLLFD, "IPC_ERROR_ADD__MALLOC_POLLFD"}
, {IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST, "IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST"}
, {IPC_ERROR_ADD_MESSAGE_TO_SEND__MALLOC, "IPC_ERROR_ADD_MESSAGE_TO_SEND__MALLOC"}
, {IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGE, "IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGE"}
, {IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGES, "IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGES"}
, {IPC_ERROR_CONNECTION__NO_CTX, "IPC_ERROR_CONNECTION__NO_CTX"}
, {IPC_ERROR_CTX_INIT__MALLOC_CTX, "IPC_ERROR_CTX_INIT__MALLOC_CTX"}
, {IPC_ERROR_CTX_INIT__MALLOC_POLLFD, "IPC_ERROR_CTX_INIT__MALLOC_POLLFD"}
, {IPC_ERROR_CONTACT_IPCD__NO_FD_PARAM, "IPC_ERROR_CONTACT_IPCD__NO_FD_PARAM"}
, {IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX, "IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX"}
, {IPC_ERROR_DEL_MESSAGE_TO_SEND__NO_PARAM_MESSAGES, "IPC_ERROR_DEL_MESSAGE_TO_SEND__NO_PARAM_MESSAGES"}
, {IPC_ERROR_MESSAGE_DEL__INDEX_ERROR, "IPC_ERROR_MESSAGE_DEL__INDEX_ERROR"}
, {IPC_ERROR_MESSAGE_DEL__EMPTY_LIST, "IPC_ERROR_MESSAGE_DEL__EMPTY_LIST"}
, {IPC_ERROR_ADD__NO_PARAM_POLLFD, "IPC_ERROR_ADD__NO_PARAM_POLLFD"}
, {IPC_ERROR_WRITE__FD_NOT_FOUND, "IPC_ERROR_WRITE__FD_NOT_FOUND"}
, {IPC_ERROR_FD_SWITCHING__NO_FD_RECORD, "IPC_ERROR_FD_SWITCHING__NO_FD_RECORD"}
, {IPC_ERROR_CLOSE_ALL__NO_CTX_PARAM, "IPC_ERROR_CLOSE_ALL__NO_CTX_PARAM" }
, {IPC_ERROR_CLOSE__NO_CTX_PARAM, "IPC_ERROR_CLOSE__NO_CTX_PARAM"}
};
const char *ipc_errors_get (enum ipc_error_code e)

247
src/ipc.h
View File

@ -9,6 +9,8 @@
#include <errno.h> // error numbers
#include <time.h>
#include <poll.h>
/***
* global defaults
**/
@ -73,13 +75,23 @@ enum msg_types {
enum ipc_event_type {
IPC_EVENT_TYPE_NOT_SET = 0
, IPC_EVENT_TYPE_ERROR = 1
, IPC_EVENT_TYPE_EXTRA_SOCKET = 2
, IPC_EVENT_TYPE_SWITCH = 3
, IPC_EVENT_TYPE_CONNECTION = 4
, IPC_EVENT_TYPE_DISCONNECTION = 5
, IPC_EVENT_TYPE_MESSAGE = 6
, IPC_EVENT_TYPE_LOOKUP = 7
, IPC_EVENT_TYPE_TIMER = 8
, IPC_EVENT_TYPE_EXTRA_SOCKET = 2 // Message received from a non IPC socket.
, IPC_EVENT_TYPE_SWITCH = 3 // Message to send to a corresponding fd.
, IPC_EVENT_TYPE_CONNECTION = 4 // New user.
, IPC_EVENT_TYPE_DISCONNECTION = 5 // User disconnected.
, IPC_EVENT_TYPE_MESSAGE = 6 // New message.
, IPC_EVENT_TYPE_LOOKUP = 7 // Client asking for a service through ipcd.
, IPC_EVENT_TYPE_TIMER = 8 // Timeout in the poll(2) function.
, IPC_EVENT_TYPE_TX = 9 // Message sent.
};
// For IO callbacks (switching).
enum ipccb {
IPC_CB_NO_ERROR = 0 // No error. A message was generated.
, IPC_CB_FD_CLOSING = 1 // The fd is closing.
, IPC_CB_FD_ERROR = 2 // Generic error.
, IPC_CB_PARSING_ERROR = 3 // The message was read but with errors.
, IPC_CB_IGNORE = 4 // The message should be ignored (protocol specific).
};
/**
@ -88,8 +100,6 @@ enum ipc_event_type {
*/
enum ipc_error_code {
IPC_ERROR_NONE = 0
, IPC_ERROR_SERVER_INIT__NON_WRITABLE_DIR = 1
, IPC_ERROR_SERVER_INIT__NO_DIR_CANNOT_CREATE_IT = 2
, IPC_ERROR_HANDLE_MESSAGE__NOT_ENOUGH_MEMORY = 3
, IPC_ERROR_CLOSED_RECIPIENT = 4
, IPC_ERROR_SERVICE_PATH__NO_PATH = 5
@ -99,12 +109,10 @@ enum ipc_error_code {
, IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM = 9
, IPC_ERROR_SERVER_INIT__MALLOC = 10
, IPC_ERROR_WRITE__NO_MESSAGE_PARAM = 11
, IPC_ERROR_WRITE__NOT_ENOUGH_DATA = 12
, IPC_ERROR_WRITE_FD__NOT_ENOUGH_DATA = 12
, IPC_ERROR_READ__NO_MESSAGE_PARAM = 13
, IPC_ERROR_CONNECTION__NO_SERVER = 14
, IPC_ERROR_CONNECTION__NO_SERVICE_NAME = 15
, IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM = 16
, IPC_ERROR_CONNECTION_GEN__NO_CINFO = 17
, IPC_ERROR_ACCEPT__NO_SERVICE_PARAM = 18
, IPC_ERROR_ACCEPT__NO_CLIENT_PARAM = 19
, IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM = 20
@ -123,8 +131,8 @@ enum ipc_error_code {
, IPC_ERROR_DEL_FD__EMPTIED_LIST = 33
, IPC_ERROR_DEL_FD__EMPTY_LIST = 34
, IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT = 35
, IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM = 36
, IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM = 37
, IPC_ERROR_CONTACT_IPCD__NO_SERVICE_NAME_PARAM = 36
, IPC_ERROR_CONTACT_IPCD__NO_SERVER_PARAM = 37
, IPC_ERROR_DEL__EMPTY_LIST = 38
, IPC_ERROR_DEL__EMPTIED_LIST = 39
, IPC_ERROR_DEL__CANNOT_FIND_CLIENT = 40
@ -173,6 +181,31 @@ enum ipc_error_code {
, IPC_ERROR_DIR_SETUP__NOT_A_DIRECTORY = 83
, IPC_ERROR_DIR_SETUP__DIRECTORY_NOT_WRITABLE = 84
, IPC_ERROR_DIRECTORY_SETUP__PATH_PARAM = 85
, IPC_ERROR_SERVER_INIT__NOT_ENOUGH_MEMORY = 86
, IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY = 87
, IPC_ERROR_CTX_INIT__NO_CONTEXT_PARAM = 88
, IPC_ERROR_CTX_INIT__CONTEXT_ALREADY_INIT = 89
, IPC_ERROR_ADD__MALLOC_POLLFD = 90
, IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST = 91
, IPC_ERROR_ADD_MESSAGE_TO_SEND__MALLOC = 92
, IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGE = 93
, IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGES = 94
, IPC_ERROR_CONNECTION__NO_CTX = 95
, IPC_ERROR_CTX_INIT__MALLOC_CTX = 96
, IPC_ERROR_CTX_INIT__MALLOC_POLLFD = 97
, IPC_ERROR_CONTACT_IPCD__NO_FD_PARAM = 98
, IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX = 99
, IPC_ERROR_DEL_MESSAGE_TO_SEND__NO_PARAM_MESSAGES = 100
, IPC_ERROR_MESSAGE_DEL__INDEX_ERROR = 101
, IPC_ERROR_MESSAGE_DEL__EMPTY_LIST = 102
, IPC_ERROR_ADD__NO_PARAM_POLLFD = 103
, IPC_ERROR_WRITE__FD_NOT_FOUND = 104
, IPC_ERROR_ADD__NOT_ENOUGH_MEMORY = 105
, IPC_ERROR_WAIT_EVENT__POLL = 106
, IPC_ERROR_FD_SWITCHING__NO_FD_RECORD = 107
, IPC_ERROR_CLOSE_ALL__NO_CTX_PARAM = 108
, IPC_ERROR_CLOSE__NO_CTX_PARAM = 109
};
struct ipc_error {
@ -186,45 +219,98 @@ struct ipc_error {
// with the error_message string in the ipc_error structure.
const char *ipc_errors_get (enum ipc_error_code e);
enum ipc_connection_type {
IPC_CONNECTION_TYPE_IPC = 0
, IPC_CONNECTION_TYPE_EXTERNAL = 1
/** Messages received = new connections. */
, IPC_CONNECTION_TYPE_SERVER = 2
/** IO operations should go through registered callbacks. */
, IPC_CONNECTION_TYPE_SWITCHED = 3
};
struct ipc_connection_info {
uint32_t version;
uint32_t index;
int32_t fd;
char type; // server, client, arbitrary fd
enum ipc_connection_type type;
char *spath; // max size: PATH_MAX
};
struct ipc_connection_infos {
struct ipc_connection_info **cinfos;
struct ipc_message {
char type; // Internal message type.
char user_type; // User-defined message type.
int fd; // File descriptor concerned about this message.
uint32_t length; // Payload length.
char *payload;
};
struct ipc_messages {
struct ipc_message *messages;
size_t size;
};
struct ipc_message {
char type;
char user_type;
uint32_t length;
char *payload;
struct ipc_switching {
int orig;
int dest;
enum ipccb (*orig_in) (int origin_fd, struct ipc_message *m);
enum ipccb (*orig_out) (int origin_fd, struct ipc_message *m);
enum ipccb (*dest_in) (int origin_fd, struct ipc_message *m);
enum ipccb (*dest_out) (int origin_fd, struct ipc_message *m);
};
struct ipc_switchings {
struct ipc_switching *collection;
size_t size;
};
void ipc_message_copy (struct ipc_message *m
, uint32_t fd
, uint8_t type
, uint8_t utype
, char *payload
, uint32_t paylen);
struct ipc_error ipc_messages_del (struct ipc_messages *messages, uint32_t index);
/**
* Context of the whole networking state.
*/
struct ipc_ctx {
/**
* Keep track of connections.
*/
struct ipc_connection_info *cinfos;
/**
* List of "pollfd" structures within cinfos, so we can pass it to poll(2).
*/
struct pollfd *pollfd;
/**
* Size of the connection list.
*/
size_t size;
/**
* List of messages to send, once the fd are available.
*/
struct ipc_messages tx;
/**
* Relations between fd.
*/
struct ipc_switchings switchdb;
};
struct ipc_event {
enum ipc_event_type type;
struct ipc_connection_info *origin;
void *m; // message pointer
uint32_t index;
int origin;
void *m; // message pointer
};
/***
* ipc event macros
**/
#define IPC_EVENT_SET(pevent,type_,message_,origin_) {\
#define IPC_EVENT_SET(pevent,type_,index_, origin_fd_,message_) {\
pevent->type = type_; \
pevent->index = index_; \
pevent->origin = origin_fd_; \
pevent->m = message_; \
pevent->origin = origin_; \
};
enum ipc_connection_types {
IPC_CONNECTION_TYPE_IPC = 0
, IPC_CONNECTION_TYPE_EXTERNAL = 1
};
#define IPC_EVENT_CLEAN(pevent) {\
@ -240,35 +326,32 @@ enum ipc_connection_types {
* main public functions
**/
struct ipc_error ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname);
struct ipc_error ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname);
struct ipc_error ipc_wait_event (struct ipc_ctx *, struct ipc_event *, int *timer);
struct ipc_error ipc_server_close (struct ipc_connection_info *srv);
struct ipc_error ipc_close (struct ipc_connection_info *p);
struct ipc_error ipc_server_init (struct ipc_ctx *ctx, const char *sname);
struct ipc_error ipc_connection (struct ipc_ctx *ctx, const char *sname);
struct ipc_error ipc_connection_switched (struct ipc_ctx *ctx, const char *sname, int clientfd, int *serverfd);
struct ipc_error ipc_read (const struct ipc_connection_info *, struct ipc_message *m);
struct ipc_error ipc_write (const struct ipc_connection_info *, const struct ipc_message *m);
struct ipc_error ipc_close (struct ipc_ctx *ctx, uint32_t index);
struct ipc_error ipc_close_all (struct ipc_ctx *ctx);
struct ipc_error ipc_wait_event (struct ipc_connection_infos *clients
, struct ipc_connection_info *srv
, struct ipc_event *event, double *timer);
void ipc_ctx_free (struct ipc_ctx *ctx);
struct ipc_error ipc_read (const struct ipc_ctx *, uint32_t index, struct ipc_message *m);
struct ipc_error ipc_write (struct ipc_ctx *, const struct ipc_message *m);
struct ipc_error fd_switching_read (struct ipc_event *event, struct ipc_ctx *ctx, int index);
struct ipc_error fd_switching_write (struct ipc_event *event, struct ipc_ctx *ctx, int index);
// store and remove only pointers on allocated structures
struct ipc_error ipc_add (struct ipc_connection_infos *, struct ipc_connection_info *);
struct ipc_error ipc_del (struct ipc_connection_infos *, struct ipc_connection_info *);
struct ipc_error ipc_add (struct ipc_ctx *, struct ipc_connection_info *, struct pollfd *);
struct ipc_error ipc_del (struct ipc_ctx *, uint32_t index);
// add an arbitrary file descriptor to read
struct ipc_error ipc_add_fd (struct ipc_connection_infos *cinfos, int fd);
struct ipc_error ipc_del_fd (struct ipc_connection_infos *cinfos, int fd);
void ipc_connections_free (struct ipc_connection_infos *);
// create the client service structure
struct ipc_error ipc_connection_gen (struct ipc_connection_info *cinfo
, uint32_t index, uint32_t version
, int fd, char type);
void ipc_connections_close (struct ipc_connection_infos *cinfos);
struct ipc_error ipc_add_fd (struct ipc_ctx *ctx, int fd);
// add a switched file descriptor to read
struct ipc_error ipc_add_fd_switched (struct ipc_ctx *ctx, int fd);
struct ipc_error ipc_del_fd (struct ipc_ctx *ctx, int fd);
/***
* message functions
@ -286,6 +369,9 @@ struct ipc_error ipc_message_format_data (struct ipc_message *m, char utype, con
struct ipc_error ipc_message_format_server_close (struct ipc_message *m);
struct ipc_error ipc_message_empty (struct ipc_message *m);
struct ipc_error ipc_messages_add (struct ipc_messages *, const struct ipc_message *);
void ipc_messages_free (struct ipc_messages *);
// Switch cases macros
// print on error
#define ERROR_CASE(e,f,m) case e : { fprintf (stderr, "function %s: %s", f, m); } break;
@ -294,42 +380,37 @@ struct ipc_error ipc_message_empty (struct ipc_message *m);
* non public functions
**/
void ipc_connection_print (struct ipc_connection_info *cinfo);
void ipc_connections_print (struct ipc_connection_infos *cinfos);
struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m);
struct ipc_error ipc_ctx_init (struct ipc_ctx **);
struct ipc_error ipc_ctx_new_alloc (struct ipc_ctx *ctx);
struct ipc_error service_path (char *path, const char *sname);
struct ipc_error handle_writing_message (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index);
struct ipc_error ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p);
struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname);
struct ipc_error service_path (char *path, const char *sname, int32_t index, int32_t version);
void ipc_ctx_print (struct ipc_ctx *ctx);
// Last parameter is the index for the server fd in the context structure.
struct ipc_error ipc_accept_add (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index);
struct ipc_error ipc_contact_ipcd (int *pfd, const char *sname);
struct ipc_error service_path (char *path, const char *sname);
/***
* networkd enumerations, structures and functions
* ipcd enumerations, structures and functions
**/
struct ipc_switching {
int orig;
int dest;
};
struct ipc_switchings {
struct ipc_switching *collection;
size_t size;
};
struct networkd {
int cpt;
struct ipc_connection_info *srv;
struct ipc_connection_infos *clients;
struct ipc_switchings *TCP_TO_IPC;
};
struct ipc_error ipc_wait_event_networkd (struct ipc_connection_infos *cinfos
, struct ipc_connection_info *cinfo // cinfo is NULL for clients
, struct ipc_event *event, struct ipc_switchings *switchdb, double *timer);
void ipc_ctx_switching_add (struct ipc_ctx *ctx, int orig, int dest);
void ipc_switching_add (struct ipc_switchings *is, int orig, int dest);
int ipc_switching_del (struct ipc_switchings *is, int fd);
int ipc_switching_get (struct ipc_switchings *is, int fd);
void ipc_switching_free (struct ipc_switchings *is);
void ipc_switching_callbacks_ (struct ipc_ctx *ctx, int fd
, enum ipccb (*cb_in )(int fd, struct ipc_message *m));
void ipc_switching_callbacks (
struct ipc_ctx *ctx
, int fd
, enum ipccb (*cb_in )(int fd, struct ipc_message *m)
, enum ipccb (*cb_out)(int fd, struct ipc_message *m));
int ipc_ctx_fd_type (struct ipc_ctx *ctx, int fd, enum ipc_connection_type type);
void ipc_switching_print (struct ipc_switchings *is);

View File

@ -145,3 +145,87 @@ struct ipc_error ipc_message_empty (struct ipc_message *m)
IPC_RETURN_NO_ERROR;
}
// store and remove only pointers on allocated structures
struct ipc_error ipc_messages_add (struct ipc_messages *messages, const struct ipc_message *message)
{
T_R ((messages == NULL), IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGES);
T_R ((message == NULL), IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGE);
messages->size++;
if (messages->size == 1 && messages->messages == NULL) {
// first allocation
SECURE_BUFFER_HEAP_ALLOCATION_R (messages->messages, sizeof (struct ipc_message),,
IPC_ERROR_ADD_MESSAGE_TO_SEND__MALLOC);
} else {
messages->messages = realloc (messages->messages, sizeof (struct ipc_message) * messages->size);
}
T_R ((messages->messages == NULL), IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST);
// DEEP COPY.
messages->messages[messages->size -1] = *message;
if (message->length > 0 && message->payload != NULL) {
messages->messages[messages->size -1].payload = malloc(message->length * sizeof (char));
strncpy(messages->messages[messages->size -1].payload, message->payload, message->length);
}
else {
messages->messages[messages->size -1].payload = NULL;
}
IPC_RETURN_NO_ERROR;
}
// Remove only pointers on allocated structures.
struct ipc_error ipc_messages_del (struct ipc_messages *messages, uint32_t index)
{
T_R ((messages == NULL), IPC_ERROR_DEL_MESSAGE_TO_SEND__NO_PARAM_MESSAGES);
T_R ((messages->size == 0 || index >= messages->size), IPC_ERROR_MESSAGE_DEL__INDEX_ERROR);
// NOT A DEEP COPY.
messages->size--;
if (messages->size == 0) {
free (messages->messages);
messages->messages = NULL;
}
else {
messages->messages[index] = messages->messages[messages->size];
messages->messages = realloc (messages->messages, sizeof (struct ipc_message) * messages->size);
T_R ((messages->messages == NULL), IPC_ERROR_MESSAGE_DEL__EMPTY_LIST);
}
IPC_RETURN_NO_ERROR;
}
void ipc_message_copy (struct ipc_message *m
, uint32_t fd
, uint8_t type
, uint8_t utype
, char *payload
, uint32_t paylen)
{
// printf("starting the message copy\n");
m->fd = fd;
m->type = type;
m->user_type = utype;
m->length = paylen;
if (m->payload != NULL) {
free(m->payload);
}
// printf("BEFORE THE PAYLOAD COPY\n");
m->payload = malloc(sizeof(char) * paylen);
memcpy(m->payload, payload, paylen);
// printf("PAYLOAD COPY DONE\n");
}
void ipc_messages_free (struct ipc_messages *messages)
{
if (messages != NULL)
{
if (messages->messages != NULL)
{
free(messages->messages);
messages->messages = 0;
}
}
}

View File

@ -20,12 +20,12 @@
/**
* TODO:
* describe a protocol to get this working into networkd
* asking networkd for a fd with an URI
* describe a protocol to get this working into ipcd
* asking ipcd for a fd with an URI
* URI should contain: who (the service name), where (destination), how (protocol)
* networkd initiates a communication with the requested service
* networkd sends the fd
* get a networkd working with this
* ipcd initiates a communication with the requested service
* ipcd sends the fd
* get a ipcd working with this
*/
struct ipc_error ipc_receive_fd (int sock, int *fd)
@ -81,9 +81,25 @@ struct ipc_error ipc_provide_fd (int sock, int fd)
IPC_RETURN_NO_ERROR;
}
void ipc_ctx_switching_add (struct ipc_ctx *ctx, int orig, int dest)
{
ipc_switching_add (&ctx->switchdb, orig, dest);
}
void ipc_switching_add (struct ipc_switchings *is, int orig, int dest)
{
is->collection = realloc (is->collection, sizeof (struct ipc_switching) * (is->size + 1));
// printf ("ipc_switching_add START: switchdb has %ld entries\n", is->size);
if (is->collection == NULL) {
// printf ("switchdb collection is null\n");
is->collection = malloc (sizeof (struct ipc_switching) * (is->size + 1));
}
else {
// printf ("switchdb collection isn't null\n");
is->collection = realloc (is->collection, sizeof (struct ipc_switching) * (is->size + 1));
}
/** TODO: less brutal approach */
if (is->collection == NULL) {
fprintf (stderr, __FILE__ " error realloc line %d", __LINE__);
exit (EXIT_FAILURE);
@ -93,6 +109,13 @@ void ipc_switching_add (struct ipc_switchings *is, int orig, int dest)
is->collection[is->size - 1].orig = orig;
is->collection[is->size - 1].dest = dest;
is->collection[is->size - 1].orig_in = NULL;
is->collection[is->size - 1].dest_in = NULL;
is->collection[is->size - 1].orig_out = NULL;
is->collection[is->size - 1].dest_out = NULL;
// printf ("ipc_switching_add END: switchdb has %ld entries\n", is->size);
}
int ipc_switching_del (struct ipc_switchings *is, int fd)
@ -110,13 +133,12 @@ int ipc_switching_del (struct ipc_switchings *is, int fd)
is->collection[i].orig = is->collection[is->size - 1].orig;
is->collection[i].dest = is->collection[is->size - 1].dest;
size_t s = (is->size - 1) > 0 ? (is->size - 1) : 1;
is->collection = realloc (is->collection, sizeof (struct ipc_switching) * s);
if (is->collection == NULL) {
/** TODO: not sure we want this behavior */
fprintf (stderr, __FILE__ " error realloc line %d", __LINE__);
exit (EXIT_FAILURE);
if (is->size == 1) {
free(is->collection);
is->collection = NULL;
}
else {
is->collection = realloc (is->collection, sizeof (struct ipc_switching) * (is->size-1));
}
is->size--;
@ -127,6 +149,28 @@ int ipc_switching_del (struct ipc_switchings *is, int fd)
return -1;
}
/**
* 0 = fd is origin
* 1 = fd is dest
* -1 = not found
*/
int ipc_switching_get_ (const struct ipc_switchings *is
, int fd
, struct ipc_switching **s)
{
for (size_t i = 0; i < is->size; i++) {
if (is->collection[i].orig == fd) {
*s = &is->collection[i];
return 0;
} else if (is->collection[i].dest == fd) {
*s = &is->collection[i];
return 1;
}
}
return -1;
}
int ipc_switching_get (struct ipc_switchings *is, int fd)
{
for (size_t i = 0; i < is->size; i++) {
@ -151,3 +195,268 @@ void ipc_switching_free (struct ipc_switchings *is)
}
is->size = 0;
}
enum ipccb
default_cb_in(int fd, struct ipc_message *m)
{
// TODO: fix buffer size for switching messages
size_t msize = 4096;
char buf[msize];
char *pbuf = buf;
// By default, usock_read (a wrapper around read(2)) is used.
{ /** Some macros use "ret" as a variable name, so this is to be sure. */
struct ipc_error ret = usock_recv (fd, &pbuf, &msize);
if (ret.error_code != IPC_ERROR_NONE) {
if (ret.error_code == IPC_ERROR_CLOSED_RECIPIENT) {
return IPC_CB_FD_CLOSING;
}
return IPC_CB_FD_ERROR;
}
}
/** There is a message, send it to the corresponding fd **/
if (msize > 0) {
struct ipc_error ret = ipc_message_format_read (m, buf, msize);
if (ret.error_code != IPC_ERROR_NONE) {
return IPC_CB_PARSING_ERROR;
}
return IPC_CB_NO_ERROR;
}
// By default, if msize <= 0 the fd should be closed.
return IPC_CB_FD_CLOSING;
}
enum ipccb
default_cb_out(int fd, struct ipc_message *m)
{
size_t msize = 0;
SECURE_DECLARATION (struct ipc_error, ret);
SECURE_BUFFER_DECLARATION (char, buf, IPC_MAX_MESSAGE_SIZE);
char *pbuf = buf;
ipc_message_format_write (m, &pbuf, &msize);
size_t nbytes_sent = 0;
ret = usock_send (fd, buf, msize, &nbytes_sent);
// On error or if what was sent != what should have been sent.
if (ret.error_code != IPC_ERROR_NONE || nbytes_sent != msize) {
return IPC_CB_FD_ERROR;
}
return IPC_CB_NO_ERROR;
}
void ipc_switching_callbacks_ (struct ipc_ctx *ctx, int fd
, enum ipccb (*cb_in )(int fd, struct ipc_message *m))
{
ipc_switching_callbacks (ctx, fd, cb_in, NULL);
}
void ipc_switching_callbacks (
struct ipc_ctx *ctx
, int fd
, enum ipccb (*cb_in )(int fd, struct ipc_message *m)
, enum ipccb (*cb_out)(int fd, struct ipc_message *m))
{
struct ipc_switching *sw = NULL;
int is_valid = ipc_switching_get_ (&ctx->switchdb, fd, &sw);
if (is_valid == -1) {
return;
}
if (sw->orig == fd) {
sw->orig_in = cb_in;
sw->orig_out = cb_out;
}
else {
sw->dest_in = cb_in;
sw->dest_out = cb_out;
}
}
/**
* fd_switching_read allows to read a message from a switched fd.
*/
struct ipc_error fd_switching_read (struct ipc_event *event, struct ipc_ctx *ctx, int index)
{
// printf ("fd_switching_read\n");
// If the socket is associated to another one for ipcd:
// read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch.
T_R ((ctx->switchdb.size == 0), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD);
int talkingfd = ctx->pollfd[index].fd;
int dest_fd = -1;
struct ipc_switching *sw = NULL;
struct ipc_message m;
memset(&m, 0, sizeof (struct ipc_message));
enum ipccb r;
int is_valid = 0;
is_valid = ipc_switching_get_ (&ctx->switchdb, talkingfd, &sw);
T_R ((is_valid == -1), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD);
if (sw->orig == talkingfd) {
dest_fd = sw->dest;
if (sw->orig_in == NULL) {
r = default_cb_in (talkingfd, &m);
}
else {
r = (*sw->orig_in)(talkingfd, &m);
}
}
else {
dest_fd = sw->orig;
if (sw->dest_in == NULL) {
r = default_cb_in (talkingfd, &m);
}
else {
r = (*sw->dest_in)(talkingfd, &m);
}
}
// Message reception OK: reading the message and put it in the list of messages to send.
if (r == IPC_CB_NO_ERROR) {
// In case of message reception:
// 1. put the message in the list to be sent
m.fd = dest_fd;
ipc_write (ctx, &m);
// 2. delete the message (a deep copy has been made)
ipc_message_empty (&m);
// 3. set event IPC_EVENT_TYPE_SWITCH, inform ipcd of a successful reception.
IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, index, ctx->pollfd[index].fd, NULL);
// 4. IPC_RETURN_NO_ERROR
IPC_RETURN_NO_ERROR;
}
// Message reception OK: no message to transfer.
// This is applied to protocol-specific messages, for example when the client
// has to communicate with the proxy, not the service.
if (r == IPC_CB_IGNORE) {
printf ("IGNORING REQUEST\n");
// In case of message reception:
// 1. set event IPC_EVENT_TYPE_SWITCH, inform ipcd of a successful reception.
IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, index, ctx->pollfd[index].fd, NULL);
// 2. IPC_RETURN_NO_ERROR
IPC_RETURN_NO_ERROR;
}
/**
* NOTE: In any other case, the fd is, or should be closed.
*/
// 1. close and remove both fd from switchdb
close (sw->dest);
ipc_del_fd (ctx, sw->dest);
// Should not close the client: it's the job of the libipc user application.
// XXX: this may be normal, but should be documented.
// close (talkingfd);
ipc_del_fd (ctx, talkingfd);
ipc_switching_del (&ctx->switchdb, talkingfd);
// 2. set event (either error or disconnection)
if (r == IPC_CB_FD_CLOSING) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, talkingfd, NULL);
}
else {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, talkingfd, NULL);
}
// 3. return IPC_ERROR_CLOSED_RECIPIENT
IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT);
}
/**
* fd_switching_write allows to read a message from a switched fd.
*/
struct ipc_error fd_switching_write (struct ipc_event *event, struct ipc_ctx *ctx, int index)
{
// printf ("fd_switching_write\n");
// If the socket is associated to another one for ipcd:
// read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch.
T_R ((ctx->switchdb.size == 0), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD);
int output_fd = ctx->pollfd[index].fd;
struct ipc_switching *sw = NULL;
struct ipc_message *m = NULL;
size_t i;
// search for the next message to send for output_fd fd.
for (i = 0; ctx->tx.size ; i++) {
if (ctx->tx.messages[i].fd == output_fd) {
m = &ctx->tx.messages[i];
break;
}
}
// In case there is no message for the fd: the error will be catched.
enum ipccb r;
int is_valid = 0;
is_valid = ipc_switching_get_ (&ctx->switchdb, output_fd, &sw);
T_R ((is_valid == -1), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD);
if (sw->orig == output_fd) {
if (sw->orig_in == NULL) {
r = default_cb_out (output_fd, m);
}
else {
r = (*sw->orig_out)(output_fd, m);
}
}
else {
if (sw->dest_in == NULL) {
r = default_cb_out (output_fd, m);
}
else {
r = (*sw->dest_out)(output_fd, m);
}
}
// Whether or not the message has been sent, it should be removed.
// Freeing the message structure.
ipc_message_empty (m);
// Removing the message from the context.
ipc_messages_del (&ctx->tx, i); // remove the message indexed by i
// Message reception OK: reading the message and put it in the list of messages to send.
if (r == IPC_CB_NO_ERROR) {
// 1. set event IPC_EVENT_TYPE_SWITCH, inform ipcd of a successful reception.
IPC_EVENT_SET (event, IPC_EVENT_TYPE_TX, index, output_fd, NULL);
// 2. IPC_RETURN_NO_ERROR
IPC_RETURN_NO_ERROR;
}
/**
* NOTE: In any other case, the fd is, or should be closed.
*/
// 1. close and remove both fd from switchdb
int delfd = ipc_switching_del (&ctx->switchdb, output_fd);
if (delfd >= 0) {
close (delfd);
ipc_del_fd (ctx, delfd);
}
close (output_fd);
ipc_del_fd (ctx, output_fd);
// 2. set event (either error or disconnection)
if (r == IPC_CB_FD_CLOSING) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, output_fd, NULL);
}
else {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, output_fd, NULL);
}
// 3. return IPC_ERROR_CLOSED_RECIPIENT
IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT);
}

View File

@ -1,20 +1,51 @@
#include "ipc.h"
void ipc_connection_print (struct ipc_connection_info *cinfo)
void ipc_ctx_print (struct ipc_ctx *ctx)
{
T_R_NOTHING ((cinfo == NULL));
printf ("Context contains:\n");
for (size_t i = 0; i < ctx->size; i++) {
printf ("- fd %d\t", ctx->pollfd[i].fd);
#if 0
LOG_DEBUG ("fd %d: index %d, version %d, type %c, path %s"
, cinfo->fd , cinfo->index, cinfo->version, cinfo->type
, (cinfo->spath == NULL) ? "-" : cinfo->spath);
#endif
}
switch (ctx->cinfos[i].type) {
case IPC_CONNECTION_TYPE_IPC: {
printf ("- ipc\n");
break;
}
case IPC_CONNECTION_TYPE_EXTERNAL: {
printf ("- external\n");
break;
}
case IPC_CONNECTION_TYPE_SERVER: {
printf ("- external\n");
break;
}
case IPC_CONNECTION_TYPE_SWITCHED: {
printf ("- switched\n");
break;
}
}
}
void ipc_connections_print (struct ipc_connection_infos *cinfos)
{
for (size_t i = 0; i < cinfos->size; i++) {
ipc_connection_print (cinfos->cinfos[i]);
if (ctx->switchdb.size > 0) {
printf ("Context.switchdb contains:\n");
for (size_t i = 0; i < ctx->switchdb.size; i++) {
printf ("- %d <-> %d\n"
, ctx->switchdb.collection[i].orig
, ctx->switchdb.collection[i].dest);
}
}
else {
printf ("Context.switchdb is empty\n");
}
if (ctx->tx.size > 0) {
printf ("Context.tx contains:\n");
for (size_t i = 0; i < ctx->tx.size; i++) {
printf ("- message to %d\n", ctx->tx.messages[i].fd);
}
}
else {
printf ("Context.tx is empty\n");
}
}

19
src/service_path.c Normal file
View File

@ -0,0 +1,19 @@
#include "ipc.h"
struct ipc_error
service_path (char *path, const char *sname)
{
T_R ((path == NULL), IPC_ERROR_SERVICE_PATH__NO_PATH);
T_R ((sname == NULL), IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME);
memset (path, 0, PATH_MAX);
char *rundir = getenv ("IPC_RUNDIR");
if (rundir == NULL)
rundir = RUNDIR;
snprintf (path, PATH_MAX - 1, "%s/%s", rundir, sname);
IPC_RETURN_NO_ERROR;
}

View File

@ -40,15 +40,6 @@ struct ipc_error usock_recv (const int32_t fd, char **buf, size_t * len)
if (*len == 0)
*len = IPC_MAX_MESSAGE_SIZE;
if (*buf == NULL) {
// do not allocate too much memory
if (*len > IPC_MAX_MESSAGE_SIZE) {
*len = IPC_MAX_MESSAGE_SIZE;
}
SECURE_BUFFER_HEAP_ALLOCATION (*buf, *len + IPC_HEADER_SIZE,,
IPC_RETURN_ERROR (IPC_ERROR_USOCK_RECV__HEAP_ALLOCATION));
}
uint32_t msize = 0;
uint32_t msize_read = 0;
@ -76,10 +67,6 @@ struct ipc_error usock_recv (const int32_t fd, char **buf, size_t * len)
T_R ((msize > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_USOCK_RECV__MESSAGE_SIZE);
msize_read += ret_recv - IPC_HEADER_SIZE;
} else if (ret_recv < 0) {
if (*buf != NULL) {
free (*buf);
*buf = NULL;
}
*len = 0;
switch (errno) {
@ -130,10 +117,6 @@ struct ipc_error usock_recv (const int32_t fd, char **buf, size_t * len)
// 1 on none byte received, indicates a closed recipient
if (ret_recv == 0) {
if (*buf != NULL) {
free (*buf);
*buf = NULL;
}
*len = 0;
IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT);
}

View File

@ -6,28 +6,30 @@
#define SERVICE_NAME "pong"
int main(int argc, char * argv[], char **env)
int main(int argc, char * argv[])
{
argc = (int) argc;
argv = (char **) argv;
SECURE_DECLARATION(struct ipc_error, ret);
SECURE_DECLARATION(struct ipc_connection_info,service);
SECURE_DECLARATION(struct ipc_ctx, ctx);
SECURE_DECLARATION(struct ipc_event, event);
ret = ipc_connection (env, &service, SERVICE_NAME);
ret = ipc_connection (&ctx, SERVICE_NAME);
if (ret.error_code != IPC_ERROR_NONE) {
printf ("error: %s\n", ipc_errors_get(ret.error_code));
return EXIT_FAILURE;
}
// long timer = 10;
// int timer = 10000; // 10 seconds
// ret = ipc_wait_event (services, struct ipc_event *event, &timer);
// if (ret.error_code != IPC_ERROR_NONE) {
// return EXIT_FAILURE;
// }
ret = ipc_close (&service);
ret = ipc_close_all (&ctx);
if (ret.error_code != IPC_ERROR_NONE) {
printf ("error: %s\n", ipc_errors_get(ret.error_code));
return EXIT_FAILURE;
}

View File

@ -6,31 +6,30 @@
#define SERVICE_NAME "pong"
int main(int argc, char * argv[], char **env)
int main(int argc, char * argv[])
{
argc = (int) argc;
argv = (char **) argv;
SECURE_DECLARATION(struct ipc_connection_info,srv);
long timer = 10;
SECURE_DECLARATION(struct ipc_ctx, ctx);
int timer = 10000; // 10 seconds timer
printf ("func 01 - server init...\n");
TEST_IPC_Q(ipc_server_init (env, &srv, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q(ipc_server_init (&ctx, SERVICE_NAME), EXIT_FAILURE);
printf ("func 01 - server init ok\n");
SECURE_DECLARATION(struct ipc_connection_infos, clients);
SECURE_DECLARATION(struct ipc_event,event);
SECURE_DECLARATION(struct ipc_event, event);
printf ("func 01 - service polling...\n");
// listen only for a single client
TEST_IPC_Q(ipc_wait_event (&clients, &srv, &event, &timer), EXIT_FAILURE);
TEST_IPC_Q(ipc_wait_event (&ctx, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_TIMER : {
fprintf(stderr, "time up!\n");
timer = 10;
timer = 10000;
};
break;
case IPC_EVENT_TYPE_CONNECTION :
@ -49,11 +48,11 @@ int main(int argc, char * argv[], char **env)
break;
}
printf ("func 01 - closing clients...\n");
ipc_connections_free (&clients);
printf ("func 01 - closing server...\n");
TEST_IPC_Q(ipc_server_close(&srv), EXIT_FAILURE);
TEST_IPC_Q(ipc_close_all(&ctx), EXIT_FAILURE);
printf ("func 01 - closing ctx...\n");
ipc_ctx_free (&ctx);
return EXIT_SUCCESS;
}

View File

@ -13,48 +13,50 @@
fprintf(stderr, "error while %s: %s\n", msg, err);\
}
void non_interactive (char *env[])
void non_interactive ()
{
struct ipc_message m;
memset (&m, 0, sizeof (struct ipc_message));
SECURE_DECLARATION(struct ipc_connection_info, srv);
SECURE_DECLARATION(struct ipc_message, m);
SECURE_DECLARATION(struct ipc_ctx, ctx);
// init service
TEST_IPC_Q(ipc_connection (env, &srv, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q(ipc_connection (&ctx, SERVICE_NAME), EXIT_FAILURE);
printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen(MSG) +1, (int) strlen(MSG), MSG);
int server_fd = ctx.pollfd[0].fd;
printf ("msg for fd %d to send (%ld): %.*s\n"
, server_fd
, (ssize_t) strlen(MSG) +1, (int) strlen(MSG), MSG);
TEST_IPC_Q(ipc_message_format_data (&m, /* type */ 'a', MSG, (ssize_t) strlen(MSG) +1), EXIT_FAILURE);
TEST_IPC_Q(ipc_write (&srv, &m), EXIT_FAILURE);
TEST_IPC_Q(ipc_read (&srv, &m), EXIT_FAILURE);
m.fd = server_fd;
TEST_IPC_Q(ipc_write_fd (server_fd, &m), EXIT_FAILURE);
TEST_IPC_Q(ipc_read (&ctx, 0 /* only one option */, &m), EXIT_FAILURE);
printf ("msg recv: %s\n", m.payload);
ipc_message_empty (&m);
TEST_IPC_Q(ipc_close (&srv), EXIT_FAILURE);
TEST_IPC_Q(ipc_close_all (&ctx), EXIT_FAILURE);
ipc_ctx_free (&ctx);
}
void interactive (char *env[])
#if 0
void interactive ()
{
SECURE_DECLARATION(struct ipc_connection_info, srv);
// index and version should be filled
srv.index = 0;
srv.version = 0;
SECURE_DECLARATION(struct ipc_ctx, ctx);
// init service
TEST_IPC_Q(ipc_connection (env, &srv, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q(ipc_connection (&ctx, SERVICE_NAME), EXIT_FAILURE);
int server_fd = ctx.pollfd[0].fd;
SECURE_DECLARATION(struct ipc_event, event);
SECURE_DECLARATION(struct ipc_connection_infos, services);
TEST_IPC_Q(ipc_add (&services, &srv), EXIT_FAILURE);
long timer = 10;
while (1) {
printf ("msg to send: ");
fflush (stdout);
TEST_IPC_Q(ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE);
TEST_IPC_Q(ipc_wait_event (&ctx, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_TIMER: {
@ -71,14 +73,16 @@ void interactive (char *env[])
ipc_message_empty (m);
free (m);
ipc_connections_free (&services);
TEST_IPC_Q(ipc_close_all (&ctx), EXIT_FAILURE);
TEST_IPC_Q(ipc_close (&srv), EXIT_FAILURE);
ipc_ctx_free (&ctx);
exit (EXIT_SUCCESS);
}
TEST_IPC_Q(ipc_write (&srv, m), EXIT_FAILURE);
m->fd = server_fd;
TEST_IPC_Q(ipc_write (&ctx, m), EXIT_FAILURE);
}
break;
case IPC_EVENT_TYPE_MESSAGE:
@ -96,16 +100,19 @@ void interactive (char *env[])
}
}
}
#endif
int main (int argc, char *argv[], char *env[])
//int main (int argc, char *argv[])
int main (void)
{
argc = argc; // warnings
argv = argv; // warnings
non_interactive ();
#if 0
if (argc == 1)
non_interactive (env);
non_interactive ();
else
interactive (env);
interactive ();
#endif
return EXIT_SUCCESS;
}

View File

@ -14,71 +14,67 @@
int cpt = 0;
struct ipc_connection_info *srv = 0;
struct ipc_connection_infos *clients;
struct ipc_ctx *ctx;
void main_loop ()
{
SECURE_DECLARATION(struct ipc_error, ret);
SECURE_DECLARATION(struct ipc_event, event);
clients = malloc (sizeof (struct ipc_connection_infos));
memset(clients, 0, sizeof(struct ipc_connection_infos));
SECURE_DECLARATION(struct ipc_event,event);
long timer = 10;
int timer = 10000;
while(1) {
// ipc_wait_event provides one event at a time
// warning: event->m is free'ed if not NULL
ret = ipc_wait_event (clients, srv, &event, &timer);
ret = ipc_wait_event (ctx, &event, &timer);
if (ret.error_code != IPC_ERROR_NONE && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) {
PRINTERR(ret,"service poll event");
// the application will shut down, and close the service
TEST_IPC_Q(ipc_server_close (srv), EXIT_FAILURE);
TEST_IPC_Q(ipc_close_all (ctx), EXIT_FAILURE);
exit (EXIT_FAILURE);
}
switch (event.type) {
case IPC_EVENT_TYPE_TIMER: {
fprintf(stderr, "time up!\n");
timer = 10;
timer = 10000;
};
break;
case IPC_EVENT_TYPE_CONNECTION: {
cpt++;
printf ("connection: %d clients connected\n", cpt);
printf ("new client has the fd %d\n", ((struct ipc_connection_info*) event.origin)->fd);
// printf ("new connection (fd %d): %d ctx connected\n", event.origin, cpt);
};
break;
case IPC_EVENT_TYPE_DISCONNECTION:
{
cpt--;
printf ("disconnection: %d clients remaining\n", cpt);
// free the ipc_connection_info structure
free (event.origin);
// printf ("disconnection (fd %d): %d clients remaining\n", event.origin, cpt);
};
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
if (m->length > 0) {
printf ("message received (type %d): %.*s\n", m->type, m->length, m->payload);
// printf ("message received (type %d): %.*s\n", m->type, m->length, m->payload);
}
ret = ipc_write (event.origin, m);
m->fd = event.origin;
ret = ipc_write (ctx, m);
if (ret.error_code != IPC_ERROR_NONE) {
PRINTERR(ret,"server write");
}
};
break;
case IPC_EVENT_TYPE_TX:
{
// printf ("a message was sent\n");
}
break;
case IPC_EVENT_TYPE_ERROR:
{
fprintf (stderr, "a problem happened with client %d\n"
, ((struct ipc_connection_info*) event.origin)->fd);
fprintf (stderr, "a problem happened with client %d\n", event.origin);
};
break;
default :
@ -97,48 +93,34 @@ void exit_program(int signal)
{
printf("Quitting, signal: %d\n", signal);
// free remaining clients
for (size_t i = 0; i < clients->size ; i++) {
struct ipc_connection_info *cli = clients->cinfos[i];
if (cli != NULL) {
free (cli);
}
clients->cinfos[i] = NULL;
}
ipc_connections_free (clients);
free (clients);
// the application will shut down, and close the service
TEST_IPC_Q(ipc_server_close (srv), EXIT_FAILURE);
free (srv);
TEST_IPC_Q(ipc_close_all (ctx), EXIT_FAILURE);
// free remaining ctx
ipc_ctx_free (ctx);
free (ctx);
exit(EXIT_SUCCESS);
}
/*
* service ping-pong: send back everything sent by the clients
* service ping-pong: send back everything sent by the ctx
* stop the program on SIG{TERM,INT,ALRM,USR{1,2},HUP} signals
*/
int main(int argc, char * argv[], char **env)
int main(void)
{
argc = argc; // warnings
argv = argv; // warnings
printf ("pid = %d\n", getpid ());
srv = malloc (sizeof (struct ipc_connection_info));
if (srv == NULL) {
ctx = malloc (sizeof (struct ipc_ctx));
if (ctx == NULL) {
exit (1);
}
memset (srv, 0, sizeof (struct ipc_connection_info));
srv->index = 0;
srv->version = 0;
memset (ctx, 0, sizeof (struct ipc_ctx));
TEST_IPC_Q(ipc_server_init (env, srv, PONGD_SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q(ipc_server_init (ctx, PONGD_SERVICE_NAME), EXIT_FAILURE);
struct ipc_connection_info * srv = &ctx->cinfos[0];
printf ("Listening on %s.\n", srv->spath);
printf("MAIN: server created\n" );

View File

@ -9,7 +9,7 @@
// test the behavior of the server when the client never read its messages
void send_message (struct ipc_connection_info *ci)
void send_message (struct ipc_ctx *ctx)
{
SECURE_DECLARATION (struct ipc_message, m);
SECURE_MALLOC (m.payload, 5, exit(EXIT_FAILURE));
@ -18,23 +18,24 @@ void send_message (struct ipc_connection_info *ci)
m.user_type = 42;
m.length = 5;
ipc_write (ci, &m);
ipc_write_fd (ctx->pollfd[0].fd /* only one connection */, &m);
ipc_message_empty (&m);
}
void read_message (struct ipc_connection_info *ci)
void read_message (struct ipc_ctx *ctx)
{
#if 0
SECURE_DECLARATION(struct ipc_event, event);
SECURE_DECLARATION(struct ipc_connection_infos, clients);
SECURE_DECLARATION (struct ipc_message, m);
long timer = 10;
int timer = 10000;
TEST_IPC_Q(ipc_read (ci, &m), EXIT_FAILURE);
// ctx, index, message
TEST_IPC_Q(ipc_read (ctx, 0 /* only one server here */, &m), EXIT_FAILURE);
ipc_wait_event (&clients, NULL, &event, &timer);
ipc_wait_event (ctx, &event, &timer);
switch (event.type) {
case IPC_EVENT_TYPE_MESSAGE : {
@ -52,37 +53,34 @@ void read_message (struct ipc_connection_info *ci)
break;
}
ipc_connections_free (&clients);
ipc_ctx_free (ctx);
#else
SECURE_DECLARATION (struct ipc_message, m);
TEST_IPC_Q(ipc_read (ci, &m), EXIT_FAILURE);
TEST_IPC_Q(ipc_read (ctx, 0 /* only one server here */, &m), EXIT_FAILURE);
printf ("received message: %*.s\n", m.length, m.payload);
free (m.payload);
#endif
}
int main(int argc, char * argv[], char **env)
int main(void)
{
argc = argc;
argv = argv;
SECURE_DECLARATION(struct ipc_connection_info,srv1);
SECURE_DECLARATION(struct ipc_connection_info,srv2);
SECURE_DECLARATION(struct ipc_ctx, ctx1);
SECURE_DECLARATION(struct ipc_ctx, ctx2);
SECURE_DECLARATION(struct ipc_event, event);
TEST_IPC_Q (ipc_connection (env, &srv1, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q (ipc_connection (env, &srv2, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q (ipc_connection (&ctx1, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q (ipc_connection (&ctx2, SERVICE_NAME), EXIT_FAILURE);
send_message (&srv1);
read_message (&srv1);
send_message (&ctx1);
read_message (&ctx1);
TEST_IPC_Q (ipc_close (&srv1), EXIT_FAILURE);
TEST_IPC_Q (ipc_close_all (&ctx1), EXIT_FAILURE);
send_message (&srv2);
read_message (&srv2);
send_message (&ctx2);
read_message (&ctx2);
TEST_IPC_Q (ipc_close (&srv2), EXIT_FAILURE);
TEST_IPC_Q (ipc_close_all (&ctx2), EXIT_FAILURE);
return EXIT_SUCCESS;
}

View File

@ -7,43 +7,46 @@
#define SERVICE_NAME "pong"
int main_loop(int argc, char * argv[], char **env)
int main_loop(int argc, char * argv[])
{
argc = argc;
argv = argv;
SECURE_DECLARATION (struct ipc_connection_info, srv);
long timer = 10;
SECURE_DECLARATION (struct ipc_ctx, ctx);
int timer = 10000; // in ms
printf ("func 03 - server init...\n");
TEST_IPC_Q (ipc_server_init (env, &srv, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q (ipc_server_init (&ctx, SERVICE_NAME), EXIT_FAILURE);
printf ("func 03 - server init ok\n");
SECURE_DECLARATION (struct ipc_connection_infos, clients);
SECURE_DECLARATION (struct ipc_event, event);
printf ("func 01 - service polling...\n");
// listen only for a single client
while (1) {
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&clients, &srv, &event, &timer), EXIT_FAILURE);
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&ctx, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_TIMER : {
fprintf (stderr, "time up!");
timer = 10;
fprintf (stderr, "time up!\n");
timer = 10000;
}
break;
case IPC_EVENT_TYPE_CONNECTION : {
printf ("connection establishment: %d \n", event.origin->fd);
printf ("connection establishment: %d \n", event.origin);
}
break;
case IPC_EVENT_TYPE_DISCONNECTION : {
printf ("client %d disconnecting\n", event.origin->fd);
printf ("client %d disconnecting\n", event.origin);
};
break;
case IPC_EVENT_TYPE_MESSAGE : {
printf ("received message: %s\n", ((struct ipc_message*) event.m)->payload);
ipc_write (event.origin, (struct ipc_message*) event.m);
ipc_write (&ctx, (struct ipc_message*) event.m);
}
break;
case IPC_EVENT_TYPE_TX : {
printf ("message sent to fd %d\n", event.origin);
}
break;
case IPC_EVENT_TYPE_NOT_SET :
@ -56,10 +59,11 @@ int main_loop(int argc, char * argv[], char **env)
}
}
printf ("func 03 - closing clients...\n");
ipc_connections_free (&clients);
printf ("func 03 - closing server...\n");
TEST_IPC_Q (ipc_server_close(&srv), EXIT_FAILURE);
TEST_IPC_Q (ipc_close_all(&ctx), EXIT_FAILURE);
printf ("func 03 - freeing the context\n");
ipc_ctx_free (&ctx);
return 0;
}
@ -71,7 +75,7 @@ void exit_program(int signal)
}
int main(int argc, char * argv[], char **env)
int main(int argc, char * argv[])
{
signal (SIGHUP, exit_program);
signal (SIGALRM, exit_program);
@ -79,6 +83,6 @@ int main(int argc, char * argv[], char **env)
signal (SIGUSR2, exit_program);
signal (SIGTERM, exit_program);
signal (SIGINT, exit_program);
main_loop (argc, argv, env);
main_loop (argc, argv);
return EXIT_SUCCESS;
}

View File

@ -9,7 +9,7 @@
// test the behavior of the server when the client never read its messages
void send_message (struct ipc_connection_info *ci)
void send_message (struct ipc_ctx *ctx)
{
SECURE_DECLARATION (struct ipc_message, m);
SECURE_MALLOC (m.payload, 1, exit(EXIT_FAILURE));
@ -17,18 +17,20 @@ void send_message (struct ipc_connection_info *ci)
m.type = MSG_TYPE_DATA;
m.user_type = 42;
m.length = 0;
m.fd = ctx->pollfd[0].fd;
ipc_write (ci, &m);
// ipc_write_fd = write now, without waiting the fd to become available
ipc_write_fd (ctx->pollfd[0].fd, &m);
ipc_message_empty (&m);
}
void read_message (struct ipc_connection_info *ci)
void read_message (struct ipc_ctx *ctx)
{
SECURE_DECLARATION (struct ipc_message, m);
ipc_read (ci, &m);
ipc_read (ctx, 0 /* there is only one valid index */, &m);
if (m.length > 0) {
printf ("received message: %*.s\n", m.length, m.payload);
}
@ -41,19 +43,16 @@ void read_message (struct ipc_connection_info *ci)
free (m.payload);
}
int main(int argc, char * argv[], char **env)
int main(void)
{
argc = argc;
argv = argv;
SECURE_DECLARATION(struct ipc_ctx, ctx);
SECURE_DECLARATION(struct ipc_connection_info,srv1);
TEST_IPC_Q(ipc_connection (&ctx, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q(ipc_connection (env, &srv1, SERVICE_NAME), EXIT_FAILURE);
send_message (&ctx);
read_message (&ctx);
send_message (&srv1);
read_message (&srv1);
TEST_IPC_Q(ipc_close (&srv1), EXIT_FAILURE);
TEST_IPC_Q(ipc_close_all (&ctx), EXIT_FAILURE);
return EXIT_SUCCESS;
}

View File

@ -1,4 +1,5 @@
#define _BSD_SOURCE
// #define _BSD_SOURCE
#define _DEFAULT_SOURCE
#include "../src/ipc.h"
@ -12,9 +13,9 @@
#define DEFAULT_MSG "coucou"
int main(int argc, char * argv[], char **env)
int main(int argc, char * argv[])
{
SECURE_DECLARATION(struct ipc_connection_info,srv);
SECURE_DECLARATION(struct ipc_ctx, ctx);
SECURE_DECLARATION(struct ipc_event, event);
SECURE_DECLARATION (struct ipc_message, write_m);
@ -46,20 +47,21 @@ int main(int argc, char * argv[], char **env)
memcpy(message_str, DEFAULT_MSG, strlen(DEFAULT_MSG));
}
TEST_IPC_Q (ipc_connection (env, &srv, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q (ipc_connection (&ctx, SERVICE_NAME), EXIT_FAILURE);
SECURE_MALLOC (write_m.payload, strlen(message_str), exit(EXIT_FAILURE));
memcpy (write_m.payload, message_str, strlen(message_str));
write_m.type = MSG_TYPE_DATA;
write_m.user_type = 42;
write_m.fd = ctx.pollfd[0].fd;
write_m.length = strlen(message_str);
gettimeofday(&tval_before, NULL);
for (size_t i = 0 ; i < nb_rounds ; i++) {
ipc_write (&srv, &write_m);
ipc_write_fd (ctx.pollfd[0].fd, &write_m);
// reading
TEST_IPC_Q(ipc_read (&srv, &read_m), EXIT_FAILURE);
TEST_IPC_Q(ipc_read (&ctx, 0 /* only valid index */, &read_m), EXIT_FAILURE);
// printf ("received message (%d bytes): %*s\n", read_m.length, read_m.length, read_m.payload);
// ipc_message_empty (&read_m);
@ -71,7 +73,7 @@ int main(int argc, char * argv[], char **env)
printf("Time elapsed: %ld.%06ld\n", (long int)tval_result.tv_sec, (long int)tval_result.tv_usec);
// disconnection
TEST_IPC_Q (ipc_close (&srv), EXIT_FAILURE);
TEST_IPC_Q (ipc_close_all (&ctx), EXIT_FAILURE);
return EXIT_SUCCESS;
}

View File

@ -5,27 +5,21 @@
#include <string.h>
#define SERVICE_NAME "example"
#define VERSION 0
#define INDEX 0
int main(int argc, char * argv[])
{
char path[PATH_MAX];
char * sname = SERVICE_NAME;
int32_t index = INDEX;
int32_t version = VERSION;
if (argc == 4) {
if (argc == 2) {
sname = argv[1];
index = atoi(argv[2]);
version = atoi(argv[3]);
}
else if (argc != 1) {
fprintf (stderr, "usage: %s [service-name index version]\n", argv[0]);
return EXIT_FAILURE;
}
service_path (path, sname, index, version);
service_path (path, sname);
// printf ("servicename: %s, index: %d, version: %d\n", sname, index, version);
printf ("%s\n", path);