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