diff options
author | Nalin Dahyabhai <nalin.dahyabhai@pobox.com> | 2008-05-30 14:59:11 -0400 |
---|---|---|
committer | Nalin Dahyabhai <nalin.dahyabhai@pobox.com> | 2008-05-30 14:59:11 -0400 |
commit | 3d207eb9f9f4b3bdc7e4775622fe75d318d054ae (patch) | |
tree | b1a93be89a1a54915c81bc3c2194c6c04a99c67e /src/nis.c | |
parent | 32dd26f4052b57bf1cdc7fad2cc47874ff989cc1 (diff) | |
download | slapi-nis-3d207eb9f9f4b3bdc7e4775622fe75d318d054ae.tar.gz slapi-nis-3d207eb9f9f4b3bdc7e4775622fe75d318d054ae.tar.xz slapi-nis-3d207eb9f9f4b3bdc7e4775622fe75d318d054ae.zip |
- move nis_all processing to a works-in-chunks state machine
Diffstat (limited to 'src/nis.c')
-rw-r--r-- | src/nis.c | 394 |
1 files changed, 327 insertions, 67 deletions
@@ -353,6 +353,55 @@ nis_maplist(struct plugin_state *state, } } +/* Enumeration, if we want to break it down into chunks, happens in a few + * phases (given the protocol): + * 1. we're sending the first entry in a map + * 2. we're sending a not-the-first entry in a map + * 3. we're sending an end-of-map + */ +struct nis_all_cookie { + enum nis_all_cookie_state { + cookie_bad, + cookie_first, + cookie_next, + cookie_this, + cookie_end1, + cookie_end2, + } state; + unsigned int key_length; + char key[1]; +}; +static void +nis_all_free_cookie(struct nis_all_cookie *cookie) +{ + free(cookie); +} +static struct nis_all_cookie * +nis_all_make_cookie(enum nis_all_cookie_state state, + unsigned int length, const char *value) +{ + struct nis_all_cookie *cookie; + cookie = malloc(sizeof(*cookie) + ((length > 0) ? length : 0)); + if (cookie != NULL) { + cookie->state = state; + switch (cookie->state) { + case cookie_bad: + case cookie_first: + case cookie_end1: + case cookie_end2: + break; + case cookie_this: + case cookie_next: + cookie->key_length = length; + if ((length > 0) && (value != NULL)) { + memcpy(&cookie->key, value, length); + } + break; + } + } + return cookie; +} + static void nis_all(struct plugin_state *state, dispatch_reply_fragment *reply_fragment_fn, @@ -365,92 +414,303 @@ nis_all(struct plugin_state *state, struct ypreq_nokey req_nokey; keydat_t *reply_key; valdat_t *reply_val; - bool_t supported; + struct nis_all_cookie *cookie; + enum nis_all_cookie_state next_state; + bool_t supported, stop; memset(&req_nokey, 0, sizeof(req_nokey)); reply_key = &reply_all->ypresp_all_u.val.keydat; reply_val = &reply_all->ypresp_all_u.val.valdat; if (xdr_ypreq_nokey(request_xdrs, &req_nokey)) { + /* Take ownership of the cookie data. */ + if (continuation_cookie) { + if (*continuation_cookie != NULL) { + cookie = *continuation_cookie; + } else { + cookie = nis_all_make_cookie(cookie_bad, + 0, NULL); + } + *continuation_cookie = NULL; + } else { + cookie = nis_all_make_cookie(cookie_bad, + 0, NULL); + } + /* Check if we even support the map. */ if (!map_supports_map(state, req_nokey.domain, req_nokey.map, &supported) || !supported) { - /* No entries? No such map final status. */ + /* No entries? No-such-map final status. */ reply_all->more = TRUE; reply_all->ypresp_all_u.val.status = YP_NOMAP; reply_key->keydat_len = 0; reply_val->valdat_len = 0; - (*reply_fragment_fn)(state, cdata, - reply, reply_xdrs, reply_buf, - TRUE, FALSE); + /* Encode the reply header so that we can queue the + * entire reply as one block. */ + xdr_replymsg(reply_xdrs, reply); /* End of data. */ reply_all->more = FALSE; - xdr_setpos(reply_xdrs, 0); xdr_ypresp_all(reply_xdrs, reply_all); - (*reply_fragment_fn)(state, cdata, - reply, reply_xdrs, reply_buf, - FALSE, TRUE); - } else { - bool_t first; - reply_all->more = TRUE; - reply_all->ypresp_all_u.val.status = YP_TRUE; - reply_all->more = map_first(state, - req_nokey.domain, - req_nokey.map, - &reply_key->keydat_len, - &reply_key->keydat_val, - &reply_val->valdat_len, - &reply_val->valdat_val); - first = TRUE; - do { - /* Send back a result. If it's the first - * entry, also send back the reply header. */ + /* Queue the entire response. */ + if (!(*reply_fragment_fn)(state, cdata, + reply, reply_xdrs, reply_buf, + FALSE, TRUE)) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, - "all(%s/%s) -> (%.*s),%d\n", + "all(%s/%s) - error queueing " + "error response\n", req_nokey.domain, - req_nokey.map, - reply_key->keydat_len, - reply_key->keydat_val, - reply_all->more); - (*reply_fragment_fn)(state, cdata, - reply, - reply_xdrs, reply_buf, - first, FALSE); - first = FALSE; - /* Find the next entry. */ - reply_all->more = map_next(state, - req_nokey.domain, - req_nokey.map, - reply_key->keydat_len, - reply_key->keydat_val, - &reply_key->keydat_len, - &reply_key->keydat_val, - &reply_val->valdat_len, - &reply_val->valdat_val); - /* If we got an entry, encode it. */ - if (reply_all->more) { - xdr_setpos(reply_xdrs, 0); - xdr_ypresp_all(reply_xdrs, reply_all); - } - } while (reply_all->more); - /* Send the end-of-map marker. */ - reply_all->ypresp_all_u.val.status = YP_NOMORE; - reply_key->keydat_len = 0; - reply_val->valdat_len = 0; + req_nokey.map); + } + /* Don't return a cookie, if one was passed to us. */ + nis_all_free_cookie(cookie); + cookie = NULL; + } else + for (stop = FALSE; stop == FALSE;) { + bool_t found, skip; xdr_setpos(reply_xdrs, 0); - reply_all->more = TRUE; - xdr_ypresp_all(reply_xdrs, reply_all); - /* End of data. */ - reply_all->more = FALSE; - xdr_ypresp_all(reply_xdrs, reply_all); - /* Bundle those two chunks into one reply. */ - (*reply_fragment_fn)(state, cdata, - reply, reply_xdrs, reply_buf, - FALSE, TRUE); - slapi_log_error(SLAPI_LOG_PLUGIN, - state->plugin_desc->spd_id, - "all(%s/%s) done\n", - req_nokey.domain, req_nokey.map); + memset(reply_all, 0, sizeof(reply_all)); + /* Follow any instructions we left for this iteration. + */ + switch (cookie->state) { + case cookie_bad: + /* fall through */ + case cookie_first: + /* Read the first key in the map, and make the + * next state either be queuing the first item + * or queueing the end-of-map reply. */ + found = map_first(state, + req_nokey.domain, + req_nokey.map, + &reply_key->keydat_len, + &reply_key->keydat_val, + &reply_val->valdat_len, + &reply_val->valdat_val); + if (found) { + /* Next time grab the entry after this + * one. */ + slapi_log_error(SLAPI_LOG_PLUGIN, + state->plugin_desc->spd_id, + "all(%s/%s) \"%.*s\"\n", + req_nokey.domain, + req_nokey.map, + reply_key->keydat_len, + reply_key->keydat_val); + skip = FALSE; + reply_all->more = TRUE; + reply_all->ypresp_all_u.val.status = YP_TRUE; + next_state = cookie_next; + } else { + /* Don't reply, just move to end-of-map + * state. */ + slapi_log_error(SLAPI_LOG_PLUGIN, + state->plugin_desc->spd_id, + "all(%s/%s) no-first\n", + req_nokey.domain, + req_nokey.map); + skip = TRUE; + next_state = cookie_end1; + } + /* Try to queue the packet. */ + nis_all_free_cookie(cookie); + if (skip || + (*reply_fragment_fn)(state, cdata, + reply, + reply_xdrs, reply_buf, + TRUE, FALSE)) { + /* Leave a note to choose the next + * entry or send end1, whichever is + * appropriate. */ + cookie = nis_all_make_cookie(next_state, + reply_key->keydat_len, + reply_key->keydat_val); + } else { + /* Leave a note to try sending the + * first entry again. */ + cookie = nis_all_make_cookie(cookie_first, + 0, NULL); + stop = TRUE; + } + break; + case cookie_next: + /* Read the next key in the map, and set up the + * cookie to note that we're queuing a not- + * first item. */ + found = map_next(state, + req_nokey.domain, + req_nokey.map, + cookie->key_length, + cookie->key, + &reply_key->keydat_len, + &reply_key->keydat_val, + &reply_val->valdat_len, + &reply_val->valdat_val); + if (found) { + slapi_log_error(SLAPI_LOG_PLUGIN, + state->plugin_desc->spd_id, + "all(%s/%s) \"%.*s\"\n", + req_nokey.domain, + req_nokey.map, + reply_key->keydat_len, + reply_key->keydat_val); + /* Next time grab the entry after this + * one. */ + skip = FALSE; + reply_all->more = TRUE; + reply_all->ypresp_all_u.val.status = YP_TRUE; + next_state = cookie_next; + } else { + /* Don't reply, just move to end-of-map + * state. */ + slapi_log_error(SLAPI_LOG_PLUGIN, + state->plugin_desc->spd_id, + "all(%s/%s) no-next\n", + req_nokey.domain, + req_nokey.map); + skip = TRUE; + next_state = cookie_end1; + } + /* Try to queue the packet. */ + if (skip || + (xdr_ypresp_all(reply_xdrs, reply_all) && + (*reply_fragment_fn)(state, cdata, + reply, + reply_xdrs, reply_buf, + FALSE, FALSE))) { + /* Leave a note to choose the next + * entry or send end1, whichever is + * appropriate. */ + nis_all_free_cookie(cookie); + cookie = nis_all_make_cookie(next_state, + reply_key->keydat_len, + reply_key->keydat_val); + } else { + /* Leave a note to retry sending this + * entry the next time. */ + nis_all_free_cookie(cookie); + cookie = nis_all_make_cookie(cookie_this, + reply_key->keydat_len, + reply_key->keydat_val); + stop = TRUE; + } + break; + case cookie_this: + /* Read the matching key in the map, and set up + * the cookie to note that we're queuing a not- + * first item. */ + reply_key->keydat_len = cookie->key_length; + reply_key->keydat_val = cookie->key; + found = map_match(state, + req_nokey.domain, + req_nokey.map, + reply_key->keydat_len, + reply_key->keydat_val, + &reply_val->valdat_len, + &reply_val->valdat_val); + if (found) { + /* Next time grab the entry after this + * one. */ + slapi_log_error(SLAPI_LOG_PLUGIN, + state->plugin_desc->spd_id, + "all(%s/%s) \"%.*s\" " + "(retry)\n", + req_nokey.domain, + req_nokey.map, + cookie->key_length, + cookie->key); + skip = FALSE; + reply_all->more = TRUE; + reply_all->ypresp_all_u.val.status = YP_TRUE; + next_state = cookie_next; + } else { + /* Don't reply, just move to end-of-map + * state. */ + slapi_log_error(SLAPI_LOG_PLUGIN, + state->plugin_desc->spd_id, + "all(%s/%s) \"%.*s\" " + "(disappeared?)\n", + req_nokey.domain, + req_nokey.map, + cookie->key_length, + cookie->key); + skip = TRUE; + next_state = cookie_end1; + } + /* Try to queue the packet. */ + if (skip || + (xdr_ypresp_all(reply_xdrs, reply_all) && + (*reply_fragment_fn)(state, cdata, + reply, + reply_xdrs, reply_buf, + FALSE, FALSE))) { + /* Leave a note to choose the next + * entry or send end1, whichever is + * appropriate. */ + nis_all_free_cookie(cookie); + cookie = nis_all_make_cookie(next_state, + reply_key->keydat_len, + reply_key->keydat_val); + } else { + /* Leave a note to retry sending this + * entry the next time. But that's how + * we got here, so do nothing. */ + stop = TRUE; + } + break; + case cookie_end1: + /* Send the end-of-map message. */ + memset(reply_key, 0, sizeof(*reply_key)); + memset(reply_val, 0, sizeof(*reply_key)); + reply_all->more = TRUE; + reply_all->ypresp_all_u.val.status = YP_NOMORE; + slapi_log_error(SLAPI_LOG_PLUGIN, + state->plugin_desc->spd_id, + "all(%s/%s) end-of-map\n", + req_nokey.domain, + req_nokey.map); + if (xdr_ypresp_all(reply_xdrs, reply_all) && + (*reply_fragment_fn)(state, cdata, + reply, + reply_xdrs, reply_buf, + FALSE, FALSE)) { + /* Leave a note to finish the reply. */ + nis_all_free_cookie(cookie); + cookie = nis_all_make_cookie(cookie_end2, + 0, NULL); + } else { + /* Leave the note alone, so that we'll + * have to try again. */ + stop = TRUE; + } + break; + case cookie_end2: + /* Send the final message. */ + reply_all->more = FALSE; + slapi_log_error(SLAPI_LOG_PLUGIN, + state->plugin_desc->spd_id, + "all(%s/%s) done\n", + req_nokey.domain, + req_nokey.map); + if (xdr_ypresp_all(reply_xdrs, reply_all) && + (*reply_fragment_fn)(state, cdata, + reply, + reply_xdrs, reply_buf, + FALSE, TRUE)) { + /* We're done. */ + nis_all_free_cookie(cookie); + cookie = NULL; + } else { + /* Leave the note alone, so that we'll + * have to try again. */ + } + stop = TRUE; + break; + } + } + /* Return the cookie if we can, else destroy it. */ + if (continuation_cookie) { + *continuation_cookie = cookie; + } else { + nis_all_free_cookie(cookie); } } else { /* XXX */ |