nutcracker 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. data/README.md +22 -0
  2. data/Rakefile +55 -0
  3. data/bin/nutcracker +2 -0
  4. data/ext/nutcracker/ChangeLog +66 -0
  5. data/ext/nutcracker/LICENSE +177 -0
  6. data/ext/nutcracker/Makefile.am +7 -0
  7. data/ext/nutcracker/Makefile.in +726 -0
  8. data/ext/nutcracker/NOTICE +124 -0
  9. data/ext/nutcracker/README.md +240 -0
  10. data/ext/nutcracker/aclocal.m4 +956 -0
  11. data/ext/nutcracker/conf/nutcracker.leaf.yml +10 -0
  12. data/ext/nutcracker/conf/nutcracker.root.yml +8 -0
  13. data/ext/nutcracker/conf/nutcracker.yml +67 -0
  14. data/ext/nutcracker/config.h.in +316 -0
  15. data/ext/nutcracker/config/config.guess +1561 -0
  16. data/ext/nutcracker/config/config.sub +1686 -0
  17. data/ext/nutcracker/config/depcomp +630 -0
  18. data/ext/nutcracker/config/install-sh +520 -0
  19. data/ext/nutcracker/config/ltmain.sh +8413 -0
  20. data/ext/nutcracker/config/missing +376 -0
  21. data/ext/nutcracker/configure +18862 -0
  22. data/ext/nutcracker/configure.ac +155 -0
  23. data/ext/nutcracker/contrib/Makefile.am +3 -0
  24. data/ext/nutcracker/contrib/Makefile.in +560 -0
  25. data/ext/nutcracker/contrib/yaml-0.1.4.tar.gz +0 -0
  26. data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +19 -0
  27. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +20 -0
  28. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +736 -0
  29. data/ext/nutcracker/contrib/yaml-0.1.4/README +27 -0
  30. data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +956 -0
  31. data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +80 -0
  32. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +1561 -0
  33. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +1686 -0
  34. data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +630 -0
  35. data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +520 -0
  36. data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +8406 -0
  37. data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +376 -0
  38. data/ext/nutcracker/contrib/yaml-0.1.4/configure +13085 -0
  39. data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +75 -0
  40. data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +222 -0
  41. data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +1971 -0
  42. data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +7357 -0
  43. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +368 -0
  44. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +123 -0
  45. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +23 -0
  46. data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +92 -0
  47. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +4 -0
  48. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +484 -0
  49. data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +1392 -0
  50. data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +394 -0
  51. data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +2329 -0
  52. data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +432 -0
  53. data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +1374 -0
  54. data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +465 -0
  55. data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +3570 -0
  56. data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +141 -0
  57. data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +640 -0
  58. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +8 -0
  59. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +675 -0
  60. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +800 -0
  61. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +1130 -0
  62. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +217 -0
  63. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +202 -0
  64. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +311 -0
  65. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +327 -0
  66. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +63 -0
  67. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +63 -0
  68. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +63 -0
  69. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +354 -0
  70. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +29 -0
  71. data/ext/nutcracker/extconf.rb +5 -0
  72. data/ext/nutcracker/m4/libtool.m4 +7376 -0
  73. data/ext/nutcracker/m4/ltoptions.m4 +368 -0
  74. data/ext/nutcracker/m4/ltsugar.m4 +123 -0
  75. data/ext/nutcracker/m4/ltversion.m4 +23 -0
  76. data/ext/nutcracker/m4/lt~obsolete.m4 +92 -0
  77. data/ext/nutcracker/notes/c-styleguide.txt +425 -0
  78. data/ext/nutcracker/notes/debug.txt +96 -0
  79. data/ext/nutcracker/notes/memcache.txt +123 -0
  80. data/ext/nutcracker/notes/recommendation.md +118 -0
  81. data/ext/nutcracker/notes/redis.md +415 -0
  82. data/ext/nutcracker/notes/socket.txt +131 -0
  83. data/ext/nutcracker/scripts/multi_get.sh +26 -0
  84. data/ext/nutcracker/scripts/nutcracker.init +73 -0
  85. data/ext/nutcracker/scripts/nutcracker.spec +52 -0
  86. data/ext/nutcracker/scripts/pipelined_read.sh +23 -0
  87. data/ext/nutcracker/scripts/pipelined_write.sh +29 -0
  88. data/ext/nutcracker/scripts/populate_memcached.sh +24 -0
  89. data/ext/nutcracker/scripts/redis-check.py +23 -0
  90. data/ext/nutcracker/scripts/redis-check.sh +564 -0
  91. data/ext/nutcracker/src/Makefile.am +46 -0
  92. data/ext/nutcracker/src/Makefile.in +726 -0
  93. data/ext/nutcracker/src/hashkit/Makefile.am +22 -0
  94. data/ext/nutcracker/src/hashkit/Makefile.in +501 -0
  95. data/ext/nutcracker/src/hashkit/nc_crc32.c +105 -0
  96. data/ext/nutcracker/src/hashkit/nc_fnv.c +82 -0
  97. data/ext/nutcracker/src/hashkit/nc_hashkit.h +74 -0
  98. data/ext/nutcracker/src/hashkit/nc_hsieh.c +93 -0
  99. data/ext/nutcracker/src/hashkit/nc_jenkins.c +230 -0
  100. data/ext/nutcracker/src/hashkit/nc_ketama.c +240 -0
  101. data/ext/nutcracker/src/hashkit/nc_md5.c +379 -0
  102. data/ext/nutcracker/src/hashkit/nc_modula.c +144 -0
  103. data/ext/nutcracker/src/hashkit/nc_murmur.c +99 -0
  104. data/ext/nutcracker/src/hashkit/nc_one_at_a_time.c +51 -0
  105. data/ext/nutcracker/src/hashkit/nc_random.c +146 -0
  106. data/ext/nutcracker/src/nc.c +573 -0
  107. data/ext/nutcracker/src/nc_array.c +204 -0
  108. data/ext/nutcracker/src/nc_array.h +73 -0
  109. data/ext/nutcracker/src/nc_client.c +189 -0
  110. data/ext/nutcracker/src/nc_client.h +28 -0
  111. data/ext/nutcracker/src/nc_conf.c +1766 -0
  112. data/ext/nutcracker/src/nc_conf.h +134 -0
  113. data/ext/nutcracker/src/nc_connection.c +392 -0
  114. data/ext/nutcracker/src/nc_connection.h +99 -0
  115. data/ext/nutcracker/src/nc_core.c +334 -0
  116. data/ext/nutcracker/src/nc_core.h +131 -0
  117. data/ext/nutcracker/src/nc_event.c +214 -0
  118. data/ext/nutcracker/src/nc_event.h +39 -0
  119. data/ext/nutcracker/src/nc_log.c +254 -0
  120. data/ext/nutcracker/src/nc_log.h +120 -0
  121. data/ext/nutcracker/src/nc_mbuf.c +285 -0
  122. data/ext/nutcracker/src/nc_mbuf.h +67 -0
  123. data/ext/nutcracker/src/nc_message.c +828 -0
  124. data/ext/nutcracker/src/nc_message.h +253 -0
  125. data/ext/nutcracker/src/nc_proxy.c +359 -0
  126. data/ext/nutcracker/src/nc_proxy.h +34 -0
  127. data/ext/nutcracker/src/nc_queue.h +788 -0
  128. data/ext/nutcracker/src/nc_rbtree.c +348 -0
  129. data/ext/nutcracker/src/nc_rbtree.h +47 -0
  130. data/ext/nutcracker/src/nc_request.c +588 -0
  131. data/ext/nutcracker/src/nc_response.c +332 -0
  132. data/ext/nutcracker/src/nc_server.c +841 -0
  133. data/ext/nutcracker/src/nc_server.h +143 -0
  134. data/ext/nutcracker/src/nc_signal.c +131 -0
  135. data/ext/nutcracker/src/nc_signal.h +34 -0
  136. data/ext/nutcracker/src/nc_stats.c +1188 -0
  137. data/ext/nutcracker/src/nc_stats.h +206 -0
  138. data/ext/nutcracker/src/nc_string.c +109 -0
  139. data/ext/nutcracker/src/nc_string.h +112 -0
  140. data/ext/nutcracker/src/nc_util.c +619 -0
  141. data/ext/nutcracker/src/nc_util.h +214 -0
  142. data/ext/nutcracker/src/proto/Makefile.am +14 -0
  143. data/ext/nutcracker/src/proto/Makefile.in +482 -0
  144. data/ext/nutcracker/src/proto/nc_memcache.c +1306 -0
  145. data/ext/nutcracker/src/proto/nc_proto.h +155 -0
  146. data/ext/nutcracker/src/proto/nc_redis.c +2102 -0
  147. data/lib/nutcracker.rb +7 -0
  148. data/lib/nutcracker/version.rb +3 -0
  149. metadata +194 -0
