summaryrefslogtreecommitdiffstats
path: root/ctrl/facemgr/examples/updownsrv
diff options
context:
space:
mode:
authorJordan Augé <jordan.auge+fdio@cisco.com>2019-10-07 09:52:33 +0200
committerJordan Augé <jordan.auge+fdio@cisco.com>2019-10-07 15:55:42 +0200
commit6b84ec54083da9911f5ad4816d0eb4f4745afad4 (patch)
treee4296ebb218fff02dc0bbea73ce1c8d12aba7bcc /ctrl/facemgr/examples/updownsrv
parent85a791ac2cdd35d79c00141e748b4c68fbdafb0d (diff)
[HICN-298] Release new hICN app for Android
Change-Id: I43adc62fadf00690b687078d739788dffdc5e566 Signed-off-by: Jordan Augé <jordan.auge+fdio@cisco.com>
Diffstat (limited to 'ctrl/facemgr/examples/updownsrv')
-rw-r--r--ctrl/facemgr/examples/updownsrv/Makefile25
-rw-r--r--ctrl/facemgr/examples/updownsrv/updownsrv.c231
2 files changed, 256 insertions, 0 deletions
diff --git a/ctrl/facemgr/examples/updownsrv/Makefile b/ctrl/facemgr/examples/updownsrv/Makefile
new file mode 100644
index 000000000..5e6111c2a
--- /dev/null
+++ b/ctrl/facemgr/examples/updownsrv/Makefile
@@ -0,0 +1,25 @@
+EXEC = $(shell basename $$(pwd))
+CC = gcc
+
+CFLAGS = -std=gnu11 -O3 -Wall -Wextra -Wpedantic -Wstrict-aliasing
+#CFLAGS += $(shell pkg-config --cflags glib-2.0 gio-2.0)
+#LDFLAGS = $(shell pkg-config --libs glib-2.0 gio-2.0)
+
+SRC = $(wildcard *.c)
+OBJ = $(SRC:.c=.o)
+
+all: $(EXEC)
+
+${EXEC}: $(OBJ)
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+%.o: %.c
+ $(CC) -o $@ -c $< $(CFLAGS)
+
+.PHONY: clean mrproper
+
+clean:
+ @rm -rf *.o
+
+mrproper: clean
+ @rm -rf $(EXEC)
diff --git a/ctrl/facemgr/examples/updownsrv/updownsrv.c b/ctrl/facemgr/examples/updownsrv/updownsrv.c
new file mode 100644
index 000000000..e10247860
--- /dev/null
+++ b/ctrl/facemgr/examples/updownsrv/updownsrv.c
@@ -0,0 +1,231 @@
+/*
+ * Dummy server sending alternating bytes to all clients.
+ *
+ * This is used by the face manager to illustrate the creation of interfaces
+ * using unix domains that sets a face up and down.
+ */
+
+#include <arpa/inet.h> // inet_ntop
+#include <errno.h> // EINTR,. ..
+#include <netinet/in.h> // INET_ADDRSTRLEN, INET6_ADDRSTRLEN
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/timerfd.h>
+#include <sys/un.h> // sockaddr_un
+#include <unistd.h> // fcntl
+#include <fcntl.h> // fcntl
+
+
+/**
+ * \brief Default unix socket path (the leading \0 means using the abstract
+ * namespace instead of the filesystem).
+ */
+#define UNIX_PATH "\0updownsrv"
+
+/**
+ * \brief Default interval (in seconds) between timer events */
+#define DEFAULT_INTERVAL 100000
+
+/**
+ * \brief Maximum allowed number of connected clients
+ */
+#define MAX_CLIENTS 5
+
+/**
+ * \brief Maximum backlog of listening unix socket
+ */
+#define LISTEN_BACKLOG MAX_CLIENTS
+
+
+/**
+ * \brief Creates a unix server socket
+ * \param [in] path - string representing the path on which to listen for
+ * connections
+ * \return int - fd associated to the socket
+ */
+int
+create_unix_server(char * path)
+{
+ struct sockaddr_un addr;
+ int fd;
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
+ perror("socket error");
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ perror("fcntl");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ if (*path == '\0') {
+ *addr.sun_path = '\0';
+ strncpy(addr.sun_path+1, path+1, sizeof(addr.sun_path)-2);
+ } else {
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
+ unlink(path);
+ }
+
+ if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+ perror("bind error");
+ return -1;
+ }
+
+ if (listen(fd, LISTEN_BACKLOG) == -1) {
+ perror("listen error");
+ return -1;
+ }
+
+ return fd;
+}
+
+
+/**
+ * \brief Main function
+ */
+int main() {
+ int fd, tfd;
+ int rc;
+
+ /* Alternating state of the server : 0 / 1 */
+ unsigned state = 0;
+
+ /*
+ * This server has to send a signal to all connected clients at periodic
+ * intervals. Since we don't expect a large number of connected clients for
+ * such a simple program, we simply use a statically allocated array.
+ */
+ int clients[MAX_CLIENTS];
+ size_t num_clients = 0;
+
+ fd_set active_fd_set, read_fd_set;
+ FD_ZERO (&active_fd_set);
+
+ /* Create listening unix socket */
+ fd = create_unix_server(UNIX_PATH);
+ if (fd < 0)
+ exit(EXIT_FAILURE);
+ FD_SET (fd, &active_fd_set);
+
+ /* Create timer */
+ tfd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (tfd == -1) {
+ perror("timer error");
+ exit(EXIT_FAILURE);
+ }
+
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ perror("fcntl");
+ exit(EXIT_FAILURE);
+ }
+
+ FD_SET (tfd, &active_fd_set);
+
+ struct itimerspec ts = {
+ .it_interval = {
+ .tv_sec = DEFAULT_INTERVAL,
+ .tv_nsec = 0,
+ },
+ .it_value = {
+ .tv_sec = DEFAULT_INTERVAL,
+ .tv_nsec = 0,
+ }
+ };
+ rc = timerfd_settime(tfd, 0, &ts, NULL);
+ if (rc == -1) {
+ perror("timerfd_settime");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Waiting for clients...\n");
+
+ for(;;) {
+ /* Block until input arrives on one or more active sockets. */
+ read_fd_set = active_fd_set;
+ rc = select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL);
+ if (rc < 0) {
+ if (rc == EINTR)
+ break;
+ perror("select");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Service all the sockets with input pending. */
+ for (int i = 0; i < FD_SETSIZE; ++i) {
+ if (!FD_ISSET (i, &read_fd_set))
+ continue;
+ if (i == fd) {
+ /* Connection request on original socket. */
+ int client_fd = accept(fd, NULL, NULL);
+ if (client_fd < 0) {
+ perror("accept");
+ continue;
+ }
+
+ fprintf(stderr, "Server: connect from new client\n");
+ clients[num_clients++] = client_fd;
+ FD_SET(client_fd, &active_fd_set);
+ } else if (i == tfd) {
+ /* Timer event */
+ uint64_t res;
+
+ read(tfd, &res, sizeof(res));
+// while (read(fd, &missed, sizeof(missed)) > 0)
+// ;
+ for (unsigned j = 0; j < num_clients; j++) {
+ write(clients[j], state ? "\1" : "\0", 1);
+ }
+ printf("STATE=%d\n", state);
+ state = 1 - state;
+ } else {
+ char buf[1024];
+ rc = read(i, buf, sizeof(buf));
+ /* Client event : we close the connection on any event... */
+ for (unsigned j = 0; j < num_clients; j++) {
+ if (i == clients[j]) {
+ clients[j] = clients[num_clients--];
+ break;
+ }
+ }
+ close(i);
+ FD_CLR(i, &active_fd_set);
+ }
+ }
+
+ }
+
+ int ret = EXIT_SUCCESS;
+
+ /* Close all active client connections */
+ for (unsigned i = 0; i < num_clients; i++) {
+ rc = close(clients[i]);
+ if (rc == -1) {
+ perror("close");
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ /* Close server */
+ rc = close(fd);
+ if (rc == -1) {
+ perror("close");
+ ret = EXIT_FAILURE;
+ }
+
+ /* Terminate timer */
+ ts.it_value.tv_sec = 0;
+ rc = timerfd_settime(tfd, 0, &ts, NULL);
+ if (rc == -1) {
+ perror("timerfd_settime");
+ exit(EXIT_FAILURE);
+ }
+
+ exit(ret);
+}