From: Jaco Kroon Date: Fri, 7 Mar 2025 10:24:25 +0000 (+0200) Subject: pppd: Implement more generic event handler mechanism X-Git-Url: https://git.ozlabs.org/?a=commitdiff_plain;h=97ca4321f5efaf95dc6d54cd5131725381c511fe;p=ppp.git pppd: Implement more generic event handler mechanism 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 --- diff --git a/pppd/Makefile.am b/pppd/Makefile.am index 93dbeed..5e708f8 100644 --- a/pppd/Makefile.am +++ b/pppd/Makefile.am @@ -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 index 0000000..b5b442d --- /dev/null +++ b/pppd/event-handler.c @@ -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 . + */ +#include +#include +#include +#include + +#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; +} diff --git a/pppd/main.c b/pppd/main.c index 3b3fc45..65dac0e 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -497,6 +497,8 @@ main(int argc, char *argv[]) fd_devnull = i; } + event_handler_init(); + /* * Initialize system-dependent stuff. */ diff --git a/pppd/pppd-private.h b/pppd/pppd-private.h index c1fbff4..b3d5a65 100644 --- a/pppd/pppd-private.h +++ b/pppd/pppd-private.h @@ -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); diff --git a/pppd/pppd.h b/pppd/pppd.h index 4f02021..786e24f 100644 --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -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 diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index 9e0e890..3c757ee 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -95,7 +95,6 @@ #include #include #include -#include /* 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); -} - /******************************************************************** * diff --git a/pppd/sys-solaris.c b/pppd/sys-solaris.c index d724d35..4e076bf 100644 --- a/pppd/sys-solaris.c +++ b/pppd/sys-solaris.c @@ -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. */