From 77d7090e199a4178e53984f9060e0eec36aae76c Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sun, 7 Jun 2009 14:17:45 +0200 Subject: [PATCH] Add a callback mechanism to watch for incoming data on sockets. This callback mechanism is used to handle socket control. It could also be used when we will need to monitor sockets outside of a port context. --- src/Makefile.am | 1 + src/client.c | 4 +-- src/ctl.c | 66 ++++++++++++++++++++------------------- src/lldpd.c | 82 +++++++++++++++++++++++++++---------------------- src/lldpd.h | 27 ++++++++++------ 5 files changed, 101 insertions(+), 79 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 0d267199..82329974 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,7 @@ lldpctl_SOURCES = lldpctl.c $(COMMON) lldpd_LDADD = @LIBOBJS@ lldpctl_LDADD = @LIBOBJS@ +lldpctl_CFLAGS = -DCLIENT_ONLY if USE_SNMP lldpd_SOURCES += agent.c agent_priv.c diff --git a/src/client.c b/src/client.c index 68a24153..4b7d466c 100644 --- a/src/client.c +++ b/src/client.c @@ -32,7 +32,7 @@ static struct client_handle client_handles[] = { { 0, NULL } }; void -client_handle_client(struct lldpd *cfg, struct lldpd_client *client, +client_handle_client(struct lldpd *cfg, struct lldpd_callback *callback, char *buffer, int n) { struct hmsg *h; /* Reception */ @@ -64,7 +64,7 @@ client_handle_client(struct lldpd *cfg, struct lldpd_client *client, t->hdr.len = 0; t->hdr.type = HMSG_NONE; } - if (ctl_msg_send(client->fd, t) == -1) + if (ctl_msg_send(callback->fd, t) == -1) LLOG_WARN("unable to send answer to client %d", h->hdr.pid); free(t); diff --git a/src/ctl.c b/src/ctl.c index 6f2bce34..121faf1e 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -63,25 +63,48 @@ ctl_connect(char *name) return s; } -int -ctl_accept(struct lldpd *cfg, int c) +#ifndef CLIENT_ONLY +static void +ctl_callback(struct lldpd *cfg, struct lldpd_callback *callback) +{ + char *buffer; + int n; + + if ((buffer = (char *)malloc(MAX_HMSGSIZE)) == + NULL) { + LLOG_WARN("failed to alloc reception buffer"); + return; + } + if ((n = recv(callback->fd, buffer, + MAX_HMSGSIZE, 0)) == -1) { + LLOG_WARN("error while receiving message"); + free(buffer); + return; + } + if (n > 0) + client_handle_client(cfg, callback, buffer, n); + else { + close(callback->fd); + lldpd_callback_del(cfg, callback->fd, ctl_callback); + } + free(buffer); +} + +void +ctl_accept(struct lldpd *cfg, struct lldpd_callback *callback) { int s; - struct lldpd_client *lc; - if ((s = accept(c, NULL, NULL)) == -1) { + if ((s = accept(callback->fd, NULL, NULL)) == -1) { LLOG_WARN("unable to accept connection from socket"); - return -1; + return; } - if ((lc = (struct lldpd_client *)malloc(sizeof( - struct lldpd_client))) == NULL) { - LLOG_WARN("failed to allocate memory for new client"); + if (lldpd_callback_add(cfg, s, ctl_callback, NULL) != 0) { + LLOG_WARN("unable to add callback for new client"); close(s); - return -1; } - lc->fd = s; - TAILQ_INSERT_TAIL(&cfg->g_clients, lc, next); - return 1; + return; } +#endif void ctl_msg_init(struct hmsg *t, enum hmsg_type type) @@ -119,25 +142,6 @@ ctl_msg_recv(int fd, struct hmsg *t) return 1; } -int -ctl_close(struct lldpd *cfg, int c) -{ - struct lldpd_client *client, *client_next; - for (client = TAILQ_FIRST(&cfg->g_clients); - client != NULL; - client = client_next) { - client_next = TAILQ_NEXT(client, next); - if (client->fd == c) { - close(client->fd); - TAILQ_REMOVE(&cfg->g_clients, client, next); - free(client); - return 1; - } - } - /* Not found */ - return -1; -} - void ctl_cleanup(char *name) { diff --git a/src/lldpd.c b/src/lldpd.c index dfd19d0d..13ecdfd1 100644 --- a/src/lldpd.c +++ b/src/lldpd.c @@ -395,12 +395,42 @@ lldpd_update_chassis(struct lldpd_chassis *ochassis, memcpy(&ochassis->c_entries, &entries, sizeof(entries)); } +int +lldpd_callback_add(struct lldpd *cfg, int fd, void(*fn)(CALLBACK_SIG), void *data) +{ + struct lldpd_callback *callback; + if ((callback = (struct lldpd_callback *) + malloc(sizeof(struct lldpd_callback))) == NULL) + return -1; + callback->fd = fd; + callback->function = fn; + callback->data = data; + TAILQ_INSERT_TAIL(&cfg->g_callbacks, callback, next); + return 0; +} + +void +lldpd_callback_del(struct lldpd *cfg, int fd, void(*fn)(CALLBACK_SIG)) +{ + struct lldpd_callback *callback, *callback_next; + for (callback = TAILQ_FIRST(&cfg->g_callbacks); + callback; + callback = callback_next) { + callback_next = TAILQ_NEXT(callback, next); + if ((callback->fd == fd) && + (callback->function = fn)) { + free(callback->data); + TAILQ_REMOVE(&cfg->g_callbacks, callback, next); + free(callback); + } + } +} static void lldpd_recv_all(struct lldpd *cfg) { struct lldpd_hardware *hardware; - struct lldpd_client *client, *client_next; + struct lldpd_callback *callback, *callback_next; fd_set rfds; struct timeval tv; #ifdef USE_SNMP @@ -434,14 +464,11 @@ lldpd_recv_all(struct lldpd *cfg) nfds = n; } } - TAILQ_FOREACH(client, &cfg->g_clients, next) { - FD_SET(client->fd, &rfds); - if (nfds < client->fd) - nfds = client->fd; + TAILQ_FOREACH(callback, &cfg->g_callbacks, next) { + FD_SET(callback->fd, &rfds); + if (nfds < callback->fd) + nfds = callback->fd; } - FD_SET(cfg->g_ctl, &rfds); - if (nfds < cfg->g_ctl) - nfds = cfg->g_ctl; #ifdef USE_SNMP if (cfg->g_snmp) @@ -487,33 +514,13 @@ lldpd_recv_all(struct lldpd *cfg) free(buffer); break; } - if (FD_ISSET(cfg->g_ctl, &rfds)) { - if (ctl_accept(cfg, cfg->g_ctl) == -1) - LLOG_WARN("unable to accept new client"); - } - for (client = TAILQ_FIRST(&cfg->g_clients); - client != NULL; - client = client_next) { - client_next = TAILQ_NEXT(client, next); - if (FD_ISSET(client->fd, &rfds)) { - /* Got a message */ - if ((buffer = (char *)malloc(MAX_HMSGSIZE)) == - NULL) { - LLOG_WARN("failed to alloc reception buffer"); - continue; - } - if ((n = recv(client->fd, buffer, - MAX_HMSGSIZE, 0)) == -1) { - LLOG_WARN("error while receiving message"); - free(buffer); - continue; - } - if (n > 0) - client_handle_client(cfg, client, buffer, n); - else - ctl_close(cfg, client->fd); /* Will use TAILQ_REMOVE ! */ - free(buffer); - } + for (callback = TAILQ_FIRST(&cfg->g_callbacks); + callback; + callback = callback_next) { + /* Callback function can use TAILQ_REMOVE */ + callback_next = TAILQ_NEXT(callback, next); + if (FD_ISSET(callback->fd, &rfds)) + callback->function(cfg, callback); } #ifdef USE_SNMP @@ -870,6 +877,8 @@ main(int argc, char *argv[]) TAILQ_INSERT_TAIL(&cfg->g_chassis, lchassis, c_entries); lchassis->c_refcount++; + TAILQ_INIT(&cfg->g_callbacks); + #ifdef USE_SNMP if (snmp) { cfg->g_snmp = 1; @@ -880,7 +889,8 @@ main(int argc, char *argv[]) /* Create socket */ if ((cfg->g_ctl = priv_ctl_create(cfg)) == -1) fatalx("unable to create control socket " LLDPD_CTL_SOCKET); - TAILQ_INIT(&cfg->g_clients); + if (lldpd_callback_add(cfg, cfg->g_ctl, ctl_accept, NULL) != 0) + fatalx("unable to add callback for control socket"); gcfg = cfg; if (atexit(lldpd_exit) != 0) { diff --git a/src/lldpd.h b/src/lldpd.h index 24620e7e..402974ce 100644 --- a/src/lldpd.h +++ b/src/lldpd.h @@ -239,11 +239,6 @@ struct lldpd_interface { }; #define STRUCT_LLDPD_INTERFACE "(Ls)" -struct lldpd_client { - TAILQ_ENTRY(lldpd_client) next; - int fd; -}; - #define PROTO_SEND_SIG struct lldpd *, struct lldpd_hardware * #define PROTO_DECODE_SIG struct lldpd *, char *, int, struct lldpd_hardware *, struct lldpd_chassis **, struct lldpd_port ** #define PROTO_GUESS_SIG char *, int @@ -267,6 +262,14 @@ struct protocol { size_t filterlen; /* Size of BPF filter */ }; +#define CALLBACK_SIG struct lldpd*, struct lldpd_callback* +struct lldpd_callback { + TAILQ_ENTRY(lldpd_callback) next; + int fd; /* FD that will trigger this callback */ + void(*function)(CALLBACK_SIG); /* Function called */ + void *data; /* Optional data for this callback*/ +}; + struct lldpd { int g_sock; int g_delay; @@ -287,7 +290,8 @@ struct lldpd { /* Unix socket handling */ int g_ctl; - TAILQ_HEAD(, lldpd_client) g_clients; + + TAILQ_HEAD(, lldpd_callback) g_callbacks; char *g_mgmt_pattern; @@ -333,6 +337,8 @@ void lldpd_vlan_cleanup(struct lldpd_port *); void lldpd_remote_cleanup(struct lldpd *, struct lldpd_hardware *, int); void lldpd_port_cleanup(struct lldpd_port *, int); void lldpd_chassis_cleanup(struct lldpd_chassis *, int); +int lldpd_callback_add(struct lldpd *, int, void(*fn)(CALLBACK_SIG), void *); +void lldpd_callback_del(struct lldpd *, int, void(*fn)(CALLBACK_SIG)); /* lldp.c */ int lldp_send(PROTO_SEND_SIG); @@ -368,8 +374,9 @@ int edp_decode(PROTO_DECODE_SIG); int ctl_create(char *); int ctl_connect(char *); void ctl_cleanup(char *); -int ctl_accept(struct lldpd *, int); -int ctl_close(struct lldpd *, int); +#ifndef CLIENT_ONLY +void ctl_accept(struct lldpd *, struct lldpd_callback *); +#endif void ctl_msg_init(struct hmsg *, enum hmsg_type); int ctl_msg_send(int, struct hmsg *); int ctl_msg_recv(int, struct hmsg *); @@ -425,8 +432,8 @@ struct client_handle { void (*handle)(struct lldpd*, struct hmsg*, struct hmsg*); }; -void client_handle_client(struct lldpd *, struct lldpd_client *, - char *, int); +void client_handle_client(struct lldpd *, struct lldpd_callback *, + char *, int); void client_handle_none(struct lldpd *, struct hmsg *, struct hmsg *); void client_handle_get_interfaces(struct lldpd *, struct hmsg *, -- 2.39.5