static void analyze_backticks(void) { int myline = *ratslexer.lex_lineno; int column = *ratslexer.lex_column; if (ratslexer.lang == LANG_C) return; /* we're just gobbling up whatever is in the backticks and * ignoring them for now. */ scan_tokens(gobble_backtick, NULL); switch (ratslexer.lang) { case LANG_PYTHON: log_pythonbacktick(myline, column, Medium); break; case LANG_PHP: log_phpbacktick(myline, column,Medium); break; case LANG_PERL: log_perlbacktick(myline, column,Medium); break; case LANG_RUBY: log_rubybacktick(myline, column,Medium); break; } }
static void scan_arguments(void) { int i; argscan_t data; data.tail = (argument_t *)NULL; data.current = (argument_t *)NULL; for (i = 0; i < DEPTH_COUNT; i++) data.depths[i] = depths[i]; scan_tokens(check_argument, (void *)&data); }
/* * XXX: This function can be cleaned up to prevent more false positives. * Currently running lex.yy.c through this yields false positives due to * pointer initializers, i.e. char *foo = bar[15]; - MMessier, 09-May-2001 */ static void analyze_variable(int token) { charscan_t data; /* If we're processing arguments right now, we don't want to check for * stack variables because they're not really stack variables */ if (current_frame != (rats_stack_t *)NULL && current_frame->next != (rats_stack_t *)NULL) return; if (depths[DEPTH_PARENTHESIS] || depths[DEPTH_BRACKET]) return; data.column = *ratslexer.lex_column; data.lineno = *ratslexer.lex_lineno; data.initial_type = token; data.last_token = token; data.depth = depths[DEPTH_BRACE]; data.skip = 0; scan_tokens(check_buffer, (void *)&data); }
bool protocol_stats_merge_line(genhash_t *merger, char *line) { int nline; token_t tokens[MAX_TOKENS]; int ntokens; char *name; int name_len; cb_assert(merger != NULL); cb_assert(line != NULL); nline = strlen(line); /* Ex: "STATS uptime 123455" */ if (nline <= 0 || nline >= MERGE_BUF_SIZE) { return false; } ntokens = scan_tokens(line, tokens, MAX_TOKENS, NULL); if (ntokens != 4) { /* 3 + 1 for the terminal token. */ return false; } name = tokens[NAME_TOKEN].value; name_len = tokens[NAME_TOKEN].length; if (name == NULL || name_len <= 0 || tokens[VALUE_TOKEN].value == NULL || tokens[VALUE_TOKEN].length <= 0 || tokens[VALUE_TOKEN].length >= MERGE_BUF_SIZE) { return false; } return protocol_stats_merge_name_val(merger, tokens[PREFIX_TOKEN].value, tokens[PREFIX_TOKEN].length, name, name_len, tokens[VALUE_TOKEN].value, tokens[VALUE_TOKEN].length); }
void cproxy_process_a2a_downstream(conn *c, char *line) { assert(c != NULL); assert(c->next == NULL); assert(c->extra != NULL); assert(c->cmd == -1); assert(c->item == NULL); assert(line != NULL); assert(line == c->rcurr); assert(IS_ASCII(c->protocol)); assert(IS_PROXY(c->protocol)); if (settings.verbose > 1) fprintf(stderr, "<%d cproxy_process_a2a_downstream %s\n", c->sfd, line); downstream *d = c->extra; assert(d != NULL); assert(d->ptd != NULL); assert(d->ptd->proxy != NULL); if (strncmp(line, "VALUE ", 6) == 0) { token_t tokens[MAX_TOKENS]; size_t ntokens; unsigned int flags; int clen = 0; int vlen; uint64_t cas = CPROXY_NOT_CAS; ntokens = scan_tokens(line, tokens, MAX_TOKENS, &clen); if (ntokens >= 5 && // Accounts for extra termimation token. ntokens <= 6 && tokens[KEY_TOKEN].length <= KEY_MAX_LENGTH && safe_strtoul(tokens[2].value, (uint32_t *) &flags) && safe_strtoul(tokens[3].value, (uint32_t *) &vlen)) { char *key = tokens[KEY_TOKEN].value; size_t nkey = tokens[KEY_TOKEN].length; item *it = item_alloc(key, nkey, flags, 0, vlen + 2); if (it != NULL) { if (ntokens == 5 || safe_strtoull(tokens[4].value, &cas)) { ITEM_set_cas(it, cas); c->item = it; c->ritem = ITEM_data(it); c->rlbytes = it->nbytes; c->cmd = -1; conn_set_state(c, conn_nread); return; // Success. } else { if (settings.verbose > 1) fprintf(stderr, "cproxy could not parse cas\n"); } } else { if (settings.verbose > 1) fprintf(stderr, "cproxy could not item_alloc size %u\n", vlen + 2); } if (it != NULL) item_remove(it); it = NULL; c->sbytes = vlen + 2; // Number of bytes to swallow. conn_set_state(c, conn_swallow); // Note, eventually, we'll see an END later. } else { // We don't know how much to swallow, so close the downstream. // The conn_closing should release the downstream, // which should write a suffix/error to the upstream. // conn_set_state(c, conn_closing); } } else if (strncmp(line, "END", 3) == 0) { conn_set_state(c, conn_pause); } else if (strncmp(line, "OK", 2) == 0) { conn_set_state(c, conn_pause); // TODO: Handle flush_all's expiration parameter against // the front_cache. // // TODO: We flush the front_cache too often, inefficiently // on every downstream flush_all OK response, rather than // on just the last flush_all OK response. // conn *uc = d->upstream_conn; if (uc != NULL && uc->cmd_curr == PROTOCOL_BINARY_CMD_FLUSH) { mcache_flush_all(&d->ptd->proxy->front_cache, 0); } } else if (strncmp(line, "STAT ", 5) == 0 || strncmp(line, "ITEM ", 5) == 0 || strncmp(line, "PREFIX ", 7) == 0) { assert(d->merger != NULL); conn *uc = d->upstream_conn; if (uc != NULL) { assert(uc->next == NULL); if (protocol_stats_merge_line(d->merger, line) == false) { // Forward the line as-is if we couldn't merge it. // int nline = strlen(line); item *it = item_alloc("s", 1, 0, 0, nline + 2); if (it != NULL) { strncpy(ITEM_data(it), line, nline); strncpy(ITEM_data(it) + nline, "\r\n", 2); if (add_conn_item(uc, it)) { add_iov(uc, ITEM_data(it), nline + 2); it = NULL; } if (it != NULL) item_remove(it); } } } conn_set_state(c, conn_new_cmd); } else { conn_set_state(c, conn_pause); // The upstream conn might be NULL when closed already // or while handling a noreply. // conn *uc = d->upstream_conn; if (uc != NULL) { assert(uc->next == NULL); out_string(uc, line); if (!update_event(uc, EV_WRITE | EV_PERSIST)) { if (settings.verbose > 1) fprintf(stderr, "Can't update upstream write event\n"); d->ptd->stats.stats.err_oom++; cproxy_close_conn(uc); } cproxy_del_front_cache_key_ascii_response(d, line, uc->cmd_start); } } }
/* Forward a simple one-liner command downstream. * For example, get, incr/decr, delete, etc. * The response, though, might be a simple line or * multiple VALUE+END lines. */ bool cproxy_forward_a2a_simple_downstream(downstream *d, char *command, conn *uc) { assert(d != NULL); assert(d->ptd != NULL); assert(d->ptd->proxy != NULL); assert(d->downstream_conns != NULL); assert(command != NULL); assert(uc != NULL); assert(uc->item == NULL); assert(uc->cmd_curr != -1); assert(d->multiget == NULL); assert(d->merger == NULL); // Handles get and gets. // if (uc->cmd_curr == PROTOCOL_BINARY_CMD_GET) { // Only use front_cache for 'get', not for 'gets'. // mcache *front_cache = (command[3] == ' ') ? &d->ptd->proxy->front_cache : NULL; return multiget_ascii_downstream(d, uc, a2a_multiget_start, a2a_multiget_skey, a2a_multiget_end, front_cache); } assert(uc->next == NULL); if (uc->cmd_curr == PROTOCOL_BINARY_CMD_FLUSH) return cproxy_broadcast_a2a_downstream(d, command, uc, "OK\r\n"); if (uc->cmd_curr == PROTOCOL_BINARY_CMD_STAT) { if (strncmp(command + 5, " reset", 6) == 0) return cproxy_broadcast_a2a_downstream(d, command, uc, "RESET\r\n"); if (cproxy_broadcast_a2a_downstream(d, command, uc, "END\r\n")) { d->merger = genhash_init(512, skeyhash_ops); return true; } else { return false; } } // TODO: Inefficient repeated scan_tokens. // int cmd_len = 0; token_t tokens[MAX_TOKENS]; size_t ntokens = scan_tokens(command, tokens, MAX_TOKENS, &cmd_len); char *key = tokens[KEY_TOKEN].value; int key_len = tokens[KEY_TOKEN].length; if (ntokens <= 1) { // This was checked long ago, while parsing assert(false); // the upstream conn. return false; } // Assuming we're already connected to downstream. // bool self = false; conn *c = cproxy_find_downstream_conn(d, key, key_len, &self); if (c != NULL) { if (self) { // TODO: This optimization could be done much earlier, // even before the upstream conn was assigned // to a downstream. // cproxy_optimize_to_self(d, uc, command); process_command(uc, command); return true; } if (cproxy_prep_conn_for_write(c)) { assert(c->state == conn_pause); out_string(c, command); if (settings.verbose > 1) fprintf(stderr, "forwarding to %d, noreply %d\n", c->sfd, uc->noreply); if (update_event(c, EV_WRITE | EV_PERSIST)) { d->downstream_used_start = 1; d->downstream_used = 1; if (cproxy_dettach_if_noreply(d, uc) == false) { cproxy_start_downstream_timeout(d, c); } else { c->write_and_go = conn_pause; // Do mcache_delete() here only during a noreply, // otherwise for with-reply requests, we could // be in a race with other clients repopulating // the front_cache. For with-reply requests, we // clear the front_cache when we get a success reply. // mcache_delete(&d->ptd->proxy->front_cache, key, key_len); } return true; } if (settings.verbose > 1) fprintf(stderr, "Couldn't update cproxy write event\n"); d->ptd->stats.stats.err_oom++; cproxy_close_conn(c); } else { d->ptd->stats.stats.err_downstream_write_prep++; cproxy_close_conn(c); } } return false; }
void cproxy_process_upstream_ascii(conn *c, char *line) { assert(c != NULL); assert(c->next == NULL); assert(c->extra != NULL); assert(c->cmd == -1); assert(c->item == NULL); assert(line != NULL); assert(line == c->rcurr); assert(IS_ASCII(c->protocol)); assert(IS_PROXY(c->protocol)); if (settings.verbose > 2) { moxi_log_write("<%d cproxy_process_upstream_ascii %s\n", c->sfd, line); } // Snapshot rcurr, because the caller, try_read_command(), changes it. // c->cmd_curr = -1; c->cmd_start = c->rcurr; c->cmd_start_time = msec_current_time; c->cmd_retries = 0; proxy_td *ptd = c->extra; assert(ptd != NULL); /* For commands set/add/replace, we build an item and read the data * directly into it, then continue in nread_complete(). */ if (!cproxy_prep_conn_for_write(c)) { ptd->stats.stats.err_upstream_write_prep++; conn_set_state(c, conn_closing); return; } bool mcmux_command = false; bool self_command = false; /* Check for proxy pattern - A:host:port or B:host:port */ if (true == settings.enable_mcmux_mode && ((*line == 'A' || *line == 'B') && *(line + 1) == ':')) { mcmux_command = true; } else if (true == settings.enable_mcmux_mode) { self_command = true; } c->peer_protocol = 0; c->peer_host = NULL; c->peer_port = 0; if (mcmux_command) { char *peer_port = NULL; int i = 0; c->peer_protocol = (*line == 'A') ? proxy_downstream_ascii_prot : proxy_downstream_binary_prot; line += 2; c->peer_host = line; while (*line != ' ' && *line != '\0' && *line != ':' && ++i < MAX_HOSTNAME_LEN) { line++; } if (*line == '\0' || line - c->peer_host <= 0) { out_string(c, "ERROR"); moxi_log_write("Malformed request line"); return; } *line = '\0'; line++; peer_port = line; i = 0; while (*line != ' ' && *line != '\0' && ++i <= MAX_PORT_LEN) { line++; } if (*line == '\0' || line - peer_port <= 0) { out_string(c, "ERROR"); moxi_log_write("Malformed request line"); return; } c->peer_port = atoi(peer_port); *line++ = '\0'; c->cmd_start = line; } int cmd_len = 0; token_t tokens[MAX_TOKENS]; size_t ntokens = scan_tokens(line, tokens, MAX_TOKENS, &cmd_len); char *cmd = tokens[COMMAND_TOKEN].value; int cmdx = -1; int cmd_st = STATS_CMD_TYPE_REGULAR; int comm; #define SEEN(cmd_id, is_cas, cmd_len) \ cmd_st = c->noreply ? \ STATS_CMD_TYPE_QUIET : STATS_CMD_TYPE_REGULAR; \ ptd->stats.stats_cmd[cmd_st][cmd_id].seen++; \ ptd->stats.stats_cmd[cmd_st][cmd_id].read_bytes += cmd_len; \ if (is_cas) { \ ptd->stats.stats_cmd[cmd_st][cmd_id].cas++; \ } if (ntokens >= 3 && (false == self_command) && (strncmp(cmd, "get", 3) == 0)) { if (cmd[3] == 'l') { c->cmd_curr = PROTOCOL_BINARY_CMD_GETL; } else if (ntokens == 3) { // Single-key get/gets optimization. // c->cmd_curr = PROTOCOL_BINARY_CMD_GETK; } else { c->cmd_curr = PROTOCOL_BINARY_CMD_GETKQ; } // Handles get and gets. // cproxy_pause_upstream_for_downstream(ptd, c); // The cmd_len from scan_tokens might not include // all the keys, so cmd_len might not == strlen(command). // Handle read_bytes during multiget broadcast. // if (cmd[3] == 'l') { SEEN(STATS_CMD_GETL, true, 0); } else { SEEN(STATS_CMD_GET, cmd[3] == 's', 0); } } else if ((ntokens == 6 || ntokens == 7) && (false == self_command) && ((strncmp(cmd, "add", 3) == 0 && (comm = NREAD_ADD) && (cmdx = STATS_CMD_ADD) && (c->cmd_curr = PROTOCOL_BINARY_CMD_ADD)) || (strncmp(cmd, "set", 3) == 0 && (comm = NREAD_SET) && (cmdx = STATS_CMD_SET) && (c->cmd_curr = PROTOCOL_BINARY_CMD_SET)) || (strncmp(cmd, "replace", 7) == 0 && (comm = NREAD_REPLACE) && (cmdx = STATS_CMD_REPLACE) && (c->cmd_curr = PROTOCOL_BINARY_CMD_REPLACE)) || (strncmp(cmd, "prepend", 7) == 0 && (comm = NREAD_PREPEND) && (cmdx = STATS_CMD_PREPEND) && (c->cmd_curr = PROTOCOL_BINARY_CMD_PREPEND)) || (strncmp(cmd, "append", 6) == 0 && (comm = NREAD_APPEND) && (cmdx = STATS_CMD_APPEND) && (c->cmd_curr = PROTOCOL_BINARY_CMD_APPEND)))) { assert(c->item == NULL); c->item = NULL; process_update_command(c, tokens, ntokens, comm, false); if (cmdx >= 0) { item *it = c->item; if (it != NULL) { SEEN(cmdx, false, cmd_len + it->nbytes); } else { SEEN(cmdx, false, cmd_len); ptd->stats.stats_cmd[cmd_st][cmdx].misses++; } } } else if ((ntokens == 7 || ntokens == 8) && (false == self_command) && (strncmp(cmd, "cas", 3) == 0 && (comm = NREAD_CAS) && (c->cmd_curr = PROTOCOL_BINARY_CMD_SET))) { assert(c->item == NULL); c->item = NULL; process_update_command(c, tokens, ntokens, comm, true); item *it = c->item; if (it != NULL) { SEEN(STATS_CMD_CAS, true, cmd_len + it->nbytes); } else { SEEN(STATS_CMD_CAS, true, cmd_len); ptd->stats.stats_cmd[cmd_st][STATS_CMD_CAS].misses++; } } else if ((ntokens == 4 || ntokens == 5) && (false == self_command) && (strncmp(cmd, "incr", 4) == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_INCREMENT)) { set_noreply_maybe(c, tokens, ntokens); cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_INCR, false, cmd_len); } else if ((ntokens == 4 || ntokens == 5) && (false == self_command) && (strncmp(cmd, "decr", 4) == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_DECREMENT)) { set_noreply_maybe(c, tokens, ntokens); cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_DECR, false, cmd_len); } else if (ntokens >= 3 && ntokens <= 4 && (false == self_command) && (strncmp(cmd, "delete", 6) == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_DELETE)) { set_noreply_maybe(c, tokens, ntokens); cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_DELETE, false, cmd_len); } else if (ntokens >= 2 && ntokens <= 4 && (false == self_command) && (strncmp(cmd, "flush_all", 9) == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_FLUSH)) { set_noreply_maybe(c, tokens, ntokens); cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_FLUSH_ALL, false, cmd_len); } else if (ntokens >= 3 && ntokens <= 4 && (strncmp(cmd, "stats proxy", 10) == 0)) { process_stats_proxy_command(c, tokens, ntokens); SEEN(STATS_CMD_STATS, false, cmd_len); } else if (ntokens == 3 && (false == self_command) && (strcmp(cmd, "stats reset") == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_STAT)) { cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_STATS_RESET, false, cmd_len); } else if (ntokens == 2 && (false == self_command) && (strcmp(cmd, "stats") == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_STAT)) { // Even though we've coded to handle advanced stats // like stats cachedump, prevent those here to avoid // locking downstream servers. // cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_STATS, false, cmd_len); } else if (ntokens == 2 && (true == mcmux_command) && (strncmp(cmd, "version", 7) == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_VERSION)) { /* downstream version command */ cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_VERSION, false, cmd_len); } else if (ntokens == 2 && (strncmp(cmd, "version", 7) == 0)) { out_string(c, "VERSION " VERSION); SEEN(STATS_CMD_VERSION, false, cmd_len); } else if ((ntokens == 3 || ntokens == 4) && (strncmp(cmd, "verbosity", 9) == 0)) { process_verbosity_command(c, tokens, ntokens); SEEN(STATS_CMD_VERBOSITY, false, cmd_len); } else if (ntokens == 2 && (strncmp(cmd, "quit", 4) == 0)) { conn_set_state(c, conn_closing); SEEN(STATS_CMD_QUIT, false, cmd_len); } else if (ntokens == 4 && (strncmp(cmd, "unl", 3) == 0) && (false == self_command) && (c->cmd_curr = PROTOCOL_BINARY_CMD_UNL)) { cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_UNL, false, cmd_len); } else { out_string(c, "ERROR"); SEEN(STATS_CMD_ERROR, false, cmd_len); } }
void process_file(char *filename, int forcelang) { FILE *fd = NULL; int i; accumulator_t * acc; #ifdef _MSC_VER struct _stat fstat; #else struct stat fstat; #endif /* * We need to determine the filetype first. * If it's a real file, process normally. * If it's a directory and the recursion flag is set, iterate through the * files in the directory and run process_file on them. */ if (!strcmp(filename, "<stdin>")) { fd=stdin; } else { if(lstat(filename,&fstat)==-1) { fprintf(stderr,"An error occurred. The file '%s' does not appear to exist\n", filename); return; } #ifndef _MSC_VER /* Symbolic link check */ if(S_ISLNK(fstat.st_mode)) { if(flags & FOLLOW_SYMLINK) { char *symname; symname=calloc(PATH_MAX,1); if(readlink(filename,symname,PATH_MAX)==-1) { return; } process_file(symname,forcelang); } return; } #endif if(S_ISDIR(fstat.st_mode)) { /* Need to error catch here.*/ if( flags & RECURSIVE_FILE_SCAN ) { process_directory(filename,forcelang); return; } } if (!S_ISREG(fstat.st_mode)) { printf("NOT REGULAR FILE\n"); return; } } if(!fd && (fd=fopen(filename,"r")) == (FILE *)NULL) { return; } /* (Re-)Initialize state */ if(!determine_language(filename, fd, forcelang)) { fclose(fd); return; } *ratslexer.lex_lineno = 1; last_text_line = 0; current_file = strdup(filename); for (i = 0; i < DEPTH_COUNT; depths[i++] = 0); /* Process the file */ if (!(flags & NO_STATUS)) { if ((flags & HTML_OUTPUT)) { printf("Analyzing <b>%s</b><br>\n", filename); } else if (flags & XML_OUTPUT) { printf("<analyzed>%s</analyzed>\n", filename); } else { printf("Analyzing %s\n", filename); } } scan_tokens((processorfn_t)NULL, NULL); process_toctou(); total_lines += *ratslexer.lex_lineno; /* Cleanup */ current_ignore = (ignore_t *)NULL; while ((acc = accumulators) != (accumulator_t *)NULL) { if (*(acc->text) != (char *)NULL) free(*(acc->text)); pop_accumulator(); } fclose(fd); }
/* Forward a simple one-liner command downstream. * For example, get, incr/decr, delete, etc. * The response, though, might be a simple line or * multiple VALUE+END lines. */ bool cproxy_forward_a2a_simple_downstream(downstream *d, char *command, conn *uc) { cb_assert(d != NULL); cb_assert(d->ptd != NULL); cb_assert(d->ptd->proxy != NULL); cb_assert(d->downstream_conns != NULL); cb_assert(command != NULL); cb_assert(uc != NULL); cb_assert(uc->item == NULL); cb_assert(uc->cmd_curr != (protocol_binary_command) -1); cb_assert(d->multiget == NULL); cb_assert(d->merger == NULL); /* Handles get and gets. */ if (uc->cmd_curr == PROTOCOL_BINARY_CMD_GETK || uc->cmd_curr == PROTOCOL_BINARY_CMD_GETKQ || uc->cmd_curr == PROTOCOL_BINARY_CMD_GETL) { /* Only use front_cache for 'get', not for 'gets'. */ mcache *front_cache = (command[3] == ' ') ? &d->ptd->proxy->front_cache : NULL; return multiget_ascii_downstream(d, uc, a2a_multiget_start, a2a_multiget_skey, a2a_multiget_end, front_cache); } cb_assert(uc->next == NULL); if (uc->cmd_curr == PROTOCOL_BINARY_CMD_FLUSH) { return cproxy_broadcast_a2a_downstream(d, command, uc, "OK\r\n"); } if (uc->cmd_curr == PROTOCOL_BINARY_CMD_STAT) { if (strncmp(command + 5, " reset", 6) == 0) { return cproxy_broadcast_a2a_downstream(d, command, uc, "RESET\r\n"); } if (cproxy_broadcast_a2a_downstream(d, command, uc, "END\r\n")) { d->merger = genhash_init(512, skeyhash_ops); return true; } else { return false; } } /* TODO: Inefficient repeated scan_tokens. */ int cmd_len = 0; token_t tokens[MAX_TOKENS]; size_t ntokens = scan_tokens(command, tokens, MAX_TOKENS, &cmd_len); char *key = tokens[KEY_TOKEN].value; int key_len = tokens[KEY_TOKEN].length; if (ntokens <= 1) { /* This was checked long ago, while parsing */ cb_assert(false); /* the upstream conn. */ return false; } /* Assuming we're already connected to downstream. */ if (!strcmp(command, "version")) { /* fake key for version command handling */ key = "v"; key_len = 1; } conn *c = cproxy_find_downstream_conn(d, key, key_len, NULL); if (c != NULL) { if (cproxy_prep_conn_for_write(c)) { cb_assert(c->state == conn_pause); out_string(c, command); if (settings.verbose > 1) { moxi_log_write("forwarding to %d, noreply %d\n", c->sfd, uc->noreply); } if (update_event(c, EV_WRITE | EV_PERSIST)) { d->downstream_used_start = 1; d->downstream_used = 1; if (cproxy_dettach_if_noreply(d, uc) == false) { cproxy_start_downstream_timeout(d, c); } else { c->write_and_go = conn_pause; /* Do mcache_delete() here only during a noreply, */ /* otherwise for with-reply requests, we could */ /* be in a race with other clients repopulating */ /* the front_cache. For with-reply requests, we */ /* clear the front_cache when we get a success reply. */ cproxy_front_cache_delete(d->ptd, key, key_len); } return true; } if (settings.verbose > 1) { moxi_log_write("Couldn't update cproxy write event\n"); } d->ptd->stats.stats.err_oom++; cproxy_close_conn(c); } else { d->ptd->stats.stats.err_downstream_write_prep++; cproxy_close_conn(c); } } return false; }
void protocol_stats_foreach_write(const void *key, const void *value, void *user_data) { char *line = (char *) value; conn *uc = (conn *) user_data; int nline; cb_assert(line != NULL); cb_assert(uc != NULL); (void)key; nline = strlen(line); if (nline > 0) { item *it; if (settings.verbose > 2) { moxi_log_write("%d: cproxy_stats writing: %s\n", uc->sfd, line); } if (IS_BINARY(uc->protocol)) { token_t line_tokens[MAX_TOKENS]; size_t line_ntokens = scan_tokens(line, line_tokens, MAX_TOKENS, NULL); if (line_ntokens == 4) { uint16_t key_len = line_tokens[NAME_TOKEN].length; uint32_t data_len = line_tokens[VALUE_TOKEN].length; it = item_alloc("s", 1, 0, 0, sizeof(protocol_binary_response_stats) + key_len + data_len); if (it != NULL) { protocol_binary_response_stats *header = (protocol_binary_response_stats *) ITEM_data(it); memset(ITEM_data(it), 0, it->nbytes); header->message.header.response.magic = (uint8_t) PROTOCOL_BINARY_RES; header->message.header.response.opcode = uc->binary_header.request.opcode; header->message.header.response.keylen = (uint16_t) htons(key_len); header->message.header.response.bodylen = htonl(key_len + data_len); header->message.header.response.opaque = uc->opaque; memcpy((ITEM_data(it)) + sizeof(protocol_binary_response_stats), line_tokens[NAME_TOKEN].value, key_len); memcpy((ITEM_data(it)) + sizeof(protocol_binary_response_stats) + key_len, line_tokens[VALUE_TOKEN].value, data_len); if (add_conn_item(uc, it)) { add_iov(uc, ITEM_data(it), it->nbytes); if (settings.verbose > 2) { moxi_log_write("%d: cproxy_stats writing binary", uc->sfd); cproxy_dump_header(uc->sfd, ITEM_data(it)); } return; } item_remove(it); } } return; } it = item_alloc("s", 1, 0, 0, nline + 2); if (it != NULL) { strncpy(ITEM_data(it), line, nline); strncpy(ITEM_data(it) + nline, "\r\n", 2); if (add_conn_item(uc, it)) { add_iov(uc, ITEM_data(it), nline + 2); return; } item_remove(it); } } }
bool protocol_stats_merge_name_val(genhash_t *merger, char *prefix, int prefix_len, char *name, int name_len, char *val, int val_len) { char *key; int key_len; cb_assert(merger); cb_assert(name); cb_assert(val); key = name + name_len - 1; /* Key part for merge rule lookup. */ while (key >= name && *key != ':') { /* Scan for last colon. */ key--; } if (key < name) { key = name; } key_len = name_len - (key - name); if (key_len > 0 && key_len < MERGE_BUF_SIZE) { char buf_name[MERGE_BUF_SIZE]; char buf_key[MERGE_BUF_SIZE]; char buf_val[MERGE_BUF_SIZE]; char *prev; token_t prev_tokens[MAX_TOKENS]; size_t prev_ntokens; bool ok; strncpy(buf_name, name, name_len); buf_name[name_len] = '\0'; prev = (char *) genhash_find(merger, buf_name); if (prev == NULL) { char *hval = malloc(prefix_len + 1 + name_len + 1 + val_len + 1); if (hval != NULL) { memcpy(hval, prefix, prefix_len); hval[prefix_len] = ' '; memcpy(hval + prefix_len + 1, name, name_len); hval[prefix_len + 1 + name_len] = ' '; memcpy(hval + prefix_len + 1 + name_len + 1, val, val_len); hval[prefix_len + 1 + name_len + 1 + val_len] = '\0'; genhash_update(merger, hval + prefix_len + 1, hval); } return true; } strncpy(buf_key, key, key_len); buf_key[key_len] = '\0'; if (strstr(protocol_stats_keys_first, buf_key) != NULL) { return true; } prev_ntokens = scan_tokens(prev, prev_tokens, MAX_TOKENS, NULL); if (prev_ntokens != 4) { return true; } strncpy(buf_val, val, val_len); buf_val[val_len] = '\0'; if (strstr(protocol_stats_keys_smallest, buf_key) != NULL) { ok = protocol_stats_merge_smallest(prev_tokens[VALUE_TOKEN].value, prev_tokens[VALUE_TOKEN].length, buf_val, val_len, buf_val, MERGE_BUF_SIZE); } else { ok = protocol_stats_merge_sum(prev_tokens[VALUE_TOKEN].value, prev_tokens[VALUE_TOKEN].length, buf_val, val_len, buf_val, MERGE_BUF_SIZE); } if (ok) { int vlen = strlen(buf_val); char *hval = malloc(prefix_len + 1 + name_len + 1 + vlen + 1); if (hval != NULL) { memcpy(hval, prefix, prefix_len); hval[prefix_len] = ' '; memcpy(hval + prefix_len + 1, name, name_len); hval[prefix_len + 1 + name_len] = ' '; strcpy(hval + prefix_len + 1 + name_len + 1, buf_val); hval[prefix_len + 1 + name_len + 1 + vlen] = '\0'; genhash_update(merger, hval + prefix_len + 1, hval); free(prev); } } /* Note, if we couldn't merge, then just keep */ /* the previous value. */ return true; } return false; }