]> git.ozlabs.org Git - ppp.git/commitdiff
pppd: Implement more generic event handler mechanism
authorJaco Kroon <jaco@uls.co.za>
Fri, 7 Mar 2025 10:24:25 +0000 (12:24 +0200)
committerJaco Kroon <jaco@uls.co.za>
Fri, 2 May 2025 10:01:23 +0000 (12:01 +0200)
This allows non-core modules to add file descriptors to the
event loop and have a call-back called when those file descriptors
won't block on read().

Signed-off-by: Jaco Kroon <jaco@uls.co.za>
pppd/Makefile.am
pppd/event-handler.c [new file with mode: 0644]
pppd/main.c
pppd/pppd-private.h
pppd/pppd.h
pppd/sys-linux.c
pppd/sys-solaris.c

index 93dbeedb3c282a8e3e4b9a59ee0019da7fa5bf51..5e708f89959a23101d088c24b4dd1f6986a59479 100644 (file)
@@ -82,6 +82,7 @@ pppd_SOURCES = \
     lcp.c \
     magic.c \
     main.c \
+    event-handler.c \
     options.c \
     session.c \
     tty.c \
diff --git a/pppd/event-handler.c b/pppd/event-handler.c
new file mode 100644 (file)
index 0000000..b5b442d
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * event-handler.c - generic select() based event handler.  Should be system
+ * independent.
+ *
+ * Copyright (c) 1994-2025 Paul Mackerras. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Derived from sys-linux.c and sys-solaris.c by Jaco Kroon <jaco@uls.co.za>.
+ */
+#include <limits.h>
+#include <stddef.h>
+#include <errno.h>
+#include <sys/select.h>
+
+#include "pppd.h"
+#include "pppd-private.h"
+
+struct event_handler {
+    struct event_handler* next;
+    int fd;
+    event_cb cb;
+    void* ctx;
+};
+
+static fd_set in_fds;          /* set of fds that wait_input waits for */
+static int max_in_fd;          /* highest fd set in in_fds */
+static struct event_handler* handlers;
+static int called_remove;
+
+/********************************************************************
+ *
+ * wait_input - wait until there is data available,
+ * for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+
+void wait_input(struct timeval *timo)
+{
+    fd_set ready, exc;
+    int n;
+    struct event_handler* h = handlers, *nh;
+
+    called_remove = 0;
+    ready = in_fds;
+    exc = in_fds;
+    n = select(max_in_fd + 1, &ready, NULL, &exc, timo);
+    if (n < 0 && errno != EINTR)
+       fatal("select: %m");
+
+    while (h) {
+       nh = h->next;
+       if (FD_ISSET(h->fd, &ready)) {
+           FD_CLR(h->fd, &ready); /* clear so that if we need to re-iterate we won't call again */
+           h->cb(h->fd, h->ctx);
+
+           if (called_remove) {
+               nh = handlers;
+               called_remove = 0;
+           }
+       }
+       h = nh;
+    }
+}
+
+/*
+ * add_fd - add an fd to the set that wait_input waits for.
+ */
+void add_fd(int fd)
+{
+    if (fd >= FD_SETSIZE)
+       fatal("internal error: file descriptor too large (%d)", fd);
+    FD_SET(fd, &in_fds);
+    if (fd > max_in_fd)
+       max_in_fd = fd;
+}
+
+void add_fd_callback(int fd, event_cb cb, void* ctx)
+{
+    struct event_handler *n = malloc(sizeof(*n));
+    n->next = handlers;
+    n->fd = fd;
+    n->cb = cb;
+    n->ctx = ctx;
+    handlers = n;
+    add_fd(fd);
+}
+
+/*
+ * remove_fd - remove an fd from the set that wait_input waits for.
+ */
+void remove_fd(int fd)
+{
+    struct event_handler** h, *t;
+    FD_CLR(fd, &in_fds);
+
+    for (h = &handlers; *h; h = &(*h)->next) {
+       if (fd == (*h)->fd) {
+           called_remove = 1;
+           t = (*h)->next;
+           free(*h);
+           *h = t;
+           return;
+       }
+    }
+}
+
+void event_handler_init()
+{
+    FD_ZERO(&in_fds);
+    max_in_fd = 0;
+}
index 3b3fc4542f3fa4c46645f85f8f26752abab65d39..65dac0e2d92f6ee329662cfaa49b2ad99773d481 100644 (file)
@@ -497,6 +497,8 @@ main(int argc, char *argv[])
        fd_devnull = i;
     }
 
+    event_handler_init();
+
     /*
      * Initialize system-dependent stuff.
      */
index c1fbff4e48bde9d3096261aa122a62dcf42e287a..b3d5a652451edcfcb1fe6046f79ded26a5eaceee 100644 (file)
@@ -374,6 +374,12 @@ void demand_rexmit(int);   /* retransmit saved frames for an NP */
 int  loop_chars(unsigned char *, int); /* process chars from loopback */
 int  loop_frame(unsigned char *, int); /* should we bring link up? */
 
+/* internal-only event handler procedures */
+void event_handler_init(void); /* initialize the event handler */
+void wait_input(struct timeval *);
+                               /* Wait for input, with timeout */
+void add_fd(int);              /* Add fd to set to wait for */
+
 /* Procedures exported from sys-*.c */
 void sys_init(void);   /* Do system-dependent initialization */
 void sys_cleanup(void);        /* Restore system state before exiting */
@@ -391,10 +397,6 @@ void set_up_tty(int, int); /* Set up port's speed, parameters, etc. */
 void restore_tty(int); /* Restore port's original parameters */
 void setdtr(int, int); /* Raise or lower port's DTR line */
 void output(int, unsigned char *, int); /* Output a PPP packet */
