From 75a77440e604d8665b9fd65ce424639469de08ff Mon Sep 17 00:00:00 2001 From: Philippe Pittoli Date: Wed, 8 Feb 2023 19:03:00 +0100 Subject: [PATCH] Add C examples. --- c/README.md | 6 +++ c/makefile | 18 +++++++++ c/pong.c | 99 +++++++++++++++++++++++++++++++++++++++++++++ c/pongd.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 237 insertions(+) create mode 100644 c/README.md create mode 100644 c/makefile create mode 100644 c/pong.c create mode 100644 c/pongd.c diff --git a/c/README.md b/c/README.md new file mode 100644 index 0000000..80b3f2c --- /dev/null +++ b/c/README.md @@ -0,0 +1,6 @@ +Some C examples, nothing fancy. +Implementation is straightforward. + +# Build + +`make` diff --git a/c/makefile b/c/makefile new file mode 100644 index 0000000..dc81a70 --- /dev/null +++ b/c/makefile @@ -0,0 +1,18 @@ +CC ?= cc +LDFLAGS ?= -lipc + +include makefile.valgrind + +all: build + +BINS = pong pongd +build: $(BINS) + +$(BINS): + $(CC) -o $@ $@.c $(LDFLAGS) + +clean: + rm $(BINS) 2>/dev/null + +# You can add your specific instructions there. +-include makefile.user diff --git a/c/pong.c b/c/pong.c new file mode 100644 index 0000000..578aa0a --- /dev/null +++ b/c/pong.c @@ -0,0 +1,99 @@ +#include +#include +#include + +// Do not forget to install libipc. +#include + +#define SERVICE "pong" +#define SERVICE_LEN 4 + +#define MAX_MSG_SIZE 10000 + +int err(void *ctx, char *msg) { + printf("error: %s\n", msg); + printf("Free context\n"); + ipc_context_deinit (&ctx); + return 1; +} + +int main(void) { + int ret = 0; + int servicefd = 0; + char message[MAX_MSG_SIZE]; + memset (message, 0, 1000); + size_t size = MAX_MSG_SIZE; + char event_type; + size_t index = 0; + int originfd = 0; + void *ctx = NULL; + + printf ("Init context.\n"); + ret = ipc_context_init (&ctx); + + if (ret != 0) { + printf ("Cannot init context.\n"); + return 1; + } + + printf ("Connect to a 'pong' service.\n"); + ret = ipc_connect_service (ctx, &servicefd, SERVICE, SERVICE_LEN); + + if (ret != 0) { + return err(ctx, "Cannot connect to a service."); + } + + printf ("Let's schedule a message.\n"); + ret = ipc_schedule (ctx, servicefd, "hello, plz bounce me", 21); + + if (ret != 0) { + return err(ctx, "Cannot schedule a message."); + } + + printf ("Let's set the timer to one second.\n"); + ipc_context_timer (ctx, 1000); + + printf ("Let's loop over events.\n"); + char should_continue = 1; + size_t count = 0; + while(should_continue) { + size = MAX_MSG_SIZE; + ret = ipc_wait_event (ctx, &event_type, &index, &originfd, message, &size); + if (ret != 0) { + return err(ctx, "Error while waiting for an event."); + } + + printf ("EVENT %lu\t", count++); + + switch ((enum event_types) event_type) { + case ERROR: return err(ctx, "Error."); + case EXTERNAL: return err(ctx, "External (shouldn't happen)."); + case SWITCH_RX: return err(ctx, "Switch RX (shouldn't happen)."); + case SWITCH_TX: return err(ctx, "Switch TX (shouldn't happen)."); + case CONNECTION: return err(ctx, "Connection (shouldn't happen)."); + case DISCONNECTION: return err(ctx, "Disconnection (shouldn't happen)."); + case TIMER: { printf ("TIMER.\n"); break; } + case MESSAGE_TX: { printf ("A message has been sent.\n"); break; } + case MESSAGE_RX: { + if (size == 0) { + printf ("No message returned.\n"); + printf ("Deinit context\n"); + ipc_context_deinit (&ctx); + return 1; + } + + message[size] = '\0'; + printf ("Response (size %lu): %s.\n", size, message); + // We received the response, quitting. + should_continue = 0; + break; + } + } + } + + printf ("Deinit context\n"); + ipc_context_deinit (&ctx); + + printf ("Context freed.\n"); + return 0; +} diff --git a/c/pongd.c b/c/pongd.c new file mode 100644 index 0000000..ddb64ba --- /dev/null +++ b/c/pongd.c @@ -0,0 +1,114 @@ +#include +#include + +#include + +#define SERVICE "pong" +#define SERVICE_LEN 4 + +#define MAX_MSG_SIZE 10000 + +int err(void *ctx, char *msg) { + printf("error: %s\n", msg); + printf("Free context\n"); + ipc_context_deinit (&ctx); + return 1; +} + +int main(int argc, char**argv) { + int ret = 0; + int servicefd = 0; + char message[MAX_MSG_SIZE]; + size_t size = MAX_MSG_SIZE; + char event_type; + size_t index = 0; + int originfd = 0; + void *ctx = NULL; + + int max_count = 0; + + if (argc > 1) { + max_count = atoi(argv[1]); + printf ("Wait for %d timer events.\n", max_count); + } + + printf ("Init context.\n"); + ret = ipc_context_init (&ctx); + + if (ret != 0) { + printf ("Cannot init context.\n"); + return 1; + } + + printf ("Create a 'pong' service.\n"); + ret = ipc_service_init (ctx, &servicefd, SERVICE, SERVICE_LEN); + + if (ret != 0) { + return err (ctx, "Cannot create a service."); + } + + printf ("Set the timer to two seconds.\n"); + ipc_context_timer (ctx, 2000); + + printf ("Loop over events.\n"); + char should_continue = 1; + size_t count = 0; + size_t count_timer = 0; + while(should_continue) { + size = MAX_MSG_SIZE; + ret = ipc_wait_event (ctx, &event_type, &index, &originfd, message, &size); + if (ret != 0) { + return err (ctx, "Error while waiting for an event."); + } + + if ((enum event_types) event_type != TIMER) { + printf ("EVENT %lu\t", count++); + } + + switch ((enum event_types) event_type) { + case ERROR: return err(ctx, "Error."); + case EXTERNAL: return err(ctx, "External (shouldn't happen)."); + case SWITCH_RX: return err(ctx, "Switch RX (shouldn't happen)."); + case SWITCH_TX: return err(ctx, "Switch TX (shouldn't happen)."); + case CONNECTION: { printf ("New connection.\n"); break; } + case DISCONNECTION: { printf ("User disconnected.\n"); break; } + + case TIMER: { + printf ("\rTIMER (%lu).", count_timer++); + fflush(stdout); + if (max_count && count_timer >= (size_t) max_count) { + printf ("waited for %lu timer events: quitting\n", count_timer); + should_continue = 0; + } + break; + } + + case MESSAGE_TX: { + printf ("Message sent.\n"); + break; + } + + case MESSAGE_RX: { + if (size == 0) { + return err(ctx, "Error: no message returned."); + } + else { + message[size+1] = '\0'; + printf ("Message received (size %lu): %s.\n", size, message); + printf ("Scheduling this message.\n"); + ret = ipc_schedule (ctx, originfd, message, size); + if (ret != 0) { + return err(ctx, "Cannot schedule a message."); + } + } + break; + } + } + } + + printf ("Deinit context\n"); + ipc_context_deinit (&ctx); + + printf ("Context freed.\n"); + return 0; +}