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