/* * Adds data to the list of pending data that will be written out to a * connection. * * Returns 0 on success, -1 on out-of-memory. */ rstatus_t conn_add_iov(struct conn *c, const void *buf, int len) { struct msghdr *m; int leftover; bool limit_to_mtu; ASSERT(c != NULL); do { rstatus_t status; ASSERT(c->msg_used >= 1); m = &c->msg[c->msg_used - 1]; /* * Limit UDP packets, and the first payloads of TCP replies, to * UDP_MAX_PAYLOAD_SIZE bytes. */ limit_to_mtu = c->udp || (1 == c->msg_used); /* We may need to start a new msghdr if this one is full. */ if (m->msg_iovlen == IOV_MAX || (limit_to_mtu && c->msg_bytes >= UDP_MAX_PAYLOAD_SIZE)) { status = conn_add_msghdr(c); if (status != MC_OK) { return status; } } status = conn_ensure_iov_space(c); if (status != MC_OK) { return status; } /* if the fragment is too big to fit in the datagram, split it up */ if (limit_to_mtu && len + c->msg_bytes > UDP_MAX_PAYLOAD_SIZE) { leftover = len + c->msg_bytes - UDP_MAX_PAYLOAD_SIZE; len -= leftover; } else { leftover = 0; } ASSERT(c->msg_used >= 1); m = &c->msg[c->msg_used - 1]; m->msg_iov[m->msg_iovlen].iov_base = (void *)buf; m->msg_iov[m->msg_iovlen].iov_len = len; c->msg_bytes += len; c->iov_used++; m->msg_iovlen++; buf = ((char *)buf) + len; len = leftover; } while (leftover > 0); return MC_OK; }
// Adds data to the list of pending data that will be written out to a // connection. // // @return true on success, false on out-of-memory. bool conn_add_iov(conn *c, const void *buf, int len) { assert(c != NULL); int leftover; do { struct msghdr *m = &c->msglist[c->msgused - 1]; // Limit the first payloads of TCP replies, to MAX_PAYLOAD_SIZE bytes. bool limit_to_mtu = 1 == c->msgused; // We may need to start a new msghdr if this one is full. if (m->msg_iovlen == IOV_MAX || (limit_to_mtu && c->msgbytes >= MAX_PAYLOAD_SIZE)) { conn_add_msghdr(c); m = &c->msglist[c->msgused - 1]; } if (!ensure_iov_space(c)) return false; // If the fragment is too big to fit in the datagram, split it up. if (limit_to_mtu && len + c->msgbytes > MAX_PAYLOAD_SIZE) { leftover = len + c->msgbytes - MAX_PAYLOAD_SIZE; len -= leftover; } else { leftover = 0; } m = &c->msglist[c->msgused - 1]; m->msg_iov[m->msg_iovlen].iov_base = (void *)buf; m->msg_iov[m->msg_iovlen].iov_len = len; c->msgbytes += len; c->iovused++; m->msg_iovlen++; buf = ((char *)buf) + len; len = leftover; } while (leftover > 0); return true; }
static void asc_dispatch(struct conn *c) { rstatus_t status; struct token token[TOKEN_MAX]; int ntoken; /* * For commands set, add, or replace, we build an item and read the data * directly into it, then continue in asc_complete_nread(). */ c->msg_curr = 0; c->msg_used = 0; c->iov_used = 0; status = conn_add_msghdr(c); if (status != MC_OK) { log_warn("server error on c %d for req of type %d because of oom in " "preparing response", c->sd, c->req_type); asc_write_server_error(c); return; } ntoken = asc_tokenize(c->req, token, TOKEN_MAX); c->req_type = asc_parse_type(c, token, ntoken); switch (c->req_type) { case REQ_GET: case REQ_GETS: /* we do not update stats metrics here because of multi-get */ asc_process_read(c, token, ntoken); break; case REQ_SET: stats_thread_incr(set); asc_process_update(c, token, ntoken); break; case REQ_ADD: stats_thread_incr(add); asc_process_update(c, token, ntoken); break; case REQ_REPLACE: stats_thread_incr(replace); asc_process_update(c, token, ntoken); break; case REQ_APPEND: stats_thread_incr(append); asc_process_update(c, token, ntoken); break; case REQ_PREPEND: stats_thread_incr(prepend); asc_process_update(c, token, ntoken); break; case REQ_CAS: stats_thread_incr(cas); asc_process_update(c, token, ntoken); break; case REQ_INCR: stats_thread_incr(incr); asc_process_arithmetic(c, token, ntoken); break; case REQ_DECR: stats_thread_incr(decr); asc_process_arithmetic(c, token, ntoken); break; case REQ_DELETE: stats_thread_incr(delete); asc_process_delete(c, token, ntoken); break; case REQ_STATS: stats_thread_incr(stats); asc_process_stats(c, token, ntoken); break; case REQ_FLUSHALL: stats_thread_incr(flush); asc_process_flushall(c, token, ntoken); break; case REQ_VERSION: asc_write_version(c); break; case REQ_QUIT: conn_set_state(c, CONN_CLOSE); break; case REQ_VERBOSITY: asc_process_verbosity(c, token, ntoken); break; case REQ_CONFIG: asc_process_config(c, token, ntoken); break; case REQ_UNKNOWN: default: log_hexdump(LOG_INFO, c->req, c->req_len, "req on c %d with %d " "invalid tokens", c->sd, ntoken); asc_write_client_error(c); break; } }