1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Functions for handling the binary protocol.
4 * NOTE: The binary protocol is deprecated as of 1.6.0.
5 */
6
7 #include "memcached.h"
8 #include "proto_bin.h"
9 #include "storage.h"
10 #ifdef TLS
11 #include "tls.h"
12 #endif
13 #include <string.h>
14 #include <stdlib.h>
15
16 /** binprot handlers **/
17 static void process_bin_flush(conn *c, char *extbuf);
18 static void process_bin_append_prepend(conn *c);
19 static void process_bin_update(conn *c, char *extbuf);
20 static void process_bin_get_or_touch(conn *c, char *extbuf);
21 static void process_bin_delete(conn *c);
22 static void complete_incr_bin(conn *c, char *extbuf);
23 static void process_bin_stat(conn *c);
24 static void process_bin_sasl_auth(conn *c);
25 static void dispatch_bin_command(conn *c, char *extbuf);
26 static void complete_update_bin(conn *c);
27 static void process_bin_complete_sasl_auth(conn *c);
28
29 static void write_bin_miss_response(conn *c, char *key, size_t nkey);
30
complete_nread_binary(conn * c)31 void complete_nread_binary(conn *c) {
32 assert(c != NULL);
33 assert(c->cmd >= 0);
34
35 switch(c->substate) {
36 case bin_read_set_value:
37 complete_update_bin(c);
38 break;
39 case bin_reading_sasl_auth_data:
40 process_bin_complete_sasl_auth(c);
41 if (c->item) {
42 do_item_remove(c->item);
43 c->item = NULL;
44 }
45 break;
46 default:
47 fprintf(stderr, "Not handling substate %d\n", c->substate);
48 assert(0);
49 }
50 }
51
try_read_command_binary(conn * c)52 int try_read_command_binary(conn *c) {
53 /* Do we have the complete packet header? */
54 if (c->rbytes < sizeof(c->binary_header)) {
55 /* need more data! */
56 return 0;
57 } else {
58 memcpy(&c->binary_header, c->rcurr, sizeof(c->binary_header));
59 protocol_binary_request_header* req;
60 req = &c->binary_header;
61
62 if (settings.verbose > 1) {
63 /* Dump the packet before we convert it to host order */
64 int ii;
65 fprintf(stderr, "<%d Read binary protocol data:", c->sfd);
66 for (ii = 0; ii < sizeof(req->bytes); ++ii) {
67 if (ii % 4 == 0) {
68 fprintf(stderr, "\n<%d ", c->sfd);
69 }
70 fprintf(stderr, " 0x%02x", req->bytes[ii]);
71 }
72 fprintf(stderr, "\n");
73 }
74
75 c->binary_header = *req;
76 c->binary_header.request.keylen = ntohs(req->request.keylen);
77 c->binary_header.request.bodylen = ntohl(req->request.bodylen);
78 c->binary_header.request.cas = ntohll(req->request.cas);
79
80 if (c->binary_header.request.magic != PROTOCOL_BINARY_REQ) {
81 if (settings.verbose) {
82 fprintf(stderr, "Invalid magic: %x\n",
83 c->binary_header.request.magic);
84 }
85 conn_set_state(c, conn_closing);
86 return -1;
87 }
88
89 uint8_t extlen = c->binary_header.request.extlen;
90 uint16_t keylen = c->binary_header.request.keylen;
91 if (c->rbytes < keylen + extlen + sizeof(c->binary_header)) {
92 // Still need more bytes. Let try_read_network() realign the
93 // read-buffer and fetch more data as necessary.
94 return 0;
95 }
96
97 if (!resp_start(c)) {
98 conn_set_state(c, conn_closing);
99 return -1;
100 }
101
102 c->cmd = c->binary_header.request.opcode;
103 c->keylen = c->binary_header.request.keylen;
104 c->opaque = c->binary_header.request.opaque;
105 /* clear the returned cas value */
106 c->cas = 0;
107
108 c->last_cmd_time = current_time;
109 // sigh. binprot has no "largest possible extlen" define, and I don't
110 // want to refactor a ton of code either. Header is only ever used out
111 // of c->binary_header, but the extlen stuff is used for the latter
112 // bytes. Just wastes 24 bytes on the stack this way.
113 char extbuf[sizeof(c->binary_header) + BIN_MAX_EXTLEN+1];
114 memcpy(extbuf + sizeof(c->binary_header), c->rcurr + sizeof(c->binary_header),
115 extlen > BIN_MAX_EXTLEN ? BIN_MAX_EXTLEN : extlen);
116 c->rbytes -= sizeof(c->binary_header) + extlen + keylen;
117 c->rcurr += sizeof(c->binary_header) + extlen + keylen;
118
119 dispatch_bin_command(c, extbuf);
120 }
121
122 return 1;
123 }
124
125 /**
126 * get a pointer to the key in this request
127 */
binary_get_key(conn * c)128 static char* binary_get_key(conn *c) {
129 return c->rcurr - (c->binary_header.request.keylen);
130 }
131
add_bin_header(conn * c,uint16_t err,uint8_t hdr_len,uint16_t key_len,uint32_t body_len)132 static void add_bin_header(conn *c, uint16_t err, uint8_t hdr_len, uint16_t key_len, uint32_t body_len) {
133 protocol_binary_response_header* header;
134 mc_resp *resp = c->resp;
135
136 assert(c);
137
138 resp_reset(resp);
139
140 header = (protocol_binary_response_header *)resp->wbuf;
141
142 header->response.magic = (uint8_t)PROTOCOL_BINARY_RES;
143 header->response.opcode = c->binary_header.request.opcode;
144 header->response.keylen = (uint16_t)htons(key_len);
145
146 header->response.extlen = (uint8_t)hdr_len;
147 header->response.datatype = (uint8_t)PROTOCOL_BINARY_RAW_BYTES;
148 header->response.status = (uint16_t)htons(err);
149
150 header->response.bodylen = htonl(body_len);
151 header->response.opaque = c->opaque;
152 header->response.cas = htonll(c->cas);
153
154 if (settings.verbose > 1) {
155 int ii;
156 fprintf(stderr, ">%d Writing bin response:", c->sfd);
157 for (ii = 0; ii < sizeof(header->bytes); ++ii) {
158 if (ii % 4 == 0) {
159 fprintf(stderr, "\n>%d ", c->sfd);
160 }
161 fprintf(stderr, " 0x%02x", header->bytes[ii]);
162 }
163 fprintf(stderr, "\n");
164 }
165
166 resp->wbytes = sizeof(header->response);
167 resp_add_iov(resp, resp->wbuf, resp->wbytes);
168 }
169
170
171 /**
172 * Writes a binary error response. If errstr is supplied, it is used as the
173 * error text; otherwise a generic description of the error status code is
174 * included.
175 */
write_bin_error(conn * c,protocol_binary_response_status err,const char * errstr,int swallow)176 void write_bin_error(conn *c, protocol_binary_response_status err,
177 const char *errstr, int swallow) {
178 size_t len;
179
180 if (!errstr) {
181 switch (err) {
182 case PROTOCOL_BINARY_RESPONSE_ENOMEM:
183 errstr = "Out of memory";
184 break;
185 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
186 errstr = "Unknown command";
187 break;
188 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
189 errstr = "Not found";
190 break;
191 case PROTOCOL_BINARY_RESPONSE_EINVAL:
192 errstr = "Invalid arguments";
193 break;
194 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
195 errstr = "Data exists for key.";
196 break;
197 case PROTOCOL_BINARY_RESPONSE_E2BIG:
198 errstr = "Too large.";
199 break;
200 case PROTOCOL_BINARY_RESPONSE_DELTA_BADVAL:
201 errstr = "Non-numeric server-side value for incr or decr";
202 break;
203 case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
204 errstr = "Not stored.";
205 break;
206 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR:
207 errstr = "Auth failure.";
208 break;
209 default:
210 assert(false);
211 errstr = "UNHANDLED ERROR";
212 fprintf(stderr, ">%d UNHANDLED ERROR: %d\n", c->sfd, err);
213 }
214 }
215
216 if (settings.verbose > 1) {
217 fprintf(stderr, ">%d Writing an error: %s\n", c->sfd, errstr);
218 }
219
220 len = strlen(errstr);
221 add_bin_header(c, err, 0, 0, len);
222 if (len > 0) {
223 resp_add_iov(c->resp, errstr, len);
224 }
225 if (swallow > 0) {
226 c->sbytes = swallow;
227 conn_set_state(c, conn_swallow);
228 } else {
229 conn_set_state(c, conn_mwrite);
230 }
231 }
232
233 /* Just write an error message and disconnect the client */
handle_binary_protocol_error(conn * c)234 static void handle_binary_protocol_error(conn *c) {
235 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_EINVAL, NULL, 0);
236 if (settings.verbose) {
237 fprintf(stderr, "Protocol error (opcode %02x), close connection %d\n",
238 c->binary_header.request.opcode, c->sfd);
239 }
240 c->close_after_write = true;
241 }
242
243 /* Form and send a response to a command over the binary protocol */
write_bin_response(conn * c,void * d,int hlen,int keylen,int dlen)244 static void write_bin_response(conn *c, void *d, int hlen, int keylen, int dlen) {
245 if (!c->noreply || c->cmd == PROTOCOL_BINARY_CMD_GET ||
246 c->cmd == PROTOCOL_BINARY_CMD_GETK) {
247 add_bin_header(c, 0, hlen, keylen, dlen);
248 mc_resp *resp = c->resp;
249 if (dlen > 0) {
250 resp_add_iov(resp, d, dlen);
251 }
252 }
253
254 conn_set_state(c, conn_new_cmd);
255 }
256
complete_incr_bin(conn * c,char * extbuf)257 static void complete_incr_bin(conn *c, char *extbuf) {
258 item *it;
259 char *key;
260 size_t nkey;
261 /* Weird magic in add_delta forces me to pad here */
262 char tmpbuf[INCR_MAX_STORAGE_LEN];
263 uint64_t cas = 0;
264
265 protocol_binary_response_incr* rsp = (protocol_binary_response_incr*)c->resp->wbuf;
266 protocol_binary_request_incr* req = (void *)extbuf;
267
268 assert(c != NULL);
269 //assert(c->wsize >= sizeof(*rsp));
270
271 /* fix byteorder in the request */
272 req->message.body.delta = ntohll(req->message.body.delta);
273 req->message.body.initial = ntohll(req->message.body.initial);
274 req->message.body.expiration = ntohl(req->message.body.expiration);
275 key = binary_get_key(c);
276 nkey = c->binary_header.request.keylen;
277
278 if (settings.verbose > 1) {
279 int i;
280 fprintf(stderr, "incr ");
281
282 for (i = 0; i < nkey; i++) {
283 fprintf(stderr, "%c", key[i]);
284 }
285 fprintf(stderr, " %lld, %llu, %d\n",
286 (long long)req->message.body.delta,
287 (long long)req->message.body.initial,
288 req->message.body.expiration);
289 }
290
291 if (c->binary_header.request.cas != 0) {
292 cas = c->binary_header.request.cas;
293 }
294 switch(add_delta(c, key, nkey, c->cmd == PROTOCOL_BINARY_CMD_INCREMENT,
295 req->message.body.delta, tmpbuf,
296 &cas)) {
297 case OK:
298 rsp->message.body.value = htonll(strtoull(tmpbuf, NULL, 10));
299 if (cas) {
300 c->cas = cas;
301 }
302 write_bin_response(c, &rsp->message.body, 0, 0,
303 sizeof(rsp->message.body.value));
304 break;
305 case NON_NUMERIC:
306 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_DELTA_BADVAL, NULL, 0);
307 break;
308 case EOM:
309 out_of_memory(c, "SERVER_ERROR Out of memory incrementing value");
310 break;
311 case DELTA_ITEM_NOT_FOUND:
312 if (req->message.body.expiration != 0xffffffff) {
313 /* Save some room for the response */
314 rsp->message.body.value = htonll(req->message.body.initial);
315
316 snprintf(tmpbuf, INCR_MAX_STORAGE_LEN, "%llu",
317 (unsigned long long)req->message.body.initial);
318 int res = strlen(tmpbuf);
319 it = item_alloc(key, nkey, 0, realtime(req->message.body.expiration),
320 res + 2);
321
322 if (it != NULL) {
323 memcpy(ITEM_data(it), tmpbuf, res);
324 memcpy(ITEM_data(it) + res, "\r\n", 2);
325
326 if (store_item(it, NREAD_ADD, c)) {
327 c->cas = ITEM_get_cas(it);
328 write_bin_response(c, &rsp->message.body, 0, 0, sizeof(rsp->message.body.value));
329 } else {
330 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_NOT_STORED,
331 NULL, 0);
332 }
333 item_remove(it); /* release our reference */
334 } else {
335 out_of_memory(c,
336 "SERVER_ERROR Out of memory allocating new item");
337 }
338 } else {
339 pthread_mutex_lock(&c->thread->stats.mutex);
340 if (c->cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
341 c->thread->stats.incr_misses++;
342 } else {
343 c->thread->stats.decr_misses++;
344 }
345 pthread_mutex_unlock(&c->thread->stats.mutex);
346
347 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, NULL, 0);
348 }
349 break;
350 case DELTA_ITEM_CAS_MISMATCH:
351 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, NULL, 0);
352 break;
353 }
354 }
355
complete_update_bin(conn * c)356 static void complete_update_bin(conn *c) {
357 protocol_binary_response_status eno = PROTOCOL_BINARY_RESPONSE_EINVAL;
358 enum store_item_type ret = NOT_STORED;
359 assert(c != NULL);
360
361 item *it = c->item;
362 pthread_mutex_lock(&c->thread->stats.mutex);
363 c->thread->stats.slab_stats[ITEM_clsid(it)].set_cmds++;
364 pthread_mutex_unlock(&c->thread->stats.mutex);
365
366 /* We don't actually receive the trailing two characters in the bin
367 * protocol, so we're going to just set them here */
368 if ((it->it_flags & ITEM_CHUNKED) == 0) {
369 *(ITEM_data(it) + it->nbytes - 2) = '\r';
370 *(ITEM_data(it) + it->nbytes - 1) = '\n';
371 } else {
372 assert(c->ritem);
373 item_chunk *ch = (item_chunk *) c->ritem;
374 if (ch->size == ch->used)
375 ch = ch->next;
376 assert(ch->size - ch->used >= 2);
377 ch->data[ch->used] = '\r';
378 ch->data[ch->used + 1] = '\n';
379 ch->used += 2;
380 }
381
382 ret = store_item(it, c->cmd, c);
383
384 #ifdef ENABLE_DTRACE
385 uint64_t cas = ITEM_get_cas(it);
386 switch (c->cmd) {
387 case NREAD_ADD:
388 MEMCACHED_COMMAND_ADD(c->sfd, ITEM_key(it), it->nkey,
389 (ret == STORED) ? it->nbytes : -1, cas);
390 break;
391 case NREAD_REPLACE:
392 MEMCACHED_COMMAND_REPLACE(c->sfd, ITEM_key(it), it->nkey,
393 (ret == STORED) ? it->nbytes : -1, cas);
394 break;
395 case NREAD_APPEND:
396 MEMCACHED_COMMAND_APPEND(c->sfd, ITEM_key(it), it->nkey,
397 (ret == STORED) ? it->nbytes : -1, cas);
398 break;
399 case NREAD_PREPEND:
400 MEMCACHED_COMMAND_PREPEND(c->sfd, ITEM_key(it), it->nkey,
401 (ret == STORED) ? it->nbytes : -1, cas);
402 break;
403 case NREAD_SET:
404 MEMCACHED_COMMAND_SET(c->sfd, ITEM_key(it), it->nkey,
405 (ret == STORED) ? it->nbytes : -1, cas);
406 break;
407 }
408 #endif
409
410 switch (ret) {
411 case STORED:
412 /* Stored */
413 write_bin_response(c, NULL, 0, 0, 0);
414 break;
415 case EXISTS:
416 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, NULL, 0);
417 break;
418 case NOT_FOUND:
419 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, NULL, 0);
420 break;
421 case NOT_STORED:
422 case TOO_LARGE:
423 case NO_MEMORY:
424 if (c->cmd == NREAD_ADD) {
425 eno = PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
426 } else if(c->cmd == NREAD_REPLACE) {
427 eno = PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
428 } else {
429 eno = PROTOCOL_BINARY_RESPONSE_NOT_STORED;
430 }
431 write_bin_error(c, eno, NULL, 0);
432 }
433
434 item_remove(c->item); /* release the c->item reference */
435 c->item = 0;
436 }
437
write_bin_miss_response(conn * c,char * key,size_t nkey)438 static void write_bin_miss_response(conn *c, char *key, size_t nkey) {
439 if (nkey) {
440 add_bin_header(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT,
441 0, nkey, nkey);
442 char *ofs = c->resp->wbuf + sizeof(protocol_binary_response_header);
443 memcpy(ofs, key, nkey);
444 resp_add_iov(c->resp, ofs, nkey);
445 conn_set_state(c, conn_new_cmd);
446 } else {
447 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT,
448 NULL, 0);
449 }
450 }
451
process_bin_get_or_touch(conn * c,char * extbuf)452 static void process_bin_get_or_touch(conn *c, char *extbuf) {
453 item *it;
454
455 protocol_binary_response_get* rsp = (protocol_binary_response_get*)c->resp->wbuf;
456 char* key = binary_get_key(c);
457 size_t nkey = c->binary_header.request.keylen;
458 int should_touch = (c->cmd == PROTOCOL_BINARY_CMD_TOUCH ||
459 c->cmd == PROTOCOL_BINARY_CMD_GAT ||
460 c->cmd == PROTOCOL_BINARY_CMD_GATK);
461 int should_return_key = (c->cmd == PROTOCOL_BINARY_CMD_GETK ||
462 c->cmd == PROTOCOL_BINARY_CMD_GATK);
463 int should_return_value = (c->cmd != PROTOCOL_BINARY_CMD_TOUCH);
464 bool failed = false;
465
466 if (settings.verbose > 1) {
467 fprintf(stderr, "<%d %s ", c->sfd, should_touch ? "TOUCH" : "GET");
468 if (fwrite(key, 1, nkey, stderr)) {}
469 fputc('\n', stderr);
470 }
471
472 if (should_touch) {
473 protocol_binary_request_touch *t = (void *)extbuf;
474 time_t exptime = ntohl(t->message.body.expiration);
475
476 it = item_touch(key, nkey, realtime(exptime), c);
477 } else {
478 it = item_get(key, nkey, c, DO_UPDATE);
479 }
480
481 if (it) {
482 /* the length has two unnecessary bytes ("\r\n") */
483 uint16_t keylen = 0;
484 uint32_t bodylen = sizeof(rsp->message.body) + (it->nbytes - 2);
485
486 pthread_mutex_lock(&c->thread->stats.mutex);
487 if (should_touch) {
488 c->thread->stats.touch_cmds++;
489 c->thread->stats.slab_stats[ITEM_clsid(it)].touch_hits++;
490 } else {
491 c->thread->stats.get_cmds++;
492 c->thread->stats.lru_hits[it->slabs_clsid]++;
493 }
494 pthread_mutex_unlock(&c->thread->stats.mutex);
495
496 if (should_touch) {
497 MEMCACHED_COMMAND_TOUCH(c->sfd, ITEM_key(it), it->nkey,
498 it->nbytes, ITEM_get_cas(it));
499 } else {
500 MEMCACHED_COMMAND_GET(c->sfd, ITEM_key(it), it->nkey,
501 it->nbytes, ITEM_get_cas(it));
502 }
503
504 if (c->cmd == PROTOCOL_BINARY_CMD_TOUCH) {
505 bodylen -= it->nbytes - 2;
506 } else if (should_return_key) {
507 bodylen += nkey;
508 keylen = nkey;
509 }
510
511 add_bin_header(c, 0, sizeof(rsp->message.body), keylen, bodylen);
512 rsp->message.header.response.cas = htonll(ITEM_get_cas(it));
513
514 // add the flags
515 FLAGS_CONV(it, rsp->message.body.flags);
516 rsp->message.body.flags = htonl(rsp->message.body.flags);
517 resp_add_iov(c->resp, &rsp->message.body, sizeof(rsp->message.body));
518
519 if (should_return_key) {
520 resp_add_iov(c->resp, ITEM_key(it), nkey);
521 }
522
523 if (should_return_value) {
524 /* Add the data minus the CRLF */
525 #ifdef EXTSTORE
526 if (it->it_flags & ITEM_HDR) {
527 if (storage_get_item(c, it, c->resp) != 0) {
528 pthread_mutex_lock(&c->thread->stats.mutex);
529 c->thread->stats.get_oom_extstore++;
530 pthread_mutex_unlock(&c->thread->stats.mutex);
531
532 failed = true;
533 }
534 } else if ((it->it_flags & ITEM_CHUNKED) == 0) {
535 resp_add_iov(c->resp, ITEM_data(it), it->nbytes - 2);
536 } else {
537 // Allow transmit handler to find the item and expand iov's
538 resp_add_chunked_iov(c->resp, it, it->nbytes - 2);
539 }
540 #else
541 if ((it->it_flags & ITEM_CHUNKED) == 0) {
542 resp_add_iov(c->resp, ITEM_data(it), it->nbytes - 2);
543 } else {
544 resp_add_chunked_iov(c->resp, it, it->nbytes - 2);
545 }
546 #endif
547 }
548
549 if (!failed) {
550 conn_set_state(c, conn_new_cmd);
551 /* Remember this command so we can garbage collect it later */
552 #ifdef EXTSTORE
553 if ((it->it_flags & ITEM_HDR) != 0 && should_return_value) {
554 // Only have extstore clean if header and returning value.
555 c->resp->item = NULL;
556 } else {
557 c->resp->item = it;
558 }
559 #else
560 c->resp->item = it;
561 #endif
562 } else {
563 item_remove(it);
564 }
565 } else {
566 failed = true;
567 }
568
569 if (failed) {
570 pthread_mutex_lock(&c->thread->stats.mutex);
571 if (should_touch) {
572 c->thread->stats.touch_cmds++;
573 c->thread->stats.touch_misses++;
574 } else {
575 c->thread->stats.get_cmds++;
576 c->thread->stats.get_misses++;
577 }
578 pthread_mutex_unlock(&c->thread->stats.mutex);
579
580 if (should_touch) {
581 MEMCACHED_COMMAND_TOUCH(c->sfd, key, nkey, -1, 0);
582 } else {
583 MEMCACHED_COMMAND_GET(c->sfd, key, nkey, -1, 0);
584 }
585
586 if (c->noreply) {
587 conn_set_state(c, conn_new_cmd);
588 } else {
589 if (should_return_key) {
590 write_bin_miss_response(c, key, nkey);
591 } else {
592 write_bin_miss_response(c, NULL, 0);
593 }
594 }
595 }
596
597 if (settings.detail_enabled) {
598 stats_prefix_record_get(key, nkey, NULL != it);
599 }
600 }
601
process_bin_stat(conn * c)602 static void process_bin_stat(conn *c) {
603 char *subcommand = binary_get_key(c);
604 size_t nkey = c->binary_header.request.keylen;
605
606 if (settings.verbose > 1) {
607 int ii;
608 fprintf(stderr, "<%d STATS ", c->sfd);
609 for (ii = 0; ii < nkey; ++ii) {
610 fprintf(stderr, "%c", subcommand[ii]);
611 }
612 fprintf(stderr, "\n");
613 }
614
615 if (nkey == 0) {
616 /* request all statistics */
617 server_stats(&append_stats, c);
618 (void)get_stats(NULL, 0, &append_stats, c);
619 } else if (strncmp(subcommand, "reset", 5) == 0) {
620 stats_reset();
621 } else if (strncmp(subcommand, "settings", 8) == 0) {
622 process_stat_settings(&append_stats, c);
623 } else if (strncmp(subcommand, "detail", 6) == 0) {
624 char *subcmd_pos = subcommand + 6;
625 if (strncmp(subcmd_pos, " dump", 5) == 0) {
626 int len;
627 char *dump_buf = stats_prefix_dump(&len);
628 if (dump_buf == NULL || len <= 0) {
629 out_of_memory(c, "SERVER_ERROR Out of memory generating stats");
630 if (dump_buf != NULL)
631 free(dump_buf);
632 return;
633 } else {
634 append_stats("detailed", strlen("detailed"), dump_buf, len, c);
635 free(dump_buf);
636 }
637 } else if (strncmp(subcmd_pos, " on", 3) == 0) {
638 settings.detail_enabled = 1;
639 } else if (strncmp(subcmd_pos, " off", 4) == 0) {
640 settings.detail_enabled = 0;
641 } else {
642 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, NULL, 0);
643 return;
644 }
645 } else {
646 if (get_stats(subcommand, nkey, &append_stats, c)) {
647 if (c->stats.buffer == NULL) {
648 out_of_memory(c, "SERVER_ERROR Out of memory generating stats");
649 } else {
650 write_and_free(c, c->stats.buffer, c->stats.offset);
651 c->stats.buffer = NULL;
652 }
653 } else {
654 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, NULL, 0);
655 }
656
657 return;
658 }
659
660 /* Append termination package and start the transfer */
661 append_stats(NULL, 0, NULL, 0, c);
662 if (c->stats.buffer == NULL) {
663 out_of_memory(c, "SERVER_ERROR Out of memory preparing to send stats");
664 } else {
665 write_and_free(c, c->stats.buffer, c->stats.offset);
666 c->stats.buffer = NULL;
667 }
668 }
669
init_sasl_conn(conn * c)670 static void init_sasl_conn(conn *c) {
671 assert(c);
672 /* should something else be returned? */
673 if (!settings.sasl)
674 return;
675
676 c->authenticated = false;
677
678 if (!c->sasl_conn) {
679 int result=sasl_server_new("memcached",
680 NULL,
681 my_sasl_hostname[0] ? my_sasl_hostname : NULL,
682 NULL, NULL,
683 NULL, 0, &c->sasl_conn);
684 if (result != SASL_OK) {
685 if (settings.verbose) {
686 fprintf(stderr, "Failed to initialize SASL conn.\n");
687 }
688 c->sasl_conn = NULL;
689 }
690 }
691 }
692
bin_list_sasl_mechs(conn * c)693 static void bin_list_sasl_mechs(conn *c) {
694 // Guard against a disabled SASL.
695 if (!settings.sasl) {
696 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND, NULL,
697 c->binary_header.request.bodylen
698 - c->binary_header.request.keylen);
699 return;
700 }
701
702 init_sasl_conn(c);
703 const char *result_string = NULL;
704 unsigned int string_length = 0;
705 int result=sasl_listmech(c->sasl_conn, NULL,
706 "", /* What to prepend the string with */
707 " ", /* What to separate mechanisms with */
708 "", /* What to append to the string */
709 &result_string, &string_length,
710 NULL);
711 if (result != SASL_OK) {
712 /* Perhaps there's a better error for this... */
713 if (settings.verbose) {
714 fprintf(stderr, "Failed to list SASL mechanisms.\n");
715 }
716 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_AUTH_ERROR, NULL, 0);
717 return;
718 }
719 write_bin_response(c, (char*)result_string, 0, 0, string_length);
720 }
721
process_bin_sasl_auth(conn * c)722 static void process_bin_sasl_auth(conn *c) {
723 // Guard for handling disabled SASL on the server.
724 if (!settings.sasl) {
725 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND, NULL,
726 c->binary_header.request.bodylen
727 - c->binary_header.request.keylen);
728 return;
729 }
730
731 assert(c->binary_header.request.extlen == 0);
732
733 int nkey = c->binary_header.request.keylen;
734 int vlen = c->binary_header.request.bodylen - nkey;
735
736 if (nkey > MAX_SASL_MECH_LEN) {
737 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_EINVAL, NULL, vlen);
738 conn_set_state(c, conn_swallow);
739 return;
740 }
741
742 char *key = binary_get_key(c);
743 assert(key);
744
745 item *it = item_alloc(key, nkey, 0, 0, vlen+2);
746
747 /* Can't use a chunked item for SASL authentication. */
748 if (it == 0 || (it->it_flags & ITEM_CHUNKED)) {
749 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_ENOMEM, NULL, vlen);
750 conn_set_state(c, conn_swallow);
751 if (it) {
752 do_item_remove(it);
753 }
754 return;
755 }
756
757 c->item = it;
758 c->ritem = ITEM_data(it);
759 c->rlbytes = vlen;
760 conn_set_state(c, conn_nread);
761 c->substate = bin_reading_sasl_auth_data;
762 }
763
process_bin_complete_sasl_auth(conn * c)764 static void process_bin_complete_sasl_auth(conn *c) {
765 assert(settings.sasl);
766 const char *out = NULL;
767 unsigned int outlen = 0;
768
769 assert(c->item);
770 init_sasl_conn(c);
771
772 int nkey = c->binary_header.request.keylen;
773 int vlen = c->binary_header.request.bodylen - nkey;
774
775 if (nkey > ((item*) c->item)->nkey) {
776 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_EINVAL, NULL, vlen);
777 conn_set_state(c, conn_swallow);
778 return;
779 }
780
781 char mech[nkey+1];
782 memcpy(mech, ITEM_key((item*)c->item), nkey);
783 mech[nkey] = 0x00;
784
785 if (settings.verbose)
786 fprintf(stderr, "mech: ``%s'' with %d bytes of data\n", mech, vlen);
787
788 const char *challenge = vlen == 0 ? NULL : ITEM_data((item*) c->item);
789
790 if (vlen > ((item*) c->item)->nbytes) {
791 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_EINVAL, NULL, vlen);
792 conn_set_state(c, conn_swallow);
793 return;
794 }
795
796 int result=-1;
797
798 switch (c->cmd) {
799 case PROTOCOL_BINARY_CMD_SASL_AUTH:
800 result = sasl_server_start(c->sasl_conn, mech,
801 challenge, vlen,
802 &out, &outlen);
803 c->sasl_started = (result == SASL_OK || result == SASL_CONTINUE);
804 break;
805 case PROTOCOL_BINARY_CMD_SASL_STEP:
806 if (!c->sasl_started) {
807 if (settings.verbose) {
808 fprintf(stderr, "%d: SASL_STEP called but sasl_server_start "
809 "not called for this connection!\n", c->sfd);
810 }
811 break;
812 }
813 result = sasl_server_step(c->sasl_conn,
814 challenge, vlen,
815 &out, &outlen);
816 break;
817 default:
818 assert(false); /* CMD should be one of the above */
819 /* This code is pretty much impossible, but makes the compiler
820 happier */
821 if (settings.verbose) {
822 fprintf(stderr, "Unhandled command %d with challenge %s\n",
823 c->cmd, challenge);
824 }
825 break;
826 }
827
828 if (settings.verbose) {
829 fprintf(stderr, "sasl result code: %d\n", result);
830 }
831
832 switch(result) {
833 case SASL_OK:
834 c->authenticated = true;
835 write_bin_response(c, "Authenticated", 0, 0, strlen("Authenticated"));
836 pthread_mutex_lock(&c->thread->stats.mutex);
837 c->thread->stats.auth_cmds++;
838 pthread_mutex_unlock(&c->thread->stats.mutex);
839 break;
840 case SASL_CONTINUE:
841 add_bin_header(c, PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE, 0, 0, outlen);
842 if (outlen > 0) {
843 resp_add_iov(c->resp, out, outlen);
844 }
845 // Immediately flush our write.
846 conn_set_state(c, conn_mwrite);
847 break;
848 default:
849 if (settings.verbose)
850 fprintf(stderr, "Unknown sasl response: %d\n", result);
851 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_AUTH_ERROR, NULL, 0);
852 pthread_mutex_lock(&c->thread->stats.mutex);
853 c->thread->stats.auth_cmds++;
854 c->thread->stats.auth_errors++;
855 pthread_mutex_unlock(&c->thread->stats.mutex);
856 }
857 }
858
authenticated(conn * c)859 static bool authenticated(conn *c) {
860 assert(settings.sasl);
861 bool rv = false;
862
863 switch (c->cmd) {
864 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: /* FALLTHROUGH */
865 case PROTOCOL_BINARY_CMD_SASL_AUTH: /* FALLTHROUGH */
866 case PROTOCOL_BINARY_CMD_SASL_STEP: /* FALLTHROUGH */
867 case PROTOCOL_BINARY_CMD_VERSION: /* FALLTHROUGH */
868 rv = true;
869 break;
870 default:
871 rv = c->authenticated;
872 }
873
874 if (settings.verbose > 1) {
875 fprintf(stderr, "authenticated() in cmd 0x%02x is %s\n",
876 c->cmd, rv ? "true" : "false");
877 }
878
879 return rv;
880 }
881
dispatch_bin_command(conn * c,char * extbuf)882 static void dispatch_bin_command(conn *c, char *extbuf) {
883 int protocol_error = 0;
884
885 uint8_t extlen = c->binary_header.request.extlen;
886 uint16_t keylen = c->binary_header.request.keylen;
887 uint32_t bodylen = c->binary_header.request.bodylen;
888
889 if (keylen > bodylen || keylen + extlen > bodylen) {
890 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND, NULL, 0);
891 c->close_after_write = true;
892 return;
893 }
894
895 if (settings.sasl && !authenticated(c)) {
896 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_AUTH_ERROR, NULL, 0);
897 c->close_after_write = true;
898 return;
899 }
900
901 MEMCACHED_PROCESS_COMMAND_START(c->sfd, c->rcurr, c->rbytes);
902 c->noreply = true;
903
904 /* binprot supports 16bit keys, but internals are still 8bit */
905 if (keylen > KEY_MAX_LENGTH) {
906 handle_binary_protocol_error(c);
907 return;
908 }
909
910 switch (c->cmd) {
911 case PROTOCOL_BINARY_CMD_SETQ:
912 c->cmd = PROTOCOL_BINARY_CMD_SET;
913 break;
914 case PROTOCOL_BINARY_CMD_ADDQ:
915 c->cmd = PROTOCOL_BINARY_CMD_ADD;
916 break;
917 case PROTOCOL_BINARY_CMD_REPLACEQ:
918 c->cmd = PROTOCOL_BINARY_CMD_REPLACE;
919 break;
920 case PROTOCOL_BINARY_CMD_DELETEQ:
921 c->cmd = PROTOCOL_BINARY_CMD_DELETE;
922 break;
923 case PROTOCOL_BINARY_CMD_INCREMENTQ:
924 c->cmd = PROTOCOL_BINARY_CMD_INCREMENT;
925 break;
926 case PROTOCOL_BINARY_CMD_DECREMENTQ:
927 c->cmd = PROTOCOL_BINARY_CMD_DECREMENT;
928 break;
929 case PROTOCOL_BINARY_CMD_QUITQ:
930 c->cmd = PROTOCOL_BINARY_CMD_QUIT;
931 break;
932 case PROTOCOL_BINARY_CMD_FLUSHQ:
933 c->cmd = PROTOCOL_BINARY_CMD_FLUSH;
934 break;
935 case PROTOCOL_BINARY_CMD_APPENDQ:
936 c->cmd = PROTOCOL_BINARY_CMD_APPEND;
937 break;
938 case PROTOCOL_BINARY_CMD_PREPENDQ:
939 c->cmd = PROTOCOL_BINARY_CMD_PREPEND;
940 break;
941 case PROTOCOL_BINARY_CMD_GETQ:
942 c->cmd = PROTOCOL_BINARY_CMD_GET;
943 break;
944 case PROTOCOL_BINARY_CMD_GETKQ:
945 c->cmd = PROTOCOL_BINARY_CMD_GETK;
946 break;
947 case PROTOCOL_BINARY_CMD_GATQ:
948 c->cmd = PROTOCOL_BINARY_CMD_GAT;
949 break;
950 case PROTOCOL_BINARY_CMD_GATKQ:
951 c->cmd = PROTOCOL_BINARY_CMD_GATK;
952 break;
953 default:
954 c->noreply = false;
955 }
956
957 switch (c->cmd) {
958 case PROTOCOL_BINARY_CMD_VERSION:
959 if (extlen == 0 && keylen == 0 && bodylen == 0) {
960 write_bin_response(c, VERSION, 0, 0, strlen(VERSION));
961 } else {
962 protocol_error = 1;
963 }
964 break;
965 case PROTOCOL_BINARY_CMD_FLUSH:
966 if (keylen == 0 && bodylen == extlen && (extlen == 0 || extlen == 4)) {
967 process_bin_flush(c, extbuf);
968 } else {
969 protocol_error = 1;
970 }
971 break;
972 case PROTOCOL_BINARY_CMD_NOOP:
973 if (extlen == 0 && keylen == 0 && bodylen == 0) {
974 write_bin_response(c, NULL, 0, 0, 0);
975 // NOOP forces pipeline flush.
976 conn_set_state(c, conn_mwrite);
977 } else {
978 protocol_error = 1;
979 }
980 break;
981 case PROTOCOL_BINARY_CMD_SET: /* FALLTHROUGH */
982 case PROTOCOL_BINARY_CMD_ADD: /* FALLTHROUGH */
983 case PROTOCOL_BINARY_CMD_REPLACE:
984 if (extlen == 8 && keylen != 0 && bodylen >= (keylen + 8)) {
985 process_bin_update(c, extbuf);
986 } else {
987 protocol_error = 1;
988 }
989 break;
990 case PROTOCOL_BINARY_CMD_GETQ: /* FALLTHROUGH */
991 case PROTOCOL_BINARY_CMD_GET: /* FALLTHROUGH */
992 case PROTOCOL_BINARY_CMD_GETKQ: /* FALLTHROUGH */
993 case PROTOCOL_BINARY_CMD_GETK:
994 if (extlen == 0 && bodylen == keylen && keylen > 0) {
995 process_bin_get_or_touch(c, extbuf);
996 } else {
997 protocol_error = 1;
998 }
999 break;
1000 case PROTOCOL_BINARY_CMD_DELETE:
1001 if (keylen > 0 && extlen == 0 && bodylen == keylen) {
1002 process_bin_delete(c);
1003 } else {
1004 protocol_error = 1;
1005 }
1006 break;
1007 case PROTOCOL_BINARY_CMD_INCREMENT:
1008 case PROTOCOL_BINARY_CMD_DECREMENT:
1009 if (keylen > 0 && extlen == 20 && bodylen == (keylen + extlen)) {
1010 complete_incr_bin(c, extbuf);
1011 } else {
1012 protocol_error = 1;
1013 }
1014 break;
1015 case PROTOCOL_BINARY_CMD_APPEND:
1016 case PROTOCOL_BINARY_CMD_PREPEND:
1017 if (keylen > 0 && extlen == 0) {
1018 process_bin_append_prepend(c);
1019 } else {
1020 protocol_error = 1;
1021 }
1022 break;
1023 case PROTOCOL_BINARY_CMD_STAT:
1024 if (extlen == 0) {
1025 process_bin_stat(c);
1026 } else {
1027 protocol_error = 1;
1028 }
1029 break;
1030 case PROTOCOL_BINARY_CMD_QUIT:
1031 if (keylen == 0 && extlen == 0 && bodylen == 0) {
1032 write_bin_response(c, NULL, 0, 0, 0);
1033 conn_set_state(c, conn_mwrite);
1034 c->close_after_write = true;
1035 c->close_reason = NORMAL_CLOSE;
1036 } else {
1037 protocol_error = 1;
1038 }
1039 break;
1040 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
1041 if (extlen == 0 && keylen == 0 && bodylen == 0) {
1042 bin_list_sasl_mechs(c);
1043 } else {
1044 protocol_error = 1;
1045 }
1046 break;
1047 case PROTOCOL_BINARY_CMD_SASL_AUTH:
1048 case PROTOCOL_BINARY_CMD_SASL_STEP:
1049 if (extlen == 0 && keylen != 0) {
1050 process_bin_sasl_auth(c);
1051 } else {
1052 protocol_error = 1;
1053 }
1054 break;
1055 case PROTOCOL_BINARY_CMD_TOUCH:
1056 case PROTOCOL_BINARY_CMD_GAT:
1057 case PROTOCOL_BINARY_CMD_GATQ:
1058 case PROTOCOL_BINARY_CMD_GATK:
1059 case PROTOCOL_BINARY_CMD_GATKQ:
1060 if (extlen == 4 && keylen != 0) {
1061 process_bin_get_or_touch(c, extbuf);
1062 } else {
1063 protocol_error = 1;
1064 }
1065 break;
1066 default:
1067 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND, NULL,
1068 bodylen);
1069 }
1070
1071 if (protocol_error)
1072 handle_binary_protocol_error(c);
1073 }
1074
process_bin_update(conn * c,char * extbuf)1075 static void process_bin_update(conn *c, char *extbuf) {
1076 char *key;
1077 int nkey;
1078 int vlen;
1079 item *it;
1080 protocol_binary_request_set* req = (void *)extbuf;
1081
1082 assert(c != NULL);
1083
1084 key = binary_get_key(c);
1085 nkey = c->binary_header.request.keylen;
1086
1087 /* fix byteorder in the request */
1088 req->message.body.flags = ntohl(req->message.body.flags);
1089 req->message.body.expiration = ntohl(req->message.body.expiration);
1090
1091 vlen = c->binary_header.request.bodylen - (nkey + c->binary_header.request.extlen);
1092
1093 if (settings.verbose > 1) {
1094 int ii;
1095 if (c->cmd == PROTOCOL_BINARY_CMD_ADD) {
1096 fprintf(stderr, "<%d ADD ", c->sfd);
1097 } else if (c->cmd == PROTOCOL_BINARY_CMD_SET) {
1098 fprintf(stderr, "<%d SET ", c->sfd);
1099 } else {
1100 fprintf(stderr, "<%d REPLACE ", c->sfd);
1101 }
1102 for (ii = 0; ii < nkey; ++ii) {
1103 fprintf(stderr, "%c", key[ii]);
1104 }
1105
1106 fprintf(stderr, " Value len is %d", vlen);
1107 fprintf(stderr, "\n");
1108 }
1109
1110 if (settings.detail_enabled) {
1111 stats_prefix_record_set(key, nkey);
1112 }
1113
1114 it = item_alloc(key, nkey, req->message.body.flags,
1115 realtime(req->message.body.expiration), vlen+2);
1116
1117 if (it == 0) {
1118 enum store_item_type status;
1119 if (! item_size_ok(nkey, req->message.body.flags, vlen + 2)) {
1120 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_E2BIG, NULL, vlen);
1121 status = TOO_LARGE;
1122 } else {
1123 out_of_memory(c, "SERVER_ERROR Out of memory allocating item");
1124 /* This error generating method eats the swallow value. Add here. */
1125 c->sbytes = vlen;
1126 status = NO_MEMORY;
1127 }
1128 /* FIXME: losing c->cmd since it's translated below. refactor? */
1129 LOGGER_LOG(c->thread->l, LOG_MUTATIONS, LOGGER_ITEM_STORE,
1130 NULL, status, 0, key, nkey, req->message.body.expiration,
1131 ITEM_clsid(it), c->sfd);
1132
1133 /* Avoid stale data persisting in cache because we failed alloc.
1134 * Unacceptable for SET. Anywhere else too? */
1135 if (c->cmd == PROTOCOL_BINARY_CMD_SET) {
1136 it = item_get(key, nkey, c, DONT_UPDATE);
1137 if (it) {
1138 item_unlink(it);
1139 STORAGE_delete(c->thread->storage, it);
1140 item_remove(it);
1141 }
1142 }
1143
1144 /* swallow the data line */
1145 conn_set_state(c, conn_swallow);
1146 return;
1147 }
1148
1149 ITEM_set_cas(it, c->binary_header.request.cas);
1150
1151 switch (c->cmd) {
1152 case PROTOCOL_BINARY_CMD_ADD:
1153 c->cmd = NREAD_ADD;
1154 break;
1155 case PROTOCOL_BINARY_CMD_SET:
1156 c->cmd = NREAD_SET;
1157 break;
1158 case PROTOCOL_BINARY_CMD_REPLACE:
1159 c->cmd = NREAD_REPLACE;
1160 break;
1161 default:
1162 assert(0);
1163 }
1164
1165 if (ITEM_get_cas(it) != 0) {
1166 c->cmd = NREAD_CAS;
1167 }
1168
1169 c->item = it;
1170 #ifdef NEED_ALIGN
1171 if (it->it_flags & ITEM_CHUNKED) {
1172 c->ritem = ITEM_schunk(it);
1173 } else {
1174 c->ritem = ITEM_data(it);
1175 }
1176 #else
1177 c->ritem = ITEM_data(it);
1178 #endif
1179 c->rlbytes = vlen;
1180 conn_set_state(c, conn_nread);
1181 c->substate = bin_read_set_value;
1182 }
1183
process_bin_append_prepend(conn * c)1184 static void process_bin_append_prepend(conn *c) {
1185 char *key;
1186 int nkey;
1187 int vlen;
1188 item *it;
1189
1190 assert(c != NULL);
1191
1192 key = binary_get_key(c);
1193 nkey = c->binary_header.request.keylen;
1194 vlen = c->binary_header.request.bodylen - nkey;
1195
1196 if (settings.verbose > 1) {
1197 fprintf(stderr, "Value len is %d\n", vlen);
1198 }
1199
1200 if (settings.detail_enabled) {
1201 stats_prefix_record_set(key, nkey);
1202 }
1203
1204 it = item_alloc(key, nkey, 0, 0, vlen+2);
1205
1206 if (it == 0) {
1207 if (! item_size_ok(nkey, 0, vlen + 2)) {
1208 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_E2BIG, NULL, vlen);
1209 } else {
1210 out_of_memory(c, "SERVER_ERROR Out of memory allocating item");
1211 /* OOM calls eat the swallow value. Add here. */
1212 c->sbytes = vlen;
1213 }
1214 /* swallow the data line */
1215 conn_set_state(c, conn_swallow);
1216 return;
1217 }
1218
1219 ITEM_set_cas(it, c->binary_header.request.cas);
1220
1221 switch (c->cmd) {
1222 case PROTOCOL_BINARY_CMD_APPEND:
1223 c->cmd = NREAD_APPEND;
1224 break;
1225 case PROTOCOL_BINARY_CMD_PREPEND:
1226 c->cmd = NREAD_PREPEND;
1227 break;
1228 default:
1229 assert(0);
1230 }
1231
1232 c->item = it;
1233 #ifdef NEED_ALIGN
1234 if (it->it_flags & ITEM_CHUNKED) {
1235 c->ritem = ITEM_schunk(it);
1236 } else {
1237 c->ritem = ITEM_data(it);
1238 }
1239 #else
1240 c->ritem = ITEM_data(it);
1241 #endif
1242 c->rlbytes = vlen;
1243 conn_set_state(c, conn_nread);
1244 c->substate = bin_read_set_value;
1245 }
1246
process_bin_flush(conn * c,char * extbuf)1247 static void process_bin_flush(conn *c, char *extbuf) {
1248 time_t exptime = 0;
1249 protocol_binary_request_flush* req = (void *)extbuf;
1250 rel_time_t new_oldest = 0;
1251
1252 if (!settings.flush_enabled) {
1253 // flush_all is not allowed but we log it on stats
1254 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_AUTH_ERROR, NULL, 0);
1255 return;
1256 }
1257
1258 if (c->binary_header.request.extlen == sizeof(req->message.body)) {
1259 exptime = ntohl(req->message.body.expiration);
1260 }
1261
1262 if (exptime > 0) {
1263 new_oldest = realtime(exptime);
1264 } else {
1265 new_oldest = current_time;
1266 }
1267 if (settings.use_cas) {
1268 settings.oldest_live = new_oldest - 1;
1269 if (settings.oldest_live <= current_time)
1270 settings.oldest_cas = get_cas_id();
1271 } else {
1272 settings.oldest_live = new_oldest;
1273 }
1274
1275 pthread_mutex_lock(&c->thread->stats.mutex);
1276 c->thread->stats.flush_cmds++;
1277 pthread_mutex_unlock(&c->thread->stats.mutex);
1278
1279 write_bin_response(c, NULL, 0, 0, 0);
1280 }
1281
process_bin_delete(conn * c)1282 static void process_bin_delete(conn *c) {
1283 item *it;
1284 uint32_t hv;
1285
1286 char* key = binary_get_key(c);
1287 size_t nkey = c->binary_header.request.keylen;
1288
1289 assert(c != NULL);
1290
1291 if (settings.verbose > 1) {
1292 int ii;
1293 fprintf(stderr, "Deleting ");
1294 for (ii = 0; ii < nkey; ++ii) {
1295 fprintf(stderr, "%c", key[ii]);
1296 }
1297 fprintf(stderr, "\n");
1298 }
1299
1300 if (settings.detail_enabled) {
1301 stats_prefix_record_delete(key, nkey);
1302 }
1303
1304 it = item_get_locked(key, nkey, c, DONT_UPDATE, &hv);
1305 if (it) {
1306 uint64_t cas = c->binary_header.request.cas;
1307 if (cas == 0 || cas == ITEM_get_cas(it)) {
1308 MEMCACHED_COMMAND_DELETE(c->sfd, ITEM_key(it), it->nkey);
1309 pthread_mutex_lock(&c->thread->stats.mutex);
1310 c->thread->stats.slab_stats[ITEM_clsid(it)].delete_hits++;
1311 pthread_mutex_unlock(&c->thread->stats.mutex);
1312 do_item_unlink(it, hv);
1313 STORAGE_delete(c->thread->storage, it);
1314 write_bin_response(c, NULL, 0, 0, 0);
1315 } else {
1316 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, NULL, 0);
1317 }
1318 do_item_remove(it); /* release our reference */
1319 } else {
1320 write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, NULL, 0);
1321 pthread_mutex_lock(&c->thread->stats.mutex);
1322 c->thread->stats.delete_misses++;
1323 pthread_mutex_unlock(&c->thread->stats.mutex);
1324 }
1325 item_unlock(hv);
1326 }
1327
1328
1329