-void wait_input(struct timeval *);
-                               /* Wait for input, with timeout */
-void add_fd(int);              /* Add fd to set to wait for */
-void remove_fd(int);   /* Remove fd from set to wait for */
 int  read_packet(unsigned char *); /* Read PPP packet */
 int  get_loop_output(void); /* Read pkts from loopback */
 void tty_send_config(int, u_int32_t, int, int);
index 4f020215c7f8d510a0a123c4bdfe9bf3a406075a..786e24f3647dab5c3ed79404bab46f8cec824abb 100644 (file)
@@ -564,6 +564,11 @@ extern int  (*allowed_address_hook)(uint32_t addr);
 extern void (*snoop_recv_hook)(unsigned char *p, int len);
 extern void (*snoop_send_hook)(unsigned char *p, int len);
 
+/* mechanism to setup event handlers */
+typedef void (*event_cb)(int fd, void* ctx); /* callback signature */
+void add_fd_callback(int, event_cb, void*); /* add fd with callback */
+void remove_fd(int);   /* Remove fd from set to wait for */
+
 #ifdef __cplusplus
 }
 #endif
index 9e0e89065adc0027ea2c93c9acc65781aea39e5d..3c757ee7d2ff61f92081121c3d1d92c50bf5d997 100644 (file)
@@ -95,7 +95,6 @@
 #include <fcntl.h>
 #include <ctype.h>
 #include <unistd.h>
-#include <limits.h>
 
 /* This is in netdevice.h. However, this compile will fail miserably if
    you attempt to include netdevice.h because it has so many references
@@ -216,9 +215,6 @@ int ppp_dev_fd = -1;                /* fd for /dev/ppp (new style driver) */
 
 static int chindex;            /* channel index (new style driver) */
 
-static fd_set in_fds;          /* set of fds that wait_input waits for */
-static int max_in_fd;          /* highest fd set in in_fds */
-
 static int has_proxy_arp       = 0;
 static int driver_version      = 0;
 static int driver_modification = 0;
@@ -491,9 +487,6 @@ void sys_init(void)
     if (sock6_fd < 0)
        sock6_fd = -errno;      /* save errno for later */
 #endif
-
-    FD_ZERO(&in_fds);
-    max_in_fd = 0;
 }
 
 /********************************************************************
@@ -1417,45 +1410,6 @@ void output (int unit, unsigned char *p, int len)
     }
 }
 
-/********************************************************************
- *
- * wait_input - wait until there is data available,
- * for the length of time specified by *timo (indefinite
- * if timo is NULL).
- */
-
-void wait_input(struct timeval *timo)
-{
-    fd_set ready, exc;
-    int n;
-
-    ready = in_fds;
-    exc = in_fds;
-    n = select(max_in_fd + 1, &ready, NULL, &exc, timo);
-    if (n < 0 && errno != EINTR)
-       fatal("select: %m");
-}
-
-/*
- * add_fd - add an fd to the set that wait_input waits for.
- */
-void add_fd(int fd)
-{
-    if (fd >= FD_SETSIZE)
-       fatal("internal error: file descriptor too large (%d)", fd);
-    FD_SET(fd, &in_fds);
-    if (fd > max_in_fd)
-       max_in_fd = fd;
-}
-
-/*
- * remove_fd - remove an fd from the set that wait_input waits for.
- */
-void remove_fd(int fd)
-{
-    FD_CLR(fd, &in_fds);
-}
-
 
 /********************************************************************
  *
index d724d35dbf780649125f42ed2c38aa9118c81cee..4e076bf0813ff6553ac0b41388e498910950018e 100644 (file)
@@ -203,10 +203,6 @@ static pid_t       tty_sid;        /* original session ID for terminal */
 
 extern u_char  inpacket_buf[]; /* borrowed from main.c */
 
-#define MAX_POLLFDS    32
-static struct pollfd pollfds[MAX_POLLFDS];
-static int n_pollfds;
-
 static int     link_mtu, link_mru;
 
 #define NMODULES       32
@@ -548,8 +544,6 @@ sys_init(void)
        ioctl(ip6fd, I_PUNLINK, ip6muxid);
        fatal("Can't link PPP device to IP (2): %m");
     }
-
-    n_pollfds = 0;
 }
 
 /*
@@ -1066,56 +1060,6 @@ output(int unit, u_char *p, int len)
 }
 
 
-/*
- * wait_input - wait until there is data available,
- * for the length of time specified by *timo (indefinite
- * if timo is NULL).
- */
-void
-wait_input(struct timeval *timo)
-{
-    int t;
-
-    t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
-    if (poll(pollfds, n_pollfds, t) < 0 && errno != EINTR)
-       fatal("poll: %m");
-}
-
-/*
- * add_fd - add an fd to the set that wait_input waits for.
- */
-void add_fd(int fd)
-{
-    int n;
-
-    for (n = 0; n < n_pollfds; ++n)
-       if (pollfds[n].fd == fd)
-           return;
-    if (n_pollfds < MAX_POLLFDS) {
-       pollfds[n_pollfds].fd = fd;
-       pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
-       ++n_pollfds;
-    } else
-       error("Too many inputs!");
-}
-
-/*
- * remove_fd - remove an fd from the set that wait_input waits for.
- */
-void remove_fd(int fd)
-{
-    int n;
-
-    for (n = 0; n < n_pollfds; ++n) {
-       if (pollfds[n].fd == fd) {
-           while (++n < n_pollfds)
-               pollfds[n-1] = pollfds[n];
-           --n_pollfds;
-           break;
-       }
-    }
-}
-
 /*
  * read_packet - get a PPP packet from the serial device.
  */