]> git.ozlabs.org Git - ccan-lca-2011.git/commitdiff
lca2011: fix client disconnect during answer (poorly).
authorRusty Russell <rusty@rustcorp.com.au>
Tue, 25 Jan 2011 00:29:15 +0000 (10:59 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 25 Jan 2011 00:29:15 +0000 (10:59 +1030)
We seek an oracle or a client when we need one, and unset when we
are destroyed.  This can cause crossed answers; better would be to
actually move the questions/answers around.

ccan/oserver/oserver.c

index 2d4cac41b28754fbef15a07f952edf5eb5109b0d..c293dd5178ed40651ab3b3b1d6269c2577af1e5e 100644 (file)
 enum state {
        SENDING_GREETING,
        RECEIVING_USER_QUESTION,
-       AWAITING_A_SUBCLIENT,
        SENDING_OTHER_QUESTION_PREFIX,
        SENDING_OTHER_QUESTION,
        RECEIVING_OTHER_ANSWER,
-       AWAITING_OUR_ORACLE,
        SENDING_ANSWER_PREFIX,
        SENDING_ANSWER,
        FINISHED
@@ -33,11 +31,9 @@ enum state {
 static uint16_t state_flag_map[] = {
        [SENDING_GREETING]              = TEVENT_FD_WRITE,
        [RECEIVING_USER_QUESTION]       = TEVENT_FD_READ,
-       [AWAITING_A_SUBCLIENT]          = 0,
        [SENDING_OTHER_QUESTION_PREFIX] = TEVENT_FD_WRITE,
        [SENDING_OTHER_QUESTION]        = TEVENT_FD_WRITE,
        [RECEIVING_OTHER_ANSWER]        = TEVENT_FD_READ,
-       [AWAITING_OUR_ORACLE]           = 0,
        [SENDING_ANSWER_PREFIX]         = TEVENT_FD_WRITE,
        [SENDING_ANSWER]                = TEVENT_FD_WRITE,
        [FINISHED]                      = 0
@@ -153,6 +149,11 @@ static bool get_oracle(struct client *me)
        return false;
 }
 
+static void wakeup(struct client *c)
+{
+       tevent_fd_set_flags(c->fde, state_flag_map[c->state]);
+}
+
 static void service_client(struct tevent_context *ev,
                           struct tevent_fd *fde, uint16_t flags, void *_c)
 {
@@ -168,50 +169,36 @@ static void service_client(struct tevent_context *ev,
                len = read_string(c->fd, &c->question);
                if (len <= 0)
                        goto fail;
-               if (input_finished(c->question)) {
-                       /* Look for someone to be oracle to. */
-                       if (get_subclient(c)) {
-                               set_state(c, SENDING_OTHER_QUESTION_PREFIX);
-                       } else {
-                               /* We sit here until someone find_oracles us */
-                               set_state(c, AWAITING_A_SUBCLIENT);
-                       }
-
-                       /* Look for an oracle for ourselves. */
-                       if (get_oracle(c)) {
-                               assert(c->oracle->state
-                                      == AWAITING_A_SUBCLIENT);
-                               set_state(c->oracle,
-                                         SENDING_OTHER_QUESTION_PREFIX);
-                       }
-               }
+               if (input_finished(c->question))
+                       set_state(c, SENDING_OTHER_QUESTION_PREFIX);
                break;
        case SENDING_OTHER_QUESTION_PREFIX:
+               if (!c->subclient)
+                       goto need_subclient;
                if (!send_string(c, "While the Oracle ponders,"
                                 " please answer the following question:\n"))
                        goto fail;
                break;
        case SENDING_OTHER_QUESTION:
+               if (!c->subclient)
+                       goto need_subclient;
                if (!send_string(c, c->subclient->question))
                        goto fail;
                break;
        case RECEIVING_OTHER_ANSWER:
+               if (!c->subclient)
+                       goto need_subclient;
                len = read_string(c->fd, &c->subclient->answer);
                if (len <= 0)
                        goto fail;
                if (input_finished(c->subclient->answer)) {
-                       /* Did our oracle answer for us already? */
-                       if (input_finished(c->answer))
-                               set_state(c, SENDING_ANSWER_PREFIX);
-                       else
-                               set_state(c, AWAITING_OUR_ORACLE);
-
-                       /* If they were waiting for an answer, move them. */
-                       if (c->subclient->state == AWAITING_OUR_ORACLE)
-                               set_state(c->subclient, SENDING_ANSWER_PREFIX);
+                       set_state(c, SENDING_ANSWER_PREFIX);
+                       wakeup(c->subclient);
                }
                break;
        case SENDING_ANSWER_PREFIX:
+               if (!input_finished(c->answer))
+                       goto need_answer;
                if (!send_string(c, "The Oracle spake thus:\n"))
                        goto fail;
                break;
@@ -225,15 +212,43 @@ static void service_client(struct tevent_context *ev,
 
        if (c->state != FINISHED)
                return;
-
 fail:
        talloc_free(c);
+       return;
+
+need_subclient:
+       if (!get_subclient(c)) {
+               /* We can't get one: go to sleep until someone find_oracle() */
+               tevent_fd_set_flags(c->fde, 0);
+       } else
+               /* In case they are waiting... */
+               wakeup(c->subclient);
+       return;
+
+need_answer:
+       /* If we don't have an oracle and find one, that's OK. */
+       if (!c->oracle && get_oracle(c)) {
+               /* In case they are waiting... */
+               wakeup(c->oracle);
+               return;
+       }
+
+       /* Either our oracle is not finished, or we don't have one: sleep. */
+       tevent_fd_set_flags(c->fde, 0);
 }
 
 static int cleanup_client(struct client *client)
 {
        unsigned int i;
 
+       /* We were an oracle? */
+       if (client->subclient)
+               client->subclient->oracle = NULL;
+
+       /* We had an oracle? */
+       if (client->oracle)
+               client->oracle->subclient = NULL;
+
        for (i = 0; i < ARRAY_SIZE(client->oserver->clients); i++) {
                if (client->oserver->clients[i] == client) {
                        client->oserver->clients[i] = NULL;