X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Foserver%2Foserver.c;h=2d4cac41b28754fbef15a07f952edf5eb5109b0d;hb=a1ee151190dc9ac9bf17163ab4d31f0491b8bbee;hp=076ba70b4c15930eeb7cfde0ffb6e2eed1a38a57;hpb=e78c302eef5bf006cd0994c03a98b1e1c078b67b;p=ccan-lca-2011.git diff --git a/ccan/oserver/oserver.c b/ccan/oserver/oserver.c index 076ba70..2d4cac4 100644 --- a/ccan/oserver/oserver.c +++ b/ccan/oserver/oserver.c @@ -15,15 +15,30 @@ #include #include #include +#include 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 }; 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 }; @@ -36,10 +51,16 @@ struct client { int fd; /* The question we read from client. */ char *question; + /* The answer to the client. */ + char *answer; /* How many bytes of the reply we sent so far. */ size_t bytes_sent; /* Our server. */ struct oserver *oserver; + /* Whose question this client is answering. */ + struct client *subclient; + /* Who is answering our question. */ + struct client *oracle; }; struct oserver { @@ -98,6 +119,40 @@ static bool send_string(struct client *c, const char *str) return true; } +static bool get_subclient(struct client *me) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(me->oserver->clients); i++) { + struct client *c = me->oserver->clients[i]; + if (!c || c == me) + continue; + if (c->oracle == NULL && input_finished(c->question)) { + me->subclient = c; + c->oracle = me; + return true; + } + } + return false; +} + +static bool get_oracle(struct client *me) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(me->oserver->clients); i++) { + struct client *c = me->oserver->clients[i]; + if (!c || c == me) + continue; + if (c->subclient == NULL && input_finished(c->question)) { + me->oracle = c; + c->subclient = me; + return true; + } + } + return false; +} + static void service_client(struct tevent_context *ev, struct tevent_fd *fde, uint16_t flags, void *_c) { @@ -105,20 +160,63 @@ static void service_client(struct tevent_context *ev, ssize_t len; switch (c->state) { + case SENDING_GREETING: + if (!send_string(c, "Welcome. Please ask your question.\n")) + goto fail; + break; case RECEIVING_USER_QUESTION: len = read_string(c->fd, &c->question); if (len <= 0) goto fail; if (input_finished(c->question)) { - unsigned int i; - - for (i = 0; c->question[i]; i++) - c->question[i] = toupper(c->question[i]); - set_state(c, SENDING_ANSWER); + /* 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); + } + } + break; + case SENDING_OTHER_QUESTION_PREFIX: + if (!send_string(c, "While the Oracle ponders," + " please answer the following question:\n")) + goto fail; + break; + case SENDING_OTHER_QUESTION: + if (!send_string(c, c->subclient->question)) + goto fail; + break; + case RECEIVING_OTHER_ANSWER: + 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); } break; + case SENDING_ANSWER_PREFIX: + if (!send_string(c, "The Oracle spake thus:\n")) + goto fail; + break; case SENDING_ANSWER: - if (!send_string(c, c->question)) + if (!send_string(c, c->answer)) goto fail; break; default: @@ -159,10 +257,13 @@ static void add_client(struct tevent_context *ev, if (client->fd < 0) err(1, "Accepting client connection"); - client->state = RECEIVING_USER_QUESTION; + client->state = SENDING_GREETING; client->bytes_sent = 0; client->question = talloc_strdup(client, ""); client->oserver = oserver; + client->oracle = NULL; + client->subclient = NULL; + client->answer = talloc_strdup(client, ""); client->fde = tevent_add_fd(ev, client, client->fd, state_flag_map[client->state], service_client, client); @@ -206,7 +307,7 @@ struct oserver *oserver_setup(struct tevent_context *ev, unsigned short port) talloc_free(oserver); return NULL; } - + talloc_set_destructor(oserver, destroy_oserver); if (setsockopt(oserver->fd, SOL_SOCKET, SO_REUSEADDR,