]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
Add a callback mechanism to watch for incoming data on sockets.
authorVincent Bernat <bernat@luffy.cx>
Sun, 7 Jun 2009 12:17:45 +0000 (14:17 +0200)
committerVincent Bernat <bernat@luffy.cx>
Sun, 7 Jun 2009 12:17:45 +0000 (14:17 +0200)
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
src/client.c
src/ctl.c
src/lldpd.c
src/lldpd.h

index 0d267199f1858199f3c778ccf94eed6728435164..82329974d5bf5f6ec4ca69f9d3c7134f34705244 100644 (file)
@@ -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
index 68a24153db9879e0ec4f98f6894f6bdf24107ce2..4b7d466c4fe65c3169846074f5b76a210ae855b2 100644 (file)
@@ -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);
index 6f2bce34faf4dddcefe0c057cb1ff8c7ba55a0ea..121faf1e9de443d53e302e9b70e235c86cf6270c 100644 (file)
--- 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)
 {
index dfd19d0de7bac15a1dda8463d07499d58f338b85..13ecdfd1937c8900432a72f001ad992d7c82e043 100644 (file)
@@ -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) {
index 24620e7ef4649c070558cbd97e5c228ee1b87677..402974ce2846e203c7d50ca3df8d352fa9cf31e2 100644 (file)
@@ -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 *,