From: Rusty Russell Date: Fri, 21 Jan 2011 03:47:57 +0000 (+1030) Subject: lca2011: test client disconnect. X-Git-Url: http://git.ozlabs.org/?p=ccan-lca-2011.git;a=commitdiff_plain;h=16c87acea61438be835b38ea417c95e1d6a256c8 lca2011: test client disconnect. --- diff --git a/ccan/oserver/test/run-one-client-disconnect.c b/ccan/oserver/test/run-one-client-disconnect.c new file mode 100644 index 0000000..8367aad --- /dev/null +++ b/ccan/oserver/test/run-one-client-disconnect.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(); +}