void numstring::mul_int_string(int alpha) { #ifdef DEBUG printf("ENTERING mul_int_string with alpha of %d\n", alpha); #endif /* multiplies the input string in_string by the integer alpha */ numstring in_copy(nstring); numstring out_string("0"); do { int modulo = alpha % BASE; if (modulo) { if (modulo == 1) { out_string += in_copy; } else { numstring row(in_copy); row.mul_digit_string(modulo); out_string += row; } } in_copy = in_copy() + "0"; // multiply by 10 } while ((alpha = alpha / BASE)); #ifdef DEBUG printf("LEAVING mul_int_string with alpha of %d", alpha); printf(" and outstring of %s\n", out_string().c_str()); #endif nstring = out_string.nstring; }
void complete_nread(conn *c) { item *it = c->item; int comm = c->item_comm; item *old_it; time_t now = time(0); stats.set_cmds++; while(1) { if (strncmp(ITEM_data(it) + it->nbytes - 2, "\r\n", 2) != 0) { out_string(c, "CLIENT_ERROR bad data chunk"); break; } old_it = assoc_find(ITEM_key(it)); if (old_it && settings.oldest_live && old_it->time <= settings.oldest_live) { item_unlink(old_it); old_it = 0; } if (old_it && old_it->exptime && old_it->exptime < now) { item_unlink(old_it); old_it = 0; } if (old_it && comm==NREAD_ADD) { item_update(old_it); out_string(c, "NOT_STORED"); break; } if (!old_it && comm == NREAD_REPLACE) { out_string(c, "NOT_STORED"); break; } if (old_it && (old_it->it_flags & ITEM_DELETED) && (comm == NREAD_REPLACE || comm == NREAD_ADD)) { out_string(c, "NOT_STORED"); break; } if (old_it) { item_replace(old_it, it); } else item_link(it); c->item = 0; out_string(c, "STORED"); return; } item_free(it); c->item = 0; return; }
/*======================================================================* in_process *======================================================================*/ PUBLIC void in_process(TTY* p_tty, u32 key) { char output[2] = {'\0', '\0'}; if (p_tty->disable_output) { sys_char = key; return; } if (!(key & FLAG_EXT)) { if (p_tty->inbuf_count < TTY_IN_BYTES) { *(p_tty->p_inbuf_head) = key; p_tty->p_inbuf_head++; if (p_tty->p_inbuf_head == p_tty->in_buf + TTY_IN_BYTES) { p_tty->p_inbuf_head = p_tty->in_buf; } p_tty->inbuf_count++; } } else { int raw_code = key & MASK_RAW; switch(raw_code) { case UP: if ((key & SHIFT_L) || (key & SHIFT_R)) { scroll_screen(p_tty->p_console, SCR_UP); } break; case DOWN: if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) { scroll_screen(p_tty->p_console, SCR_DN); } break; case F1: case F2: case F3: if ((key & FLAG_ALT_L) || (key & FLAG_ALT_R)) { select_console(raw_code - F1); } break; case ENTER: out_string(p_tty->p_console, "\n> ", Blue); out_string(p_tty->p_console, "$ ", Light_Green); break; case BACKSPACE: out_char(p_tty->p_console, '\b', White); break; default: break; } } }
/* * read from network as much as we can, handle buffer overflow and connection * close. * return 0 if there's nothing to read on the first read. */ int try_read_network(conn *c) { int gotdata = 0; int res; while (1) { if (c->rbytes >= c->rsize) { char *new_rbuf = realloc(c->rbuf, c->rsize*2); if (!new_rbuf) { fprintf(stderr, "Couldn't realloc input buffer\n"); c->rbytes = 0; /* ignore what we read */ out_string(c, "SERVER_ERROR out of memory"); c->write_and_close = 1; return 1; } c->rbuf = new_rbuf; c->rsize *= 2; } res = read(c->sfd, c->rbuf + c->rbytes, c->rsize - c->rbytes); if (res > 0) { stats.bytes_read += res; gotdata = 1; c->rbytes += res; continue; } if (res == 0) { /* connection closed */ c->state = conn_closing; return 1; } if (res == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) break; else return 0; } } return gotdata; }
/** * Depending on our configuration, we can optimize SET's * on certain keys by making them fire-and-forget and * immediately transmitting a success response to the * upstream client. */ bool cproxy_optimize_set_ascii(downstream *d, conn *uc, char *key, int key_len) { assert(d); assert(d->ptd); assert(d->ptd->proxy); assert(uc); assert(uc->next == NULL); if (d->ptd->behavior_pool.base.optimize_set[0] == '\0') { return false; } if (matcher_check(&d->ptd->proxy->optimize_set_matcher, key, key_len, false)) { d->upstream_conn = NULL; d->upstream_suffix = NULL; d->upstream_suffix_len = 0; d->upstream_retry = 0; out_string(uc, "STORED"); if (!update_event(uc, EV_WRITE | EV_PERSIST)) { if (settings.verbose > 1) { moxi_log_write("ERROR: Can't update upstream write event\n"); } d->ptd->stats.stats.err_oom++; cproxy_close_conn(uc); } return true; } return false; }
void BDateColumn::DrawField(BField* _field, BRect rect, BView* parent) { float width = rect.Width() - (2 * kTEXT_MARGIN); BDateField* field = (BDateField*)_field; if (field->Width() != rect.Width()) { char dateString[256]; time_t curtime = field->UnixTime(); tm time_data; BFont font; parent->GetFont(&font); localtime_r(&curtime, &time_data); for (int32 index = 0; ; index++) { if (!kTIME_FORMATS[index]) break; strftime(dateString, 256, kTIME_FORMATS[index], &time_data); if (font.StringWidth(dateString) <= width) break; } if (font.StringWidth(dateString) > width) { BString out_string(dateString); parent->TruncateString(&out_string, B_TRUNCATE_MIDDLE, width + 2); strcpy(dateString, out_string.String()); } field->SetClippedString(dateString); field->SetWidth(width); } DrawString(field->ClippedString(), parent, rect); }
void BTitledColumn::DrawTitle(BRect rect, BView* parent) { float width = rect.Width() - (2 * kTEXT_MARGIN); BString out_string(fTitle); parent->TruncateString(&out_string, B_TRUNCATE_END, width + 2); DrawString(out_string.String(), parent, rect); }
/*======================================================================* clear_screen *======================================================================*/ PUBLIC void clear_screen(CONSOLE* p_con) { p_con->cursor = 0; for (int i = 0; i <= 25; i++) { for (int j = 0; j <= 40; j++) { out_string(p_con, " ", White); } } p_con->cursor = 0; if (p_con == console_table + nr_current_console){ set_cursor(p_con->cursor); set_video_start_addr(p_con->original_addr); } }
void SimpleMenu::pushBt_clicked(bool val){ // QString program = "./NNN"; // QProcess *myProcess = new QProcess(); // myProcess->start(program,0); QObject *parent; QString program = "/home/sweden/qt/mingxiao/NNN"; QStringList arguments; arguments << "";//-b" << "-t" << "input.txt"; QProcess *myProcess = new QProcess(parent); myProcess->start(program, arguments); if(myProcess->waitForStarted(5000)) { QByteArray out_data = myProcess->readAllStandardOutput(); QString out_string(out_data); qDebug() << out_string.toStdString().c_str(); } else { qDebug() << "myProcess did not start in time"; } QProcess::execute("gcc /home/sweden/hh.c -o /home/sweden/ggg"); system("/home/sweden/ggg"); //this->close(); if(falg==true){ QPixmap pixmap("/home/sweden/qt/mingxiao/bobo.jpg"); label->setPixmap(pixmap); falg = false ; return; }else { QPixmap pixmap("/home/sweden/qt/mingxiao/g.jpg"); label->setPixmap(pixmap); falg = true; return; } }
/*======================================================================* init_screen *======================================================================*/ PUBLIC void init_screen(TTY* p_tty) { int nr_tty = p_tty - tty_table; p_tty->p_console = console_table + nr_tty; int v_mem_size = V_MEM_SIZE >> 1; /* 显存总大小 (in WORD) */ int con_v_mem_size = v_mem_size / NR_CONSOLES; p_tty->p_console->original_addr = nr_tty * con_v_mem_size; p_tty->p_console->v_mem_limit = con_v_mem_size; p_tty->p_console->current_start_addr = p_tty->p_console->original_addr; /* 默认光标位置在最开始处 */ p_tty->p_console->cursor = p_tty->p_console->original_addr; if (nr_tty == 0) { p_tty->p_console->cursor = p_tty->p_console->original_addr + 80 * 9; } out_string(p_tty->p_console, "\tMuteOS login tty", White); out_char(p_tty->p_console, nr_tty + '0', White); out_string(p_tty->p_console, "\n> ", Blue); out_string(p_tty->p_console, "$ ", Light_Green); }
void BStringColumn::DrawField(BField* _field, BRect rect, BView* parent) { float width = rect.Width() - (2 * kTEXT_MARGIN); BStringField* field = static_cast<BStringField*>(_field); if (width != field->Width()) { BString out_string(field->String()); parent->TruncateString(&out_string, fTruncate, width + 2); field->SetClippedString(out_string.String()); field->SetWidth(width); } DrawString(field->ClippedString(), parent, rect); }
/*======================================================================* out_char *======================================================================*/ PUBLIC void out_char(CONSOLE* p_con, char ch, int color) { int row, column; u8* p_vmem = (u8*)(V_MEM_BASE + p_con->cursor * 2); switch(ch) { case '\n': if (p_con->cursor < p_con->original_addr + p_con->v_mem_limit - SCREEN_WIDTH) { p_con->cursor = p_con->original_addr + SCREEN_WIDTH * ((p_con->cursor - p_con->original_addr) / SCREEN_WIDTH + 1); } break; case '\b': row = (p_con->cursor - p_con->original_addr) / SCREEN_WIDTH; column = p_con->cursor - row * SCREEN_WIDTH; if (column > 4) { p_con->cursor--; *(p_vmem - 2) = ' '; *(p_vmem - 1) = White; } break; case '\t': out_string(p_con, " ", color); break; default: if (p_con->cursor < p_con->original_addr + p_con->v_mem_limit - 1) { *p_vmem++ = ch; *p_vmem++ = color; p_con->cursor++; } break; } while (p_con->cursor >= p_con->current_start_addr + SCREEN_SIZE) { scroll_screen(p_con, SCR_DN); } if (p_con == console_table + nr_current_console){ flush(p_con); } }
void BStringColumn::DrawField(BField* _field, BRect rect, BView* parent) { float width = rect.Width() - (2 * kTEXT_MARGIN); BStringField* field = static_cast<BStringField*>(_field); float fieldWidth = field->Width(); bool updateNeeded = width != fieldWidth; if (updateNeeded) { BString out_string(field->String()); float preferredWidth = parent->StringWidth(out_string.String()); if (width < preferredWidth) { parent->TruncateString(&out_string, fTruncate, width + 2); field->SetClippedString(out_string.String()); } else field->SetClippedString(""); field->SetWidth(width); } DrawString(field->HasClippedString() ? field->ClippedString() : field->String(), parent, rect); }
/* We get here after reading the value in set/add/replace * commands. The command has been stored in c->cmd, and * the item is ready in c->item. */ void cproxy_process_upstream_ascii_nread(conn *c) { assert(c != NULL); assert(c->next == NULL); item *it = c->item; assert(it != NULL); // pthread_mutex_lock(&c->thread->stats.mutex); // c->thread->stats.slab_stats[it->slabs_clsid].set_cmds++; // pthread_mutex_unlock(&c->thread->stats.mutex); if (strncmp(ITEM_data(it) + it->nbytes - 2, "\r\n", 2) == 0) { proxy_td *ptd = c->extra; assert(ptd != NULL); cproxy_pause_upstream_for_downstream(ptd, c); } else { out_string(c, "CLIENT_ERROR bad data chunk"); } }
/* 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 out_move_callback(__ a, ___ b, ___ c, ___ d) { out_string(b, **a); }
/* Used for broadcast commands, like flush_all or stats. */ bool cproxy_broadcast_a2a_downstream(downstream *d, char *command, conn *uc, char *suffix) { assert(d != NULL); assert(d->ptd != NULL); assert(d->ptd->proxy != NULL); assert(d->downstream_conns != NULL); assert(d->downstream_used_start == 0); assert(d->downstream_used == 0); assert(command != NULL); assert(uc != NULL); assert(uc->next == NULL); assert(uc->item == NULL); int nwrite = 0; int nconns = mcs_server_count(&d->mst); for (int i = 0; i < nconns; i++) { conn *c = d->downstream_conns[i]; if (c != NULL && c != NULL_CONN) { if (cproxy_prep_conn_for_write(c)) { assert(c->state == conn_pause); out_string(c, command); if (update_event(c, EV_WRITE | EV_PERSIST)) { nwrite++; if (uc->noreply) { c->write_and_go = conn_pause; } } else { if (settings.verbose > 1) { moxi_log_write("Update cproxy write event failed\n"); } d->ptd->stats.stats.err_oom++; cproxy_close_conn(c); } } else { d->ptd->stats.stats.err_downstream_write_prep++; cproxy_close_conn(c); } } } if (settings.verbose > 1) { moxi_log_write("%d: a2a broadcast nwrite %d out of %d\n", uc->sfd, nwrite, nconns); } if (nwrite > 0) { d->downstream_used_start = nwrite; d->downstream_used = nwrite; if (cproxy_dettach_if_noreply(d, uc) == false) { d->upstream_suffix = suffix; d->upstream_suffix_len = 0; d->upstream_status = PROTOCOL_BINARY_RESPONSE_SUCCESS; d->upstream_retry = 0; d->target_host_ident = NULL; cproxy_start_downstream_timeout(d, NULL); } else { // TODO: Handle flush_all's expiration parameter against // the front_cache. // if (strncmp(command, "flush_all", 9) == 0) { mcache_flush_all(&d->ptd->proxy->front_cache, 0); } } return true; } return false; }
void process_stat(conn *c, char *command) { time_t now = time(0); if (strcmp(command, "stats") == 0) { char temp[512]; /* we report curr_conns - 1, because one conn is the listening one */ sprintf(temp, "STAT curr_items %u\r\nSTAT total_items %u\r\nSTAT bytes %llu\r\nSTAT curr_connections %u\r\nSTAT total_connections %u\r\nSTAT connection_structures %u\r\nSTAT age %u\r\nSTAT cmd_get %u\r\nSTAT cmd_set %u\r\nSTAT get_hits %u\r\nSTAT get_misses %u\r\nSTAT bytes_read %llu\r\nSTAT bytes_written %llu\r\nSTAT limit_maxbytes %u\r\nSTAT limit_maxitems %u\r\nEND", stats.curr_items, stats.total_items, stats.curr_bytes, stats.curr_conns - 1, stats.total_conns, stats.conn_structs, (items_tail ? now - items_tail->time : 0), stats.get_cmds, stats.set_cmds, stats.get_hits, stats.get_misses, stats.bytes_read, stats.bytes_written, settings.maxbytes, settings.maxitems); out_string(c, temp); return; } if (strcmp(command, "stats reset") == 0) { stats_reset(); out_string(c, "RESET"); } if (strncmp(command, "stats cachedump", 15) == 0) { char *start = command + 15; int limit = 0; int memlimit = 2*1024*1024; char *buffer; int bufcurr; item *it = items_head; int bytes = 0; int len; int shown = 0; char temp[256]; limit = atoi(start); buffer = malloc(memlimit); if (buffer == 0) { out_string(c, "SERVER_ERROR out of memory"); return; } bufcurr = 0; while(1) { if(limit && shown >=limit) break; if (!it) break; sprintf(temp, "ITEM %s [%u b; %u s]\r\n", it->key, it->nbytes - 2, it->time); len = strlen(temp); if (bufcurr + len +5 > memlimit) /* 5 is END\r\n */ break; strcpy(buffer + bufcurr, temp); bufcurr+=len; shown++; it = it->next; } strcpy(buffer+bufcurr, "END\r\n"); bufcurr+=5; c->write_and_free = buffer; c->wcurr = buffer; c->wbytes = bufcurr; c->state = conn_write; return; } }
void process_command(conn *c, char *command) { int comm = 0; /* * for commands set/add/replace, we build an item and read the data * directly into it, then continue in nread_complete(). */ if ((strncmp(command, "add ", 4) == 0 && (comm = NREAD_ADD)) || (strncmp(command, "set ", 4) == 0 && (comm = NREAD_SET)) || (strncmp(command, "replace ", 8) == 0 && (comm = NREAD_REPLACE))) { char s_comm[10]; char key[256]; int flags; time_t expire; int len, res; item *it; res = sscanf(command, "%s %s %u %u %d\n", s_comm, key, &flags, &expire, &len); if (res!=5 || strlen(key)==0 ) { out_string(c, "CLIENT_ERROR bad command line format"); return; } it = item_alloc(key, flags, expire, len+2); if (it == 0) { out_string(c, "SERVER_ERROR out of memory"); c->write_and_close = 1; return; } c->item_comm = comm; c->item = it; c->rcurr = it->data; c->rlbytes = it->nbytes; c->state = conn_nread; return; } if (strncmp(command, "get ", 4) == 0) { char *start = command + 4; char key[256]; int next; int i = 0; item *it; time_t now = time(0); while(sscanf(start, " %s%n", key, &next) >= 1) { start+=next; stats.get_cmds++; it = (item *)assoc_find(key); if (it && (it->it_flags & ITEM_DELETED)) { it = 0; } if (it && it->exptime && it->exptime < now) { item_unlink(it); it = 0; } if (it) { stats.get_hits++; it->usecount++; item_update(it); *(c->ilist + i) = it; i++; if (i > c->isize) { c->isize *= 2; c->ilist = realloc(c->ilist, sizeof(item *)*c->isize); } } else stats.get_misses++; } c->icurr = c->ilist; c->ileft = i; if (c->ileft) { c->ipart = 0; c->state = conn_mwrite; c->ibytes = 0; return; } else { out_string(c, "END"); return; } } if (strncmp(command, "delete ", 7) == 0) { char key [256]; char *start = command+7; item *it; sscanf(start, " %s", key); it = assoc_find(key); if (!it) { out_string(c, "NOT_FOUND"); return; } else { it->usecount++; /* use its expiration time as its deletion time now */ it->exptime = time(0) + 4; it->it_flags |= ITEM_DELETED; todelete[delcurr++] = it; if (delcurr >= deltotal) { deltotal *= 2; todelete = realloc(todelete, sizeof(item *)*deltotal); } } out_string(c, "DELETED"); return; } if (strncmp(command, "stats", 5) == 0) { process_stat(c, command); return; } if (strcmp(command, "version") == 0) { out_string(c, "VERSION 2.0"); return; } out_string(c, "ERROR"); return; }
static void send_file_encrypted_end (struct tgl_state *TLS, struct send_file *f, void *callback, void *callback_extra) { out_int (CODE_messages_send_encrypted_file); out_int (CODE_input_encrypted_chat); out_int (tgl_get_peer_id (f->to_id)); tgl_peer_t *P = tgl_peer_get (TLS, f->to_id); assert (P); out_long (P->encr_chat.access_hash); long long r; tglt_secure_random (&r, 8); out_long (r); encr_start (); out_int (CODE_decrypted_message_layer); out_random (15 + 4 * (lrand48 () % 3)); out_int (TGL_ENCRYPTED_LAYER); out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != TLS->our_id)); out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == TLS->our_id)); out_int (CODE_decrypted_message); out_long (r); out_int (P->encr_chat.ttl); out_string (""); int *save_ptr = packet_ptr; if (f->flags == -1) { out_int (CODE_decrypted_message_media_photo); } else if ((f->flags & TGLDF_VIDEO)) { out_int (CODE_decrypted_message_media_video); } else if ((f->flags & TGLDF_AUDIO)) { out_int (CODE_decrypted_message_media_audio); } else { out_int (CODE_decrypted_message_media_document); } if (f->flags == -1 || !(f->flags & TGLDF_AUDIO)) { out_cstring ("", 0); out_int (90); out_int (90); } if (f->flags == -1) { out_int (f->w); out_int (f->h); } else if (f->flags & TGLDF_VIDEO) { out_int (f->duration); out_string (tg_mime_by_filename (f->file_name)); out_int (f->w); out_int (f->h); } else if (f->flags & TGLDF_AUDIO) { out_int (f->duration); out_string (tg_mime_by_filename (f->file_name)); } else { out_string (""); out_string (tg_mime_by_filename (f->file_name)); // document } out_int (f->size); out_cstring ((void *)f->key, 32); out_cstring ((void *)f->init_iv, 32); int *save_in_ptr = in_ptr; int *save_in_end = in_end; in_ptr = save_ptr; in_end = packet_ptr; assert (skip_type_any (TYPE_TO_PARAM(decrypted_message_media)) >= 0); assert (in_ptr == in_end); in_ptr = save_ptr; in_end = packet_ptr; struct tl_ds_decrypted_message_media *DS_DMM = fetch_ds_type_decrypted_message_media (TYPE_TO_PARAM (decrypted_message_media)); in_end = save_in_ptr; in_ptr = save_in_end; int peer_type = tgl_get_peer_type (f->to_id); int peer_id = tgl_get_peer_id (f->to_id); int date = time (NULL); encr_finish (&P->encr_chat); if (f->size < (16 << 20)) { out_int (CODE_input_encrypted_file_uploaded); } else { out_int (CODE_input_encrypted_file_big_uploaded); } out_long (f->id); out_int (f->part_num); if (f->size < (16 << 20)) { out_string (""); } unsigned char md5[16]; unsigned char str[64]; memcpy (str, f->key, 32); memcpy (str + 32, f->init_iv, 32); MD5 (str, 64, md5); out_int ((*(int *)md5) ^ (*(int *)(md5 + 4))); tfree_secure (f->iv, 32); bl_do_create_message_encr_new (TLS, r, &TLS->our_id, &peer_type, &peer_id, &date, NULL, 0, DS_DMM, NULL, NULL, TGLMF_OUT | TGLMF_UNREAD | TGLMF_ENCRYPTED | TGLMF_CREATE | TGLMF_CREATED); free_ds_type_decrypted_message_media (DS_DMM, TYPE_TO_PARAM (decrypted_message_media)); struct tgl_message *M = tgl_message_get (TLS, r); assert (M); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_file_methods, M, callback, callback_extra); tfree_str (f->file_name); tfree (f, sizeof (*f)); }
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_stat(conn *c, char *command) { time_t now = time(0); if (strcmp(command, "stats") == 0) { char temp[1024]; pid_t pid = getpid(); char *pos = temp; struct rusage usage; getrusage(RUSAGE_SELF, &usage); pos += sprintf(pos, "STAT pid %u\r\n", pid); pos += sprintf(pos, "STAT uptime %lu\r\n", now - stats.started); pos += sprintf(pos, "STAT time %ld\r\n", now); pos += sprintf(pos, "STAT version " VERSION "\r\n"); pos += sprintf(pos, "STAT rusage_user %ld.%06ld\r\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec); pos += sprintf(pos, "STAT rusage_system %ld.%06ld\r\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec); pos += sprintf(pos, "STAT curr_items %u\r\n", stats.curr_items); pos += sprintf(pos, "STAT total_items %u\r\n", stats.total_items); pos += sprintf(pos, "STAT bytes %llu\r\n", stats.curr_bytes); pos += sprintf(pos, "STAT curr_connections %u\r\n", stats.curr_conns - 1); /* ignore listening conn */ pos += sprintf(pos, "STAT total_connections %u\r\n", stats.total_conns); pos += sprintf(pos, "STAT connection_structures %u\r\n", stats.conn_structs); pos += sprintf(pos, "STAT cmd_get %u\r\n", stats.get_cmds); pos += sprintf(pos, "STAT cmd_set %u\r\n", stats.set_cmds); pos += sprintf(pos, "STAT get_hits %u\r\n", stats.get_hits); pos += sprintf(pos, "STAT get_misses %u\r\n", stats.get_misses); pos += sprintf(pos, "STAT bytes_read %llu\r\n", stats.bytes_read); pos += sprintf(pos, "STAT bytes_written %llu\r\n", stats.bytes_written); pos += sprintf(pos, "STAT limit_maxbytes %u\r\n", settings.maxbytes); pos += sprintf(pos, "END"); out_string(c, temp); return; } if (strcmp(command, "stats reset") == 0) { stats_reset(); out_string(c, "RESET"); return; } #ifdef HAVE_MALLOC_H #ifdef HAVE_STRUCT_MALLINFO if (strcmp(command, "stats malloc") == 0) { char temp[512]; struct mallinfo info; char *pos = temp; info = mallinfo(); pos += sprintf(pos, "STAT arena_size %d\r\n", info.arena); pos += sprintf(pos, "STAT free_chunks %d\r\n", info.ordblks); pos += sprintf(pos, "STAT fastbin_blocks %d\r\n", info.smblks); pos += sprintf(pos, "STAT mmapped_regions %d\r\n", info.hblks); pos += sprintf(pos, "STAT mmapped_space %d\r\n", info.hblkhd); pos += sprintf(pos, "STAT max_total_alloc %d\r\n", info.usmblks); pos += sprintf(pos, "STAT fastbin_space %d\r\n", info.fsmblks); pos += sprintf(pos, "STAT total_alloc %d\r\n", info.uordblks); pos += sprintf(pos, "STAT total_free %d\r\n", info.fordblks); pos += sprintf(pos, "STAT releasable_space %d\r\nEND", info.keepcost); out_string(c, temp); return; } #endif /* HAVE_STRUCT_MALLINFO */ #endif /* HAVE_MALLOC_H */ if (strcmp(command, "stats maps") == 0) { char *wbuf; int wsize = 8192; /* should be enough */ int fd; int res; wbuf = (char *)malloc(wsize); if (wbuf == 0) { out_string(c, "SERVER_ERROR out of memory"); return; } fd = open("/proc/self/maps", O_RDONLY); if (fd == -1) { out_string(c, "SERVER_ERROR cannot open the maps file"); free(wbuf); return; } res = read(fd, wbuf, wsize - 6); /* 6 = END\r\n\0 */ if (res == wsize - 6) { out_string(c, "SERVER_ERROR buffer overflow"); free(wbuf); close(fd); return; } if (res == 0 || res == -1) { out_string(c, "SERVER_ERROR can't read the maps file"); free(wbuf); close(fd); return; } strcpy(wbuf + res, "END\r\n"); c->write_and_free=wbuf; c->wcurr=wbuf; c->wbytes = res + 6; c->state = conn_write; c->write_and_go = conn_read; close(fd); return; } if (strncmp(command, "stats cachedump", 15) == 0) { char *buf; unsigned int bytes, id, limit = 0; char *start = command + 15; if (sscanf(start, "%u %u\r\n", &id, &limit) < 1) { out_string(c, "CLIENT_ERROR bad command line"); return; } buf = item_cachedump(id, limit, &bytes); if (buf == 0) { out_string(c, "SERVER_ERROR out of memory"); return; } c->write_and_free = buf; c->wcurr = buf; c->wbytes = bytes; c->state = conn_write; c->write_and_go = conn_read; return; } if (strcmp(command, "stats slabs")==0) { int bytes = 0; char *buf = slabs_stats(&bytes); if (!buf) { out_string(c, "SERVER_ERROR out of memory"); return; } c->write_and_free = buf; c->wcurr = buf; c->wbytes = bytes; c->state = conn_write; c->write_and_go = conn_read; return; } if (strcmp(command, "stats items")==0) { char buffer[4096]; item_stats(buffer, 4096); out_string(c, buffer); return; } if (strcmp(command, "stats sizes")==0) { int bytes = 0; char *buf = item_stats_sizes(&bytes); if (! buf) { out_string(c, "SERVER_ERROR out of memory"); return; } c->write_and_free = buf; c->wcurr = buf; c->wbytes = bytes; c->state = conn_write; c->write_and_go = conn_read; return; } out_string(c, "ERROR"); }
void process_command(conn *c, char *command) { int comm = 0; int incr = 0; /* * for commands set/add/replace, we build an item and read the data * directly into it, then continue in nread_complete(). */ if (settings.verbose > 1) fprintf(stderr, "<%d %s\n", c->sfd, command); /* All incoming commands will require a response, so we cork at the beginning, and uncork at the very end (usually by means of out_string) */ set_cork(c, 1); if ((strncmp(command, "add ", 4) == 0 && (comm = NREAD_ADD)) || (strncmp(command, "set ", 4) == 0 && (comm = NREAD_SET)) || (strncmp(command, "replace ", 8) == 0 && (comm = NREAD_REPLACE))) { char key[251]; int flags; time_t expire; int len, res; item *it; res = sscanf(command, "%*s %250s %u %ld %d\n", key, &flags, &expire, &len); if (res!=4 || strlen(key)==0 ) { out_string(c, "CLIENT_ERROR bad command line format"); return; } expire = realtime(expire); it = item_alloc(key, flags, expire, len+2); if (it == 0) { out_string(c, "SERVER_ERROR out of memory"); /* swallow the data line */ c->write_and_go = conn_swallow; c->sbytes = len+2; return; } c->item_comm = comm; c->item = it; c->rcurr = ITEM_data(it); c->rlbytes = it->nbytes; c->state = conn_nread; return; } if ((strncmp(command, "incr ", 5) == 0 && (incr = 1)) || (strncmp(command, "decr ", 5) == 0)) { char temp[32]; unsigned int value; item *it; unsigned int delta; char key[251]; int res; char *ptr; time_t now = time(0); res = sscanf(command, "%*s %250s %u\n", key, &delta); if (res!=2 || strlen(key)==0 ) { out_string(c, "CLIENT_ERROR bad command line format"); return; } it = assoc_find(key); if (it && (it->it_flags & ITEM_DELETED)) { it = 0; } if (it && it->exptime && it->exptime < now) { item_unlink(it); it = 0; } if (!it) { out_string(c, "NOT_FOUND"); return; } ptr = ITEM_data(it); while (*ptr && (*ptr<'0' && *ptr>'9')) ptr++; value = atoi(ptr); if (incr) value+=delta; else { if (delta >= value) value = 0; else value-=delta; } sprintf(temp, "%u", value); res = strlen(temp); if (res + 2 > it->nbytes) { /* need to realloc */ item *new_it; new_it = item_alloc(ITEM_key(it), it->flags, it->exptime, res + 2 ); if (new_it == 0) { out_string(c, "SERVER_ERROR out of memory"); return; } memcpy(ITEM_data(new_it), temp, res); memcpy(ITEM_data(new_it) + res, "\r\n", 2); item_replace(it, new_it); } else { /* replace in-place */ memcpy(ITEM_data(it), temp, res); memset(ITEM_data(it) + res, ' ', it->nbytes-res-2); } out_string(c, temp); return; } if (strncmp(command, "get ", 4) == 0) { char *start = command + 4; char key[251]; int next; int i = 0; item *it; time_t now = time(0); while(sscanf(start, " %250s%n", key, &next) >= 1) { start+=next; stats.get_cmds++; it = assoc_find(key); if (it && (it->it_flags & ITEM_DELETED)) { it = 0; } if (settings.oldest_live && it && it->time <= settings.oldest_live) { item_unlink(it); it = 0; } if (it && it->exptime && it->exptime < now) { item_unlink(it); it = 0; } if (it) { if (i >= c->isize) { item **new_list = realloc(c->ilist, sizeof(item *)*c->isize*2); if (new_list) { c->isize *= 2; c->ilist = new_list; } else break; } stats.get_hits++; it->refcount++; item_update(it); *(c->ilist + i) = it; i++; } else stats.get_misses++; } c->icurr = c->ilist; c->ileft = i; if (c->ileft) { c->ipart = 0; c->state = conn_mwrite; c->ibytes = 0; return; } else { out_string(c, "END"); return; } } if (strncmp(command, "delete ", 7) == 0) { char key[251]; item *it; int res; time_t exptime = 0; res = sscanf(command, "%*s %250s %ld", key, &exptime); it = assoc_find(key); if (!it) { out_string(c, "NOT_FOUND"); return; } if (exptime == 0) { item_unlink(it); out_string(c, "DELETED"); return; } if (delcurr >= deltotal) { item **new_delete = realloc(todelete, sizeof(item *) * deltotal * 2); if (new_delete) { todelete = new_delete; deltotal *= 2; } else { /* * can't delete it immediately, user wants a delay, * but we ran out of memory for the delete queue */ out_string(c, "SERVER_ERROR out of memory"); return; } } exptime = realtime(exptime); it->refcount++; /* use its expiration time as its deletion time now */ it->exptime = exptime; it->it_flags |= ITEM_DELETED; todelete[delcurr++] = it; out_string(c, "DELETED"); return; } if (strncmp(command, "stats", 5) == 0) { process_stat(c, command); return; } if (strcmp(command, "flush_all") == 0) { settings.oldest_live = time(0); out_string(c, "OK"); return; } if (strcmp(command, "version") == 0) { out_string(c, "VERSION " VERSION); return; } if (strcmp(command, "quit") == 0) { c->state = conn_closing; return; } if (strncmp(command, "slabs reassign ", 15) == 0) { int src, dst; char *start = command+15; if (sscanf(start, "%u %u\r\n", &src, &dst) == 2) { int rv = slabs_reassign(src, dst); if (rv == 1) { out_string(c, "DONE"); return; } if (rv == 0) { out_string(c, "CANT"); return; } if (rv == -1) { out_string(c, "BUSY"); return; } } out_string(c, "CLIENT_ERROR bogus command"); return; } out_string(c, "ERROR"); return; }
/* 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 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); } } }
void drive_machine(conn *c) { int exit = 0; int sfd, flags = 1; socklen_t addrlen; struct sockaddr addr; conn *newc; int res; while (!exit) { /* printf("state %d\n", c->state);*/ switch(c->state) { case conn_listening: addrlen = sizeof(addr); if ((sfd = accept(c->sfd, &addr, &addrlen)) == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { exit = 1; break; } else { perror("accept()"); } break; } if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 || fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) { perror("setting O_NONBLOCK"); close(sfd); break; } newc = conn_new(sfd, conn_read, EV_READ | EV_PERSIST); if (!newc) { if (settings.verbose > 0) fprintf(stderr, "couldn't create new connection\n"); close(sfd); break; } break; case conn_read: if (try_read_command(c)) { continue; } if (try_read_network(c)) { continue; } /* we have no command line and no data to read from network */ if (!update_event(c, EV_READ | EV_PERSIST)) { if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; } exit = 1; break; case conn_nread: /* we are reading rlbytes into rcurr; */ if (c->rlbytes == 0) { complete_nread(c); break; } /* first check if we have leftovers in the conn_read buffer */ if (c->rbytes > 0) { int tocopy = c->rbytes > c->rlbytes ? c->rlbytes : c->rbytes; memcpy(c->rcurr, c->rbuf, tocopy); c->rcurr += tocopy; c->rlbytes -= tocopy; if (c->rbytes > tocopy) { memmove(c->rbuf, c->rbuf+tocopy, c->rbytes - tocopy); } c->rbytes -= tocopy; break; } /* now try reading from the socket */ res = read(c->sfd, c->rcurr, c->rlbytes); if (res > 0) { stats.bytes_read += res; c->rcurr += res; c->rlbytes -= res; break; } if (res == 0) { /* end of stream */ c->state = conn_closing; break; } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_READ | EV_PERSIST)) { if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; } exit = 1; break; } /* otherwise we have a real error, on which we close the connection */ if (settings.verbose > 0) fprintf(stderr, "Failed to read, and not due to blocking\n"); c->state = conn_closing; break; case conn_swallow: /* we are reading sbytes and throwing them away */ if (c->sbytes == 0) { c->state = conn_read; break; } /* first check if we have leftovers in the conn_read buffer */ if (c->rbytes > 0) { int tocopy = c->rbytes > c->sbytes ? c->sbytes : c->rbytes; c->sbytes -= tocopy; if (c->rbytes > tocopy) { memmove(c->rbuf, c->rbuf+tocopy, c->rbytes - tocopy); } c->rbytes -= tocopy; break; } /* now try reading from the socket */ res = read(c->sfd, c->rbuf, c->rsize > c->sbytes ? c->sbytes : c->rsize); if (res > 0) { stats.bytes_read += res; c->sbytes -= res; break; } if (res == 0) { /* end of stream */ c->state = conn_closing; break; } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_READ | EV_PERSIST)) { if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; } exit = 1; break; } /* otherwise we have a real error, on which we close the connection */ if (settings.verbose > 0) fprintf(stderr, "Failed to read, and not due to blocking\n"); c->state = conn_closing; break; case conn_write: /* we are writing wbytes bytes starting from wcurr */ if (c->wbytes == 0) { if (c->write_and_free) { free(c->write_and_free); c->write_and_free = 0; } c->state = c->write_and_go; if (c->state == conn_read) set_cork(c, 0); break; } res = write(c->sfd, c->wcurr, c->wbytes); if (res > 0) { stats.bytes_written += res; c->wcurr += res; c->wbytes -= res; break; } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_WRITE | EV_PERSIST)) { if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; } exit = 1; break; } /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK, we have a real error, on which we close the connection */ if (settings.verbose > 0) fprintf(stderr, "Failed to write, and not due to blocking\n"); c->state = conn_closing; break; case conn_mwrite: /* * we're writing ibytes bytes from iptr. iptr alternates between * ibuf, where we build a string "VALUE...", and ITEM_data(it) for the * current item. When we finish a chunk, we choose the next one using * ipart, which has the following semantics: 0 - start the loop, 1 - * we finished ibuf, go to current ITEM_data(it); 2 - we finished ITEM_data(it), * move to the next item and build its ibuf; 3 - we finished all items, * write "END". */ if (c->ibytes > 0) { res = write(c->sfd, c->iptr, c->ibytes); if (res > 0) { stats.bytes_written += res; c->iptr += res; c->ibytes -= res; break; } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_WRITE | EV_PERSIST)) { if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; } exit = 1; break; } /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK, we have a real error, on which we close the connection */ if (settings.verbose > 0) fprintf(stderr, "Failed to write, and not due to blocking\n"); c->state = conn_closing; break; } else { item *it; /* we finished a chunk, decide what to do next */ switch (c->ipart) { case 1: it = *(c->icurr); assert((it->it_flags & ITEM_SLABBED) == 0); c->iptr = ITEM_data(it); c->ibytes = it->nbytes; c->ipart = 2; break; case 2: it = *(c->icurr); item_remove(it); c->ileft--; if (c->ileft <= 0) { c->ipart = 3; break; } else { c->icurr++; } /* FALL THROUGH */ case 0: it = *(c->icurr); assert((it->it_flags & ITEM_SLABBED) == 0); c->ibytes = sprintf(c->ibuf, "VALUE %s %u %u\r\n", ITEM_key(it), it->flags, it->nbytes - 2); if (settings.verbose > 1) fprintf(stderr, ">%d sending key %s\n", c->sfd, ITEM_key(it)); c->iptr = c->ibuf; c->ipart = 1; break; case 3: out_string(c, "END"); break; } } break; case conn_closing: conn_close(c); exit = 1; break; } } return; }
/* Used for broadcast commands, like flush_all or stats. */ bool cproxy_broadcast_a2a_downstream(downstream *d, char *command, conn *uc, char *suffix) { 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->next == NULL); assert(uc->item == NULL); int nwrite = 0; int nconns = memcached_server_count(&d->mst); for (int i = 0; i < nconns; i++) { conn *c = d->downstream_conns[i]; if (c != NULL) { if (cproxy_prep_conn_for_write(c)) { assert(c->state == conn_pause); out_string(c, command); if (update_event(c, EV_WRITE | EV_PERSIST)) { nwrite++; if (uc->noreply) { c->write_and_go = conn_pause; } } else { if (settings.verbose > 1) fprintf(stderr, "Update cproxy write event failed\n"); d->ptd->stats.stats.err_oom++; cproxy_close_conn(c); } } else { d->ptd->stats.stats.err_downstream_write_prep++; cproxy_close_conn(c); } } } if (settings.verbose > 1) fprintf(stderr, "forward multiget nwrite %d out of %d\n", nwrite, nconns); d->downstream_used_start = nwrite; d->downstream_used = nwrite; if (cproxy_dettach_if_noreply(d, uc) == false) { d->upstream_suffix = suffix; cproxy_start_downstream_timeout(d, NULL); } else { // TODO: Handle flush_all's expiration parameter against // the front_cache. // if (strncmp(command, "flush_all", 9) == 0) { mcache_flush_all(&d->ptd->proxy->front_cache, 0); } } return nwrite > 0; }
main():Object { out_string("Hey\n") }; };