]> git.ozlabs.org Git - ccan-lca-2011.git/blobdiff - ccan/oserver/oserver.c
lca2011: add dummy max_clients field.
[ccan-lca-2011.git] / ccan / oserver / oserver.c
index 8a5fdceecf1a0c2c4f7ddf1ac278ad8c61f7e793..362bfae849fc2ec8aef9c951fc1d3f5b9cd7ef2b 100644 (file)
@@ -5,6 +5,7 @@
 #include <ccan/opt/opt.h>
 #include <ccan/tevent/tevent.h>
 #include <ccan/array_size/array_size.h>
+#include <ccan/grab_file/grab_file.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -222,6 +223,17 @@ static int cleanup_client(struct client *client)
        return 0;
 }
 
+static unsigned int max_client(struct client *clients[5])
+{
+       unsigned int i, ret = 0;
+
+       for (i = 0; i < 5; i++) {
+               if (clients[i])
+                       ret = i+1;
+       }
+       return ret;
+}
+
 static void add_client(struct tevent_context *ev,
                       struct tevent_fd *fde, uint16_t flags, void *_oserver)
 {
@@ -253,6 +265,7 @@ static void add_client(struct tevent_context *ev,
        /* Full?  Stop listening... */
        if (client->id == ARRAY_SIZE(oserver->clients)-1)
                tevent_fd_set_flags(oserver->fde, 0);
+       oserver->max_clients = max_client(oserver->clients);
 }
 
 static void clear_clients(struct oserver *oserver)
@@ -304,10 +317,91 @@ static void dump(struct tevent_context *ev,
        write(fd, str, strlen(str));
        close(fd);
        talloc_free(str);
+       if (oserver->argv)
+               execvp(oserver->argv[0], oserver->argv);
+}
+
+static bool load_file(struct oserver *oserver, const char *file)
+{
+       char *str;
+
+       if (!file)
+               return false;
+
+       str = grab_file(oserver, file, NULL);
+       if (!str)
+               return false;
+
+       if (!cdump_unbundle(oserver, cdump_struct_oserver, oserver, str)) {
+               talloc_free(str);
+               return false;
+       }
+       talloc_free(str);
+       return true;
+}
+
+static bool complete_server(struct tevent_context *ev,
+                           struct oserver *oserver, const char *dumpfile)
+{
+       oserver->max_clients = max_client(oserver->clients);
+
+       /* Re-set this even if restored from file, in case it changed. */
+       oserver->dumpfile = dumpfile;
+       if (oserver->dumpfile)
+               tevent_add_signal(ev, oserver, SIGHUP, SA_RESTART,
+                                 dump, oserver);
+
+       /* Don't kill us if client dies. */
+       signal(SIGPIPE, SIG_IGN);
+
+       /* Show talloc tree on SIGUSR1. */
+       tevent_add_signal(ev, oserver, SIGUSR1, SA_RESTART,
+                         talloc_dump, oserver);
+
+       oserver->fde = tevent_add_fd(ev, oserver, oserver->fd,
+                                    TEVENT_FD_READ, add_client, oserver);
+       if (!oserver->fde)
+               return false;
+       return true;
+}
+
+struct oserver *oserver_restore(struct tevent_context *ev, const char *dumpfile)
+{
+       unsigned int i;
+       struct oserver *oserver = talloc(ev, struct oserver);
+       if (!load_file(oserver, dumpfile)) {
+               talloc_free(oserver);
+               return NULL;
+       }
+
+       /* Restore ignored fields in clients, and talloc hierarchy. */
+       for (i = 0; i < ARRAY_SIZE(oserver->clients); i++) {
+               struct client *client = oserver->clients[i];
+               if (!client)
+                       continue;
+               /* These two were marked CDUMP_IGNORE. */
+               client->oserver = oserver;
+               client->fde = tevent_add_fd(ev, client, client->fd,
+                                           state_flag_map[client->state],
+                                           service_client, client);
+               tevent_fd_set_auto_close(client->fde);
+               /* cdump knows nothing of talloc. */
+               talloc_steal(oserver, client);
+               talloc_steal(client, client->question);
+               talloc_steal(client, client->answer);
+               talloc_set_destructor(client, cleanup_client);
+       }
+
+       talloc_set_destructor(oserver, destroy_oserver);
+       if (!complete_server(ev, oserver, dumpfile)) {
+               talloc_free(oserver);
+               return NULL;
+       }
+       return oserver;
 }
 
 struct oserver *oserver_setup(struct tevent_context *ev, unsigned short port,
-                             const char *dumpfile)
+                             const char *dumpfile, char *argv[])
 {
        struct oserver *oserver;
        int one = 1;
@@ -317,6 +411,14 @@ struct oserver *oserver_setup(struct tevent_context *ev, unsigned short port,
        } u;
 
        oserver = talloc(ev, struct oserver);
+       oserver->argv = argv;
+       if (argv) {
+               /* Count the terminal NULL in argv_len. */
+               for (oserver->argv_len = 1;
+                    argv[oserver->argv_len - 1];
+                    oserver->argv_len++);
+       } else
+               oserver->argv_len = 0;
        clear_clients(oserver);
        oserver->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (oserver->fd < 0) {
@@ -343,25 +445,10 @@ struct oserver *oserver_setup(struct tevent_context *ev, unsigned short port,
                return NULL;
        }
 
-       oserver->fde = tevent_add_fd(ev, oserver, oserver->fd,
-                                    TEVENT_FD_READ, add_client, oserver);
-       if (!oserver->fde) {
+       if (!complete_server(ev, oserver, dumpfile)) {
                talloc_free(oserver);
                return NULL;
        }
 
-       oserver->dumpfile = dumpfile;
-       if (oserver->dumpfile) {
-               tevent_add_signal(ev, oserver, SIGHUP, SA_RESTART,
-                                 dump, oserver);
-       }
-
-       /* Don't kill us if client dies. */
-       signal(SIGPIPE, SIG_IGN);
-
-       /* Show talloc tree on SIGUSR1. */
-       tevent_add_signal(ev, oserver, SIGUSR1, SA_RESTART,
-                         talloc_dump, oserver);
-
        return oserver;
 }