@@ -0,0 +1,1306 @@
1
+ /*
2
+ * twemproxy - A fast and lightweight proxy for memcached protocol.
3
+ * Copyright (C) 2011 Twitter, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include <ctype.h>
19
+
20
+ #include <nc_core.h>
21
+ #include <nc_proto.h>
22
+
23
+ /*
24
+ * From memcache protocol specification:
25
+ *
26
+ * Data stored by memcached is identified with the help of a key. A key
27
+ * is a text string which should uniquely identify the data for clients
28
+ * that are interested in storing and retrieving it. Currently the
29
+ * length limit of a key is set at 250 characters (of course, normally
30
+ * clients wouldn't need to use such long keys); the key must not include
31
+ * control characters or whitespace.
32
+ */
33
+ #define MEMCACHE_MAX_KEY_LENGTH 250
34
+
35
+ /*
36
+ * Return true, if the memcache command is a storage command, otherwise
37
+ * return false
38
+ */
39
+ static bool
40
+ memcache_storage(struct msg *r)
41
+ {
42
+ switch (r->type) {
43
+ case MSG_REQ_MC_SET:
44
+ case MSG_REQ_MC_CAS:
45
+ case MSG_REQ_MC_ADD:
46
+ case MSG_REQ_MC_REPLACE:
47
+ case MSG_REQ_MC_APPEND:
48
+ case MSG_REQ_MC_PREPEND:
49
+ return true;
50
+
51
+ default:
52
+ break;
53
+ }
54
+
55
+ return false;
56
+ }
57
+
58
+ /*
59
+ * Return true, if the memcache command is a cas command, otherwise
60
+ * return false
61
+ */
62
+ static bool
63
+ memcache_cas(struct msg *r)
64
+ {
65
+ if (r->type == MSG_REQ_MC_CAS) {
66
+ return true;
67
+ }
68
+
69
+ return false;
70
+ }
71
+
72
+ /*
73
+ * Return true, if the memcache command is a retrieval command, otherwise
74
+ * return false
75
+ */
76
+ static bool
77
+ memcache_retrieval(struct msg *r)
78
+ {
79
+ switch (r->type) {
80
+ case MSG_REQ_MC_GET:
81
+ case MSG_REQ_MC_GETS:
82
+ return true;
83
+
84
+ default:
85
+ break;
86
+ }
87
+
88
+ return false;
89
+ }
90
+
91
+ /*
92
+ * Return true, if the memcache command is a arithmetic command, otherwise
93
+ * return false
94
+ */
95
+ static bool
96
+ memcache_arithmetic(struct msg *r)
97
+ {
98
+ switch (r->type) {
99
+ case MSG_REQ_MC_INCR:
100
+ case MSG_REQ_MC_DECR:
101
+ return true;
102
+
103
+ default:
104
+ break;
105
+ }
106
+
107
+ return false;
108
+ }
109
+
110
+ /*
111
+ * Return true, if the memcache command is a delete command, otherwise
112
+ * return false
113
+ */
114
+ static bool
115
+ memcache_delete(struct msg *r)
116
+ {
117
+ if (r->type == MSG_REQ_MC_DELETE) {
118
+ return true;
119
+ }
120
+
121
+ return false;
122
+ }
123
+
124
+ void
125
+ memcache_parse_req(struct msg *r)
126
+ {
127
+ struct mbuf *b;
128
+ uint8_t *p, *m;
129
+ uint8_t ch;
130
+ enum {
131
+ SW_START,
132
+ SW_REQ_TYPE,
133
+ SW_SPACES_BEFORE_KEY,
134
+ SW_KEY,
135
+ SW_SPACES_BEFORE_KEYS,
136
+ SW_SPACES_BEFORE_FLAGS,
137
+ SW_FLAGS,
138
+ SW_SPACES_BEFORE_EXPIRY,
139
+ SW_EXPIRY,
140
+ SW_SPACES_BEFORE_VLEN,
141
+ SW_VLEN,
142
+ SW_SPACES_BEFORE_CAS,
143
+ SW_CAS,
144
+ SW_RUNTO_VAL,
145
+ SW_VAL,
146
+ SW_SPACES_BEFORE_NUM,
147
+ SW_NUM,
148
+ SW_RUNTO_CRLF,
149
+ SW_CRLF,
150
+ SW_NOREPLY,
151
+ SW_AFTER_NOREPLY,
152
+ SW_ALMOST_DONE,
153
+ SW_SENTINEL
154
+ } state;
155
+
156
+ state = r->state;
157
+ b = STAILQ_LAST(&r->mhdr, mbuf, next);
158
+
159
+ ASSERT(r->request);
160
+ ASSERT(!r->redis);
161
+ ASSERT(state >= SW_START && state < SW_SENTINEL);
162
+ ASSERT(b != NULL);
163
+ ASSERT(b->pos <= b->last);
164
+
165
+ /* validate the parsing maker */
166
+ ASSERT(r->pos != NULL);
167
+ ASSERT(r->pos >= b->pos && r->pos <= b->last);
168
+
169
+ for (p = r->pos; p < b->last; p++) {
170
+ ch = *p;
171
+
172
+ switch (state) {
173
+
174
+ case SW_START:
175
+ if (ch == ' ') {
176
+ break;
177
+ }
178
+
179
+ if (!islower(ch)) {
180
+ goto error;
181
+ }
182
+
183
+ /* req_start <- p; type_start <- p */
184
+ r->token = p;
185
+ state = SW_REQ_TYPE;
186
+
187
+ break;
188
+
189
+ case SW_REQ_TYPE:
190
+ if (ch == ' ' || ch == CR) {
191
+ /* type_end = p - 1 */
192
+ m = r->token;
193
+ r->token = NULL;
194
+ r->type = MSG_UNKNOWN;
195
+
196
+ switch (p - m) {
197
+
198
+ case 3:
199
+ if (str4cmp(m, 'g', 'e', 't', ' ')) {
200
+ r->type = MSG_REQ_MC_GET;
201
+ break;
202
+ }
203
+
204
+ if (str4cmp(m, 's', 'e', 't', ' ')) {
205
+ r->type = MSG_REQ_MC_SET;
206
+ break;
207
+ }
208
+
209
+ if (str4cmp(m, 'a', 'd', 'd', ' ')) {
210
+ r->type = MSG_REQ_MC_ADD;
211
+ break;
212
+ }
213
+
214
+ if (str4cmp(m, 'c', 'a', 's', ' ')) {
215
+ r->type = MSG_REQ_MC_CAS;
216
+ break;
217
+ }
218
+
219
+ break;
220
+
221
+ case 4:
222
+ if (str4cmp(m, 'g', 'e', 't', 's')) {
223
+ r->type = MSG_REQ_MC_GETS;
224
+ break;
225
+ }
226
+
227
+ if (str4cmp(m, 'i', 'n', 'c', 'r')) {
228
+ r->type = MSG_REQ_MC_INCR;
229
+ break;
230
+ }
231
+
232
+ if (str4cmp(m, 'd', 'e', 'c', 'r')) {
233
+ r->type = MSG_REQ_MC_DECR;
234
+ break;
235
+ }
236
+
237
+ if (str4cmp(m, 'q', 'u', 'i', 't')) {
238
+ r->type = MSG_REQ_MC_QUIT;
239
+ r->quit = 1;
240
+ break;
241
+ }
242
+
243
+ break;
244
+
245
+ case 6:
246
+ if (str6cmp(m, 'a', 'p', 'p', 'e', 'n', 'd')) {
247
+ r->type = MSG_REQ_MC_APPEND;
248
+ break;
249
+ }
250
+
251
+ if (str6cmp(m, 'd', 'e', 'l', 'e', 't', 'e')) {
252
+ r->type = MSG_REQ_MC_DELETE;
253
+ break;
254
+ }
255
+
256
+ break;
257
+
258
+ case 7:
259
+ if (str7cmp(m, 'p', 'r', 'e', 'p', 'e', 'n', 'd')) {
260
+ r->type = MSG_REQ_MC_PREPEND;
261
+ break;
262
+ }
263
+
264
+ if (str7cmp(m, 'r', 'e', 'p', 'l', 'a', 'c', 'e')) {
265
+ r->type = MSG_REQ_MC_REPLACE;
266
+ break;
267
+ }
268
+
269
+ break;
270
+ }
271
+
272
+ switch (r->type) {
273
+ case MSG_REQ_MC_GET:
274
+ case MSG_REQ_MC_GETS:
275
+ case MSG_REQ_MC_DELETE:
276
+ case MSG_REQ_MC_CAS:
277
+ case MSG_REQ_MC_SET:
278
+ case MSG_REQ_MC_ADD:
279
+ case MSG_REQ_MC_REPLACE:
280
+ case MSG_REQ_MC_APPEND:
281
+ case MSG_REQ_MC_PREPEND:
282
+ case MSG_REQ_MC_INCR:
283
+ case MSG_REQ_MC_DECR:
284
+ if (ch == CR) {
285
+ goto error;
286
+ }
287
+ state = SW_SPACES_BEFORE_KEY;
288
+ break;
289
+
290
+ case MSG_REQ_MC_QUIT:
291
+ p = p - 1; /* go back by 1 byte */
292
+ state = SW_CRLF;
293
+ break;
294
+
295
+ case MSG_UNKNOWN:
296
+ goto error;
297
+
298
+ default:
299
+ NOT_REACHED();
300
+ }
301
+
302
+ } else if (!islower(ch)) {
303
+ goto error;
304
+ }
305
+
306
+ break;
307
+
308
+ case SW_SPACES_BEFORE_KEY:
309
+ if (ch != ' ') {
310
+ r->token = p;
311
+ r->key_start = p;
312
+ state = SW_KEY;
313
+ }
314
+
315
+ break;
316
+
317
+ case SW_KEY:
318
+ if (ch == ' ' || ch == CR) {
319
+ if ((p - r->key_start) > MEMCACHE_MAX_KEY_LENGTH) {
320
+ log_error("parsed bad req %"PRIu64" of type %d with key "
321
+ "prefix '%.*s...' and length %d that exceeds "
322
+ "maximum key length", r->id, r->type, 16,
323
+ r->key_start, p - r->key_start);
324
+ goto error;
325
+ }
326
+ r->key_end = p;
327
+ r->token = NULL;
328
+
329
+ /* get next state */
330
+ if (memcache_storage(r)) {
331
+ state = SW_SPACES_BEFORE_FLAGS;
332
+ } else if (memcache_arithmetic(r)) {
333
+ state = SW_SPACES_BEFORE_NUM;
334
+ } else if (memcache_delete(r)) {
335
+ state = SW_RUNTO_CRLF;
336
+ } else if (memcache_retrieval(r)) {
337
+ state = SW_SPACES_BEFORE_KEYS;
338
+ } else {
339
+ state = SW_RUNTO_CRLF;
340
+ }
341
+
342
+ if (ch == CR) {
343
+ if (memcache_storage(r) || memcache_arithmetic(r)) {
344
+ goto error;
345
+ }
346
+ p = p - 1; /* go back by 1 byte */
347
+ }
348
+ }
349
+
350
+ break;
351
+
352
+ case SW_SPACES_BEFORE_KEYS:
353
+ ASSERT(memcache_retrieval(r));
354
+ switch (ch) {
355
+ case ' ':
356
+ break;
357
+
358
+ case CR:
359
+ state = SW_ALMOST_DONE;
360
+ break;
361
+
362
+ default:
363
+ r->token = p;
364
+ goto fragment;
365
+ }
366
+
367
+ break;
368
+
369
+ case SW_SPACES_BEFORE_FLAGS:
370
+ if (ch != ' ') {
371
+ if (!isdigit(ch)) {
372
+ goto error;
373
+ }
374
+ /* flags_start <- p; flags <- ch - '0' */
375
+ r->token = p;
376
+ state = SW_FLAGS;
377
+ }
378
+
379
+ break;
380
+
381
+ case SW_FLAGS:
382
+ if (isdigit(ch)) {
383
+ /* flags <- flags * 10 + (ch - '0') */
384
+ ;
385
+ } else if (ch == ' ') {
386
+ /* flags_end <- p - 1 */
387
+ r->token = NULL;
388
+ state = SW_SPACES_BEFORE_EXPIRY;
389
+ } else {
390
+ goto error;
391
+ }
392
+
393
+ break;
394
+
395
+ case SW_SPACES_BEFORE_EXPIRY:
396
+ if (ch != ' ') {
397
+ if (!isdigit(ch)) {
398
+ goto error;
399
+ }
400
+ /* expiry_start <- p; expiry <- ch - '0' */
401
+ r->token = p;
402
+ state = SW_EXPIRY;
403
+ }
404
+
405
+ break;
406
+
407
+ case SW_EXPIRY:
408
+ if (isdigit(ch)) {
409
+ /* expiry <- expiry * 10 + (ch - '0') */
410
+ ;
411
+ } else if (ch == ' ') {
412
+ /* expiry_end <- p - 1 */
413
+ r->token = NULL;
414
+ state = SW_SPACES_BEFORE_VLEN;
415
+ } else {
416
+ goto error;
417
+ }
418
+
419
+ break;
420
+
421
+ case SW_SPACES_BEFORE_VLEN:
422
+ if (ch != ' ') {
423
+ if (!isdigit(ch)) {
424
+ goto error;
425
+ }
426
+ /* vlen_start <- p */
427
+ r->token = p;
428
+ r->vlen = (uint32_t)(ch - '0');
429
+ state = SW_VLEN;
430
+ }
431
+
432
+ break;
433
+
434
+ case SW_VLEN:
435
+ if (isdigit(ch)) {
436
+ r->vlen = r->vlen * 10 + (uint32_t)(ch - '0');
437
+ } else if (memcache_cas(r)) {
438
+ if (ch != ' ') {
439
+ goto error;
440
+ }
441
+ /* vlen_end <- p - 1 */
442
+ p = p - 1; /* go back by 1 byte */
443
+ r->token = NULL;
444
+ state = SW_SPACES_BEFORE_CAS;
445
+ } else if (ch == ' ' || ch == CR) {
446
+ /* vlen_end <- p - 1 */
447
+ p = p - 1; /* go back by 1 byte */
448
+ r->token = NULL;
449
+ state = SW_RUNTO_CRLF;
450
+ } else {
451
+ goto error;
452
+ }
453
+
454
+ break;
455
+
456
+ case SW_SPACES_BEFORE_CAS:
457
+ if (ch != ' ') {
458
+ if (!isdigit(ch)) {
459
+ goto error;
460
+ }
461
+ /* cas_start <- p; cas <- ch - '0' */
462
+ r->token = p;
463
+ state = SW_CAS;
464
+ }
465
+
466
+ break;
467
+
468
+ case SW_CAS:
469
+ if (isdigit(ch)) {
470
+ /* cas <- cas * 10 + (ch - '0') */
471
+ ;
472
+ } else if (ch == ' ' || ch == CR) {
473
+ /* cas_end <- p - 1 */
474
+ p = p - 1; /* go back by 1 byte */
475
+ r->token = NULL;
476
+ state = SW_RUNTO_CRLF;
477
+ } else {
478
+ goto error;
479
+ }
480
+
481
+ break;
482
+
483
+
484
+ case SW_RUNTO_VAL:
485
+ switch (ch) {
486
+ case LF:
487
+ /* val_start <- p + 1 */
488
+ state = SW_VAL;
489
+ break;
490
+
491
+ default:
492
+ goto error;
493
+ }
494
+
495
+ break;
496
+
497
+ case SW_VAL:
498
+ m = p + r->vlen;
499
+ if (m >= b->last) {
500
+ ASSERT(r->vlen >= (uint32_t)(b->last - p));
501
+ r->vlen -= (uint32_t)(b->last - p);
502
+ m = b->last - 1;
503
+ p = m; /* move forward by vlen bytes */
504
+ break;
505
+ }
506
+ switch (*m) {
507
+ case CR:
508
+ /* val_end <- p - 1 */
509
+ p = m; /* move forward by vlen bytes */
510
+ state = SW_ALMOST_DONE;
511
+ break;
512
+
513
+ default:
514
+ goto error;
515
+ }
516
+
517
+ break;
518
+
519
+ case SW_SPACES_BEFORE_NUM:
520
+ if (ch != ' ') {
521
+ if (!isdigit(ch)) {
522
+ goto error;
523
+ }
524
+ /* num_start <- p; num <- ch - '0' */
525
+ r->token = p;
526
+ state = SW_NUM;
527
+ }
528
+
529
+ break;
530
+
531
+ case SW_NUM:
532
+ if (isdigit(ch)) {
533
+ /* num <- num * 10 + (ch - '0') */
534
+ ;
535
+ } else if (ch == ' ' || ch == CR) {
536
+ r->token = NULL;
537
+ /* num_end <- p - 1 */
538
+ p = p - 1; /* go back by 1 byte */
539
+ state = SW_RUNTO_CRLF;
540
+ } else {
541
+ goto error;
542
+ }
543
+
544
+ break;
545
+
546
+ case SW_RUNTO_CRLF:
547
+ switch (ch) {
548
+ case ' ':
549
+ break;
550
+
551
+ case 'n':
552
+ if (memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r)) {
553
+ /* noreply_start <- p */
554
+ r->token = p;
555
+ state = SW_NOREPLY;
556
+ } else {
557
+ goto error;
558
+ }
559
+
560
+ break;
561
+
562
+ case CR:
563
+ if (memcache_storage(r)) {
564
+ state = SW_RUNTO_VAL;
565
+ } else {
566
+ state = SW_ALMOST_DONE;
567
+ }
568
+
569
+ break;
570
+
571
+ default:
572
+ goto error;
573
+ }
574
+
575
+ break;
576
+
577
+ case SW_NOREPLY:
578
+ switch (ch) {
579
+ case ' ':
580
+ case CR:
581
+ m = r->token;
582
+ if (((p - m) == 7) && str7cmp(m, 'n', 'o', 'r', 'e', 'p', 'l', 'y')) {
583
+ ASSERT(memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r));
584
+ r->token = NULL;
585
+ /* noreply_end <- p - 1 */
586
+ r->noreply = 1;
587
+ state = SW_AFTER_NOREPLY;
588
+ p = p - 1; /* go back by 1 byte */
589
+ } else {
590
+ goto error;
591
+ }
592
+ }
593
+
594
+ break;
595
+
596
+ case SW_AFTER_NOREPLY:
597
+ switch (ch) {
598
+ case ' ':
599
+ break;
600
+
601
+ case CR:
602
+ if (memcache_storage(r)) {
603
+ state = SW_RUNTO_VAL;
604
+ } else {
605
+ state = SW_ALMOST_DONE;
606
+ }
607
+ break;
608
+
609
+ default:
610
+ goto error;
611
+ }
612
+
613
+ break;
614
+
615
+ case SW_CRLF:
616
+ switch (ch) {
617
+ case ' ':
618
+ break;
619
+
620
+ case CR:
621
+ state = SW_ALMOST_DONE;
622
+ break;
623
+
624
+ default:
625
+ goto error;
626
+ }
627
+
628
+ break;
629
+
630
+ case SW_ALMOST_DONE:
631
+ switch (ch) {
632
+ case LF:
633
+ /* req_end <- p */
634
+ goto done;
635
+
636
+ default:
637
+ goto error;
638
+ }
639
+
640
+ break;
641
+
642
+ case SW_SENTINEL:
643
+ default:
644
+ NOT_REACHED();
645
+ break;
646
+
647
+ }
648
+ }
649
+
650
+ /*
651
+ * At this point, buffer from b->pos to b->last has been parsed completely
652
+ * but we haven't been able to reach to any conclusion. Normally, this
653
+ * means that we have to parse again starting from the state we are in
654
+ * after more data has been read. The newly read data is either read into
655
+ * a new mbuf, if existing mbuf is full (b->last == b->end) or into the
656
+ * existing mbuf.
657
+ *
658
+ * The only exception to this is when the existing mbuf is full (b->last
659
+ * is at b->end) and token marker is set, which means that we have to
660
+ * copy the partial token into a new mbuf and parse again with more data
661
+ * read into new mbuf.
662
+ */
663
+ ASSERT(p == b->last);
664
+ r->pos = p;
665
+ r->state = state;
666
+
667
+ if (b->last == b->end && r->token != NULL) {
668
+ r->pos = r->token;
669
+ r->token = NULL;
670
+ r->result = MSG_PARSE_REPAIR;
671
+ } else {
672
+ r->result = MSG_PARSE_AGAIN;
673
+ }
674
+
675
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
676
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
677
+ r->state, r->pos - b->pos, b->last - b->pos);
678
+ return;
679
+
680
+ fragment:
681
+ ASSERT(p != b->last);
682
+ ASSERT(r->token != NULL);
683
+ r->pos = r->token;
684
+ r->token = NULL;
685
+ r->state = state;
686
+ r->result = MSG_PARSE_FRAGMENT;
687
+
688
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
689
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
690
+ r->state, r->pos - b->pos, b->last - b->pos);
691
+ return;
692
+
693
+ done:
694
+ ASSERT(r->type > MSG_UNKNOWN && r->type < MSG_SENTINEL);
695
+ r->pos = p + 1;
696
+ ASSERT(r->pos <= b->last);
697
+ r->state = SW_START;
698
+ r->result = MSG_PARSE_OK;
699
+
700
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
701
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
702
+ r->state, r->pos - b->pos, b->last - b->pos);
703
+ return;
704
+
705
+ error:
706
+ r->result = MSG_PARSE_ERROR;
707
+ r->state = state;
708
+ errno = EINVAL;
709
+
710
+ log_hexdump(LOG_INFO, b->pos, mbuf_length(b), "parsed bad req %"PRIu64" "
711
+ "res %d type %d state %d", r->id, r->result, r->type,
712
+ r->state);
713
+ }
714
+
715
+ void
716
+ memcache_parse_rsp(struct msg *r)
717
+ {
718
+ struct mbuf *b;
719
+ uint8_t *p, *m;
720
+ uint8_t ch;
721
+ enum {
722
+ SW_START,
723
+ SW_RSP_NUM,
724
+ SW_RSP_STR,
725
+ SW_SPACES_BEFORE_KEY,
726
+ SW_KEY,
727
+ SW_SPACES_BEFORE_FLAGS,
728
+ SW_FLAGS,
729
+ SW_SPACES_BEFORE_VLEN,
730
+ SW_VLEN,
731
+ SW_RUNTO_VAL,
732
+ SW_VAL,
733
+ SW_VAL_LF,
734
+ SW_END,
735
+ SW_RUNTO_CRLF,
736
+ SW_CRLF,
737
+ SW_ALMOST_DONE,
738
+ SW_SENTINEL
739
+ } state;
740
+
741
+ state = r->state;
742
+ b = STAILQ_LAST(&r->mhdr, mbuf, next);
743
+
744
+ ASSERT(!r->request);
745
+ ASSERT(!r->redis);
746
+ ASSERT(state >= SW_START && state < SW_SENTINEL);
747
+ ASSERT(b != NULL);
748
+ ASSERT(b->pos <= b->last);
749
+
750
+ /* validate the parsing marker */
751
+ ASSERT(r->pos != NULL);
752
+ ASSERT(r->pos >= b->pos && r->pos <= b->last);
753
+
754
+ for (p = r->pos; p < b->last; p++) {
755
+ ch = *p;
756
+
757
+ switch (state) {
758
+ case SW_START:
759
+ if (isdigit(ch)) {
760
+ state = SW_RSP_NUM;
761
+ } else {
762
+ state = SW_RSP_STR;
763
+ }
764
+ p = p - 1; /* go back by 1 byte */
765
+
766
+ break;
767
+
768
+ case SW_RSP_NUM:
769
+ if (r->token == NULL) {
770
+ /* rsp_start <- p; type_start <- p */
771
+ r->token = p;
772
+ }
773
+
774
+ if (isdigit(ch)) {
775
+ /* num <- num * 10 + (ch - '0') */
776
+ ;
777
+ } else if (ch == ' ' || ch == CR) {
778
+ /* type_end <- p - 1 */
779
+ r->token = NULL;
780
+ r->type = MSG_RSP_MC_NUM;
781
+ p = p - 1; /* go back by 1 byte */
782
+ state = SW_CRLF;
783
+ } else {
784
+ goto error;
785
+ }
786
+
787
+ break;
788
+
789
+ case SW_RSP_STR:
790
+ if (r->token == NULL) {
791
+ /* rsp_start <- p; type_start <- p */
792
+ r->token = p;
793
+ }
794
+
795
+ if (ch == ' ' || ch == CR) {
796
+ /* type_end <- p - 1 */
797
+ m = r->token;
798
+ r->token = NULL;
799
+ r->type = MSG_UNKNOWN;
800
+
801
+ switch (p - m) {
802
+ case 3:
803
+ if (str4cmp(m, 'E', 'N', 'D', '\r')) {
804
+ r->type = MSG_RSP_MC_END;
805
+ /* end_start <- m; end_end <- p - 1*/
806
+ r->end = m;
807
+ break;
808
+ }
809
+
810
+ break;
811
+
812
+ case 5:
813
+ if (str5cmp(m, 'V', 'A', 'L', 'U', 'E')) {
814
+ /*
815
+ * Encompasses responses for 'get', 'gets' and
816
+ * 'cas' command.
817
+ */
818
+ r->type = MSG_RSP_MC_VALUE;
819
+ break;
820
+ }
821
+
822
+ if (str5cmp(m, 'E', 'R', 'R', 'O', 'R')) {
823
+ r->type = MSG_RSP_MC_ERROR;
824
+ break;
825
+ }
826
+
827
+ break;
828
+
829
+ case 6:
830
+ if (str6cmp(m, 'S', 'T', 'O', 'R', 'E', 'D')) {
831
+ r->type = MSG_RSP_MC_STORED;
832
+ break;
833
+ }
834
+
835
+ if (str6cmp(m, 'E', 'X', 'I', 'S', 'T', 'S')) {
836
+ r->type = MSG_RSP_MC_EXISTS;
837
+ break;
838
+ }
839
+
840
+ break;
841
+
842
+ case 7:
843
+ if (str7cmp(m, 'D', 'E', 'L', 'E', 'T', 'E', 'D')) {
844
+ r->type = MSG_RSP_MC_DELETED;
845
+ break;
846
+ }
847
+
848
+ break;
849
+
850
+ case 9:
851
+ if (str9cmp(m, 'N', 'O', 'T', '_', 'F', 'O', 'U', 'N', 'D')) {
852
+ r->type = MSG_RSP_MC_NOT_FOUND;
853
+ break;
854
+ }
855
+
856
+ break;
857
+
858
+ case 10:
859
+ if (str10cmp(m, 'N', 'O', 'T', '_', 'S', 'T', 'O', 'R', 'E', 'D')) {
860
+ r->type = MSG_RSP_MC_NOT_STORED;
861
+ break;
862
+ }
863
+
864
+ break;
865
+
866
+ case 12:
867
+ if (str12cmp(m, 'C', 'L', 'I', 'E', 'N', 'T', '_', 'E', 'R', 'R', 'O', 'R')) {
868
+ r->type = MSG_RSP_MC_CLIENT_ERROR;
869
+ break;
870
+ }
871
+
872
+ if (str12cmp(m, 'S', 'E', 'R', 'V', 'E', 'R', '_', 'E', 'R', 'R', 'O', 'R')) {
873
+ r->type = MSG_RSP_MC_SERVER_ERROR;
874
+ break;
875
+ }
876
+
877
+ break;
878
+ }
879
+
880
+ switch (r->type) {
881
+ case MSG_UNKNOWN:
882
+ goto error;
883
+
884
+ case MSG_RSP_MC_STORED:
885
+ case MSG_RSP_MC_NOT_STORED:
886
+ case MSG_RSP_MC_EXISTS:
887
+ case MSG_RSP_MC_NOT_FOUND:
888
+ case MSG_RSP_MC_DELETED:
889
+ state = SW_CRLF;
890
+ break;
891
+
892
+ case MSG_RSP_MC_END:
893
+ state = SW_CRLF;
894
+ break;
895
+
896
+ case MSG_RSP_MC_VALUE:
897
+ state = SW_SPACES_BEFORE_KEY;
898
+ break;
899
+
900
+ case MSG_RSP_MC_ERROR:
901
+ state = SW_CRLF;
902
+ break;
903
+
904
+ case MSG_RSP_MC_CLIENT_ERROR:
905
+ case MSG_RSP_MC_SERVER_ERROR:
906
+ state = SW_RUNTO_CRLF;
907
+ break;
908
+
909
+ default:
910
+ NOT_REACHED();
911
+ }
912
+
913
+ p = p - 1; /* go back by 1 byte */
914
+ }
915
+
916
+ break;
917
+
918
+ case SW_SPACES_BEFORE_KEY:
919
+ if (ch != ' ') {
920
+ state = SW_KEY;
921
+ p = p - 1; /* go back by 1 byte */
922
+ }
923
+
924
+ break;
925
+
926
+ case SW_KEY:
927
+ if (r->token == NULL) {
928
+ r->token = p;
929
+ r->key_start = p;
930
+ }
931
+
932
+ if (ch == ' ') {
933
+ if ((p - r->key_start) > MEMCACHE_MAX_KEY_LENGTH) {
934
+ log_error("parsed bad req %"PRIu64" of type %d with key "
935
+ "prefix '%.*s...' and length %d that exceeds "
936
+ "maximum key length", r->id, r->type, 16,
937
+ r->key_start, p - r->key_start);
938
+ goto error;
939
+ }
940
+ r->key_end = p;
941
+ r->token = NULL;
942
+ state = SW_SPACES_BEFORE_FLAGS;
943
+ }
944
+
945
+ break;
946
+
947
+ case SW_SPACES_BEFORE_FLAGS:
948
+ if (ch != ' ') {
949
+ if (!isdigit(ch)) {
950
+ goto error;
951
+ }
952
+ state = SW_FLAGS;
953
+ p = p - 1; /* go back by 1 byte */
954
+ }
955
+
956
+ break;
957
+
958
+ case SW_FLAGS:
959
+ if (r->token == NULL) {
960
+ /* flags_start <- p */
961
+ r->token = p;
962
+ }
963
+
964
+ if (isdigit(ch)) {
965
+ /* flags <- flags * 10 + (ch - '0') */
966
+ ;
967
+ } else if (ch == ' ') {
968
+ /* flags_end <- p - 1 */
969
+ r->token = NULL;
970
+ state = SW_SPACES_BEFORE_VLEN;
971
+ } else {
972
+ goto error;
973
+ }
974
+
975
+ break;
976
+
977
+ case SW_SPACES_BEFORE_VLEN:
978
+ if (ch != ' ') {
979
+ if (!isdigit(ch)) {
980
+ goto error;
981
+ }
982
+ p = p - 1; /* go back by 1 byte */
983
+ state = SW_VLEN;
984
+ }
985
+
986
+ break;
987
+
988
+ case SW_VLEN:
989
+ if (r->token == NULL) {
990
+ /* vlen_start <- p */
991
+ r->token = p;
992
+ r->vlen = (uint32_t)(ch - '0');
993
+ } else if (isdigit(ch)) {
994
+ r->vlen = r->vlen * 10 + (uint32_t)(ch - '0');
995
+ } else if (ch == ' ' || ch == CR) {
996
+ /* vlen_end <- p - 1 */
997
+ p = p - 1; /* go back by 1 byte */
998
+ r->token = NULL;
999
+ state = SW_RUNTO_CRLF;
1000
+ } else {
1001
+ goto error;
1002
+ }
1003
+
1004
+ break;
1005
+
1006
+ case SW_RUNTO_VAL:
1007
+ switch (ch) {
1008
+ case LF:
1009
+ /* val_start <- p + 1 */
1010
+ state = SW_VAL;
1011
+ break;
1012
+
1013
+ default:
1014
+ goto error;
1015
+ }
1016
+
1017
+ break;
1018
+
1019
+ case SW_VAL:
1020
+ m = p + r->vlen;
1021
+ if (m >= b->last) {
1022
+ ASSERT(r->vlen >= (uint32_t)(b->last - p));
1023
+ r->vlen -= (uint32_t)(b->last - p);
1024
+ m = b->last - 1;
1025
+ p = m; /* move forward by vlen bytes */
1026
+ break;
1027
+ }
1028
+ switch (*m) {
1029
+ case CR:
1030
+ /* val_end <- p - 1 */
1031
+ p = m; /* move forward by vlen bytes */
1032
+ state = SW_VAL_LF;
1033
+ break;
1034
+
1035
+ default:
1036
+ goto error;
1037
+ }
1038
+
1039
+ break;
1040
+
1041
+ case SW_VAL_LF:
1042
+ switch (ch) {
1043
+ case LF:
1044
+ state = SW_END;
1045
+ break;
1046
+
1047
+ default:
1048
+ goto error;
1049
+ }
1050
+
1051
+ break;
1052
+
1053
+ case SW_END:
1054
+ if (r->token == NULL) {
1055
+ if (ch != 'E') {
1056
+ goto error;
1057
+ }
1058
+ /* end_start <- p */
1059
+ r->token = p;
1060
+ } else if (ch == CR) {
1061
+ /* end_end <- p */
1062
+ m = r->token;
1063
+ r->token = NULL;
1064
+
1065
+ switch (p - m) {
1066
+ case 3:
1067
+ if (str4cmp(m, 'E', 'N', 'D', '\r')) {
1068
+ r->end = m;
1069
+ state = SW_ALMOST_DONE;
1070
+ }
1071
+ break;
1072
+
1073
+ default:
1074
+ goto error;
1075
+ }
1076
+ }
1077
+
1078
+ break;
1079
+
1080
+ case SW_RUNTO_CRLF:
1081
+ switch (ch) {
1082
+ case CR:
1083
+ if (r->type == MSG_RSP_MC_VALUE) {
1084
+ state = SW_RUNTO_VAL;
1085
+ } else {
1086
+ state = SW_ALMOST_DONE;
1087
+ }
1088
+
1089
+ break;
1090
+
1091
+ default:
1092
+ break;
1093
+ }
1094
+
1095
+ break;
1096
+
1097
+ case SW_CRLF:
1098
+ switch (ch) {
1099
+ case ' ':
1100
+ break;
1101
+
1102
+ case CR:
1103
+ state = SW_ALMOST_DONE;
1104
+ break;
1105
+
1106
+ default:
1107
+ goto error;
1108
+ }
1109
+
1110
+ break;
1111
+
1112
+ case SW_ALMOST_DONE:
1113
+ switch (ch) {
1114
+ case LF:
1115
+ /* rsp_end <- p */
1116
+ goto done;
1117
+
1118
+ default:
1119
+ goto error;
1120
+ }
1121
+
1122
+ break;
1123
+
1124
+ case SW_SENTINEL:
1125
+ default:
1126
+ NOT_REACHED();
1127
+ break;
1128
+
1129
+ }
1130
+ }
1131
+
1132
+ ASSERT(p == b->last);
1133
+ r->pos = p;
1134
+ r->state = state;
1135
+
1136
+ if (b->last == b->end && r->token != NULL) {
1137
+ r->pos = r->token;
1138
+ r->token = NULL;
1139
+ r->result = MSG_PARSE_REPAIR;
1140
+ } else {
1141
+ r->result = MSG_PARSE_AGAIN;
1142
+ }
1143
+
1144
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed rsp %"PRIu64" res %d "
1145
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
1146
+ r->state, r->pos - b->pos, b->last - b->pos);
1147
+ return;
1148
+
1149
+ done:
1150
+ ASSERT(r->type > MSG_UNKNOWN && r->type < MSG_SENTINEL);
1151
+ r->pos = p + 1;
1152
+ ASSERT(r->pos <= b->last);
1153
+ r->state = SW_START;
1154
+ r->token = NULL;
1155
+ r->result = MSG_PARSE_OK;
1156
+
1157
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed rsp %"PRIu64" res %d "
1158
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
1159
+ r->state, r->pos - b->pos, b->last - b->pos);
1160
+ return;
1161
+
1162
+ error:
1163
+ r->result = MSG_PARSE_ERROR;
1164
+ r->state = state;
1165
+ errno = EINVAL;
1166
+
1167
+ log_hexdump(LOG_INFO, b->pos, mbuf_length(b), "parsed bad rsp %"PRIu64" "
1168
+ "res %d type %d state %d", r->id, r->result, r->type,
1169
+ r->state);
1170
+ }
1171
+
1172
+ /*
1173
+ * Pre-split copy handler invoked when the request is a multi vector -
1174
+ * 'get' or 'gets' request and is about to be split into two requests
1175
+ */
1176
+ void
1177
+ memcache_pre_splitcopy(struct mbuf *mbuf, void *arg)
1178
+ {
1179
+ struct msg *r = arg; /* request vector */
1180
+ struct string get = string("get "); /* 'get ' string */
1181
+ struct string gets = string("gets "); /* 'gets ' string */
1182
+
1183
+ ASSERT(r->request);
1184
+ ASSERT(!r->redis);
1185
+ ASSERT(mbuf_empty(mbuf));
1186
+
1187
+ switch (r->type) {
1188
+ case MSG_REQ_MC_GET:
1189
+ mbuf_copy(mbuf, get.data, get.len);
1190
+ break;
1191
+
1192
+ case MSG_REQ_MC_GETS:
1193
+ mbuf_copy(mbuf, gets.data, gets.len);
1194
+ break;
1195
+
1196
+ default:
1197
+ NOT_REACHED();
1198
+ }
1199
+ }
1200
+
1201
+ /*
1202
+ * Post-split copy handler invoked when the request is a multi vector -
1203
+ * 'get' or 'gets' request and has already been split into two requests
1204
+ */
1205
+ rstatus_t
1206
+ memcache_post_splitcopy(struct msg *r)
1207
+ {
1208
+ struct mbuf *mbuf;
1209
+ struct string crlf = string(CRLF);
1210
+
1211
+ ASSERT(r->request);
1212
+ ASSERT(!r->redis);
1213
+ ASSERT(!STAILQ_EMPTY(&r->mhdr));
1214
+
1215
+ mbuf = STAILQ_LAST(&r->mhdr, mbuf, next);
1216
+ mbuf_copy(mbuf, crlf.data, crlf.len);
1217
+
1218
+ return NC_OK;
1219
+ }
1220
+
1221
+ /*
1222
+ * Pre-coalesce handler is invoked when the message is a response to
1223
+ * the fragmented multi vector request - 'get' or 'gets' and all the
1224
+ * responses to the fragmented request vector hasn't been received
1225
+ */
1226
+ void
1227
+ memcache_pre_coalesce(struct msg *r)
1228
+ {
1229
+ struct msg *pr = r->peer; /* peer request */
1230
+ struct mbuf *mbuf;
1231
+
1232
+ ASSERT(!r->request);
1233
+ ASSERT(pr->request);
1234
+
1235
+ if (pr->frag_id == 0) {
1236
+ /* do nothing, if not a response to a fragmented request */
1237
+ return;
1238
+ }
1239
+
1240
+ switch (r->type) {
1241
+
1242
+ case MSG_RSP_MC_VALUE:
1243
+ case MSG_RSP_MC_END:
1244
+
1245
+ /*
1246
+ * Readjust responses of the fragmented message vector by not
1247
+ * including the end marker for all but the last response
1248
+ */
1249
+
1250
+ if (pr->last_fragment) {
1251
+ break;
1252
+ }
1253
+
1254
+ ASSERT(r->end != NULL);
1255
+
1256
+ for (;;) {
1257
+ mbuf = STAILQ_LAST(&r->mhdr, mbuf, next);
1258
+ ASSERT(mbuf != NULL);
1259
+
1260
+ /*
1261
+ * We cannot assert that end marker points to the last mbuf
1262
+ * Consider a scenario where end marker points to the
1263
+ * penultimate mbuf and the last mbuf only contains spaces
1264
+ * and CRLF: mhdr -> [...END] -> [\r\n]
1265
+ */
1266
+
1267
+ if (r->end >= mbuf->pos && r->end < mbuf->last) {
1268
+ /* end marker is within this mbuf */
1269
+ r->mlen -= (uint32_t)(mbuf->last - r->end);
1270
+ mbuf->last = r->end;
1271
+ break;
1272
+ }
1273
+
1274
+ /* end marker is not in this mbuf */
1275
+ r->mlen -= mbuf_length(mbuf);
1276
+ mbuf_remove(&r->mhdr, mbuf);
1277
+ mbuf_put(mbuf);
1278
+ }
1279
+
1280
+ break;
1281
+
1282
+ default:
1283
+ /*
1284
+ * Valid responses for a fragmented requests are MSG_RSP_MC_VALUE or,
1285
+ * MSG_RSP_MC_END. For an invalid response, we send out SERVER_ERRROR
1286
+ * with EINVAL errno
1287
+ */
1288
+ mbuf = STAILQ_FIRST(&r->mhdr);
1289
+ log_hexdump(LOG_ERR, mbuf->pos, mbuf_length(mbuf), "rsp fragment "
1290
+ "with unknown type %d", r->type);
1291
+ pr->error = 1;
1292
+ pr->err = EINVAL;
1293
+ break;
1294
+ }
1295
+ }
1296
+
1297
+ /*
1298
+ * Post-coalesce handler is invoked when the message is a response to
1299
+ * the fragmented multi vector request - 'get' or 'gets' and all the
1300
+ * responses to the fragmented request vector has been received and
1301
+ * the fragmented request is consider to be done
1302
+ */
1303
+ void
1304
+ memcache_post_coalesce(struct msg *r)
1305
+ {
1306
+ }