]> git.ozlabs.org Git - ccan-lca-2011.git/commitdiff
lca2011: test client disconnect.
authorRusty Russell <rusty@rustcorp.com.au>
Fri, 21 Jan 2011 03:47:57 +0000 (14:17 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Fri, 21 Jan 2011 03:47:57 +0000 (14:17 +1030)
ccan/oserver/test/run-one-client-disconnect.c [new file with mode: 0644]

diff --git a/ccan/oserver/test/run-one-client-disconnect.c b/ccan/oserver/test/run-one-client-disconnect.c
new file mode 100644 (file)
index 0000000..8367aad
--- /dev/null
@@ -0,0 +1,147 @@
+#include <ccan/oserver/oserver.c>
+#include <ccan/oserver/oserver.h>
+#include <ccan/str/str.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/wait.h>
+
+static bool write_sall(int fd, const char *str)
+{
+       while (str[0]) {
+               ssize_t len = write(fd, str, strlen(str));
+               if (len < 0)
+                       return false;
+               str += len;
+       }
+       return true;
+}
+
+static bool input_is(int fd, const char *str)
+{
+       while (str[0]) {
+               char buffer[1000];
+               ssize_t len = read(fd, buffer, strlen(str));
+               if (len < 0)
+                       return false;
+               if (strncmp(str, buffer, len) != 0)
+                       return false;
+               str += len;
+       }
+       return true;
+}
+
+static void run_client(int readyfd, bool die)
+{
+       union {
+               struct sockaddr addr;
+               struct sockaddr_in in;
+       } u;
+       int sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+       char c;
+
+       u.in.sin_family = AF_INET;
+       u.in.sin_port = htons(OSERVER_PORT);
+       u.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       if (connect(sfd, &u.addr, sizeof(u.in)) != 0)
+               exit(1);
+
+       if (!input_is(sfd, "Welcome.  Please ask your question.\n"))
+               exit(1);
+
+       /* Ask a question. */
+       if (!write_sall(sfd, "Question?\n"))
+               exit(1);
+
+       if (!input_is(sfd, "While the Oracle ponders, please answer the following question:\nQuestion?\n"))
+               exit(1);
+
+       if (die)
+               exit(0);
+
+       read(readyfd, &c, 1);
+       if (!write_sall(sfd, "Answer?\n"))
+               exit(1);
+
+       /* Since other died, oracle won't say any more. */
+       read(sfd, &c, 1);
+       exit(1);
+}      
+
+static void set_flag(struct tevent_context *ev,
+                    struct tevent_signal *se,
+                    int signum,
+                    int count,
+                    void *siginfo,
+                    void *_flag)
+{
+       bool *flag = _flag;
+       *flag = true;
+}
+
+static unsigned int count_clients(struct oserver *oserver)
+{
+       unsigned int i, count = 0;
+
+       for (i = 0; i < ARRAY_SIZE(oserver->clients); i++) {
+               if (oserver->clients[i])
+                       count++;
+       }
+       return count;
+}
+
+int main(int argc, char *argv[])
+{
+       int ready[2];
+       struct tevent_context *ev = tevent_context_init(NULL);
+       struct oserver *oserver;
+       bool done = false;
+       int status;
+
+       /* This is how many tests you plan to run */
+       plan_tests(2);
+
+       oserver = oserver_setup(ev, OSERVER_PORT);
+       if (!oserver)
+               err(1, "Failed to set up server");
+
+       tevent_add_signal(ev, ev, SIGCHLD, 0, set_flag, &done);
+       pipe(ready);
+
+       if (fork() == 0) {
+               /* This child will exit, doesn't need fd. */
+               close(ready[0]);
+               close(ready[1]);
+               run_client(-1, true);
+       }
+       if (fork() == 0) {
+               close(ready[1]);
+               run_client(ready[0], false);
+       }
+       
+       /* Wait for dead child to exit... */
+       while (!done)
+               tevent_loop_once(ev);
+
+       /* Wait for client to be freed. */
+       while (count_clients(oserver) == 2)
+               tevent_loop_once(ev);
+
+       /* One child should be dead... */
+       ok1(waitpid(-1, &status, 0) > 0);
+
+       /* Tell other child to write answer. */
+       write(ready[1], &status, 1);
+
+       /* Process that. */
+       tevent_loop_once(ev);
+
+       /* Other child should be hung... */
+       ok1(waitpid(-1, &status, WNOHANG) == 0);
+
+       talloc_free(ev);
+       return exit_status();
+}