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