]> git.ozlabs.org Git - ccan-lca-2011.git/blob - ccan/oserver/test/run-one-client-disconnect.c
8367aad68dc4876528ede746fec5418ae9fa61b0
[ccan-lca-2011.git] / ccan / oserver / test / run-one-client-disconnect.c
1 #include <ccan/oserver/oserver.c>
2 #include <ccan/oserver/oserver.h>
3 #include <ccan/str/str.h>
4 #include <ccan/tap/tap.h>
5 #include <sys/types.h>
6 #include <sys/select.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <string.h>
10 #include <sys/wait.h>
11
12 static bool write_sall(int fd, const char *str)
13 {
14         while (str[0]) {
15                 ssize_t len = write(fd, str, strlen(str));
16                 if (len < 0)
17                         return false;
18                 str += len;
19         }
20         return true;
21 }
22
23 static bool input_is(int fd, const char *str)
24 {
25         while (str[0]) {
26                 char buffer[1000];
27                 ssize_t len = read(fd, buffer, strlen(str));
28                 if (len < 0)
29                         return false;
30                 if (strncmp(str, buffer, len) != 0)
31                         return false;
32                 str += len;
33         }
34         return true;
35 }
36
37 static void run_client(int readyfd, bool die)
38 {
39         union {
40                 struct sockaddr addr;
41                 struct sockaddr_in in;
42         } u;
43         int sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
44         char c;
45
46         u.in.sin_family = AF_INET;
47         u.in.sin_port = htons(OSERVER_PORT);
48         u.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
49         if (connect(sfd, &u.addr, sizeof(u.in)) != 0)
50                 exit(1);
51
52         if (!input_is(sfd, "Welcome.  Please ask your question.\n"))
53                 exit(1);
54
55         /* Ask a question. */
56         if (!write_sall(sfd, "Question?\n"))
57                 exit(1);
58
59         if (!input_is(sfd, "While the Oracle ponders, please answer the following question:\nQuestion?\n"))
60                 exit(1);
61
62         if (die)
63                 exit(0);
64
65         read(readyfd, &c, 1);
66         if (!write_sall(sfd, "Answer?\n"))
67                 exit(1);
68
69         /* Since other died, oracle won't say any more. */
70         read(sfd, &c, 1);
71         exit(1);
72 }       
73
74 static void set_flag(struct tevent_context *ev,
75                      struct tevent_signal *se,
76                      int signum,
77                      int count,
78                      void *siginfo,
79                      void *_flag)
80 {
81         bool *flag = _flag;
82         *flag = true;
83 }
84
85 static unsigned int count_clients(struct oserver *oserver)
86 {
87         unsigned int i, count = 0;
88
89         for (i = 0; i < ARRAY_SIZE(oserver->clients); i++) {
90                 if (oserver->clients[i])
91                         count++;
92         }
93         return count;
94 }
95
96 int main(int argc, char *argv[])
97 {
98         int ready[2];
99         struct tevent_context *ev = tevent_context_init(NULL);
100         struct oserver *oserver;
101         bool done = false;
102         int status;
103
104         /* This is how many tests you plan to run */
105         plan_tests(2);
106
107         oserver = oserver_setup(ev, OSERVER_PORT);
108         if (!oserver)
109                 err(1, "Failed to set up server");
110
111         tevent_add_signal(ev, ev, SIGCHLD, 0, set_flag, &done);
112         pipe(ready);
113
114         if (fork() == 0) {
115                 /* This child will exit, doesn't need fd. */
116                 close(ready[0]);
117                 close(ready[1]);
118                 run_client(-1, true);
119         }
120         if (fork() == 0) {
121                 close(ready[1]);
122                 run_client(ready[0], false);
123         }
124         
125         /* Wait for dead child to exit... */
126         while (!done)
127                 tevent_loop_once(ev);
128
129         /* Wait for client to be freed. */
130         while (count_clients(oserver) == 2)
131                 tevent_loop_once(ev);
132
133         /* One child should be dead... */
134         ok1(waitpid(-1, &status, 0) > 0);
135
136         /* Tell other child to write answer. */
137         write(ready[1], &status, 1);
138
139         /* Process that. */
140         tevent_loop_once(ev);
141
142         /* Other child should be hung... */
143         ok1(waitpid(-1, &status, WNOHANG) == 0);
144
145         talloc_free(ev);
146         return exit_status();
147 }