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,155 @@
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
+ #ifndef _NC_PROTO_H_
19
+ #define _NC_PROTO_H_
20
+
21
+ #include <nc_core.h>
22
+
23
+ #ifdef NC_LITTLE_ENDIAN
24
+
25
+ #define str4cmp(m, c0, c1, c2, c3) \
26
+ (*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0))
27
+
28
+ #define str5cmp(m, c0, c1, c2, c3, c4) \
29
+ (str4cmp(m, c0, c1, c2, c3) && (m[4] == c4))
30
+
31
+ #define str6cmp(m, c0, c1, c2, c3, c4, c5) \
32
+ (str4cmp(m, c0, c1, c2, c3) && \
33
+ (((uint32_t *) m)[1] & 0xffff) == ((c5 << 8) | c4))
34
+
35
+ #define str7cmp(m, c0, c1, c2, c3, c4, c5, c6) \
36
+ (str6cmp(m, c0, c1, c2, c3, c4, c5) && (m[6] == c6))
37
+
38
+ #define str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
39
+ (str4cmp(m, c0, c1, c2, c3) && \
40
+ (((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)))
41
+
42
+ #define str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
43
+ (str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && m[8] == c8)
44
+
45
+ #define str10cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) \
46
+ (str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && \
47
+ (((uint32_t *) m)[2] & 0xffff) == ((c9 << 8) | c8))
48
+
49
+ #define str11cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) \
50
+ (str10cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) && (m[10] == c10))
51
+
52
+ #define str12cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) \
53
+ (str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && \
54
+ (((uint32_t *) m)[2] == ((c11 << 24) | (c10 << 16) | (c9 << 8) | c8)))
55
+
56
+ #else
57
+
58
+ #define str4cmp(m, c0, c1, c2, c3) \
59
+ (m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3)
60
+
61
+ #define str5cmp(m, c0, c1, c2, c3, c4) \
62
+ (str4cmp(m, c0, c1, c2, c3) && (m[4] == c4))
63
+
64
+ #define str6cmp(m, c0, c1, c2, c3, c4, c5) \
65
+ (str5cmp(m, c0, c1, c2, c3, c4) && m[5] == c5)
66
+
67
+ #define str7cmp(m, c0, c1, c2, c3, c4, c5, c6) \
68
+ (str6cmp(m, c0, c1, c2, c3, c4, c5) && m[6] == c6)
69
+
70
+ #define str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
71
+ (str7cmp(m, c0, c1, c2, c3, c4, c5, c6) && m[7] == c7)
72
+
73
+ #define str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
74
+ (str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && m[8] == c8)
75
+
76
+ #define str10cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) \
77
+ (str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) && m[9] == c9)
78
+
79
+ #define str11cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) \
80
+ (str10cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) && m[10] == c10)
81
+
82
+ #define str12cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) \
83
+ (str11cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) && m[11] == c11)
84
+
85
+ #endif
86
+
87
+ #define str3icmp(m, c0, c1, c2) \
88
+ ((m[0] == c0 || m[0] == (c0 ^ 0x20)) && \
89
+ (m[1] == c1 || m[1] == (c1 ^ 0x20)) && \
90
+ (m[2] == c2 || m[2] == (c2 ^ 0x20)))
91
+
92
+ #define str4icmp(m, c0, c1, c2, c3) \
93
+ (str3icmp(m, c0, c1, c2) && (m[3] == c3 || m[3] == (c3 ^ 0x20)))
94
+
95
+ #define str5icmp(m, c0, c1, c2, c3, c4) \
96
+ (str4icmp(m, c0, c1, c2, c3) && (m[4] == c4 || m[4] == (c4 ^ 0x20)))
97
+
98
+ #define str6icmp(m, c0, c1, c2, c3, c4, c5) \
99
+ (str5icmp(m, c0, c1, c2, c3, c4) && (m[5] == c5 || m[5] == (c5 ^ 0x20)))
100
+
101
+ #define str7icmp(m, c0, c1, c2, c3, c4, c5, c6) \
102
+ (str6icmp(m, c0, c1, c2, c3, c4, c5) && \
103
+ (m[6] == c6 || m[6] == (c6 ^ 0x20)))
104
+
105
+ #define str8icmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
106
+ (str7icmp(m, c0, c1, c2, c3, c4, c5, c6) && \
107
+ (m[7] == c7 || m[7] == (c7 ^ 0x20)))
108
+
109
+ #define str9icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
110
+ (str8icmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && \
111
+ (m[8] == c8 || m[8] == (c8 ^ 0x20)))
112
+
113
+ #define str10icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) \
114
+ (str9icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) && \
115
+ (m[9] == c9 || m[9] == (c9 ^ 0x20)))
116
+
117
+ #define str11icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) \
118
+ (str10icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) && \
119
+ (m[10] == c10 || m[10] == (c10 ^ 0x20)))
120
+
121
+ #define str12icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) \
122
+ (str11icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) && \
123
+ (m[11] == c11 || m[11] == (c11 ^ 0x20)))
124
+
125
+ #define str13icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12) \
126
+ (str12icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) && \
127
+ (m[12] == c12 || m[12] == (c12 ^ 0x20)))
128
+
129
+ #define str14icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) \
130
+ (str13icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12) && \
131
+ (m[13] == c13 || m[13] == (c13 ^ 0x20)))
132
+
133
+ #define str15icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14) \
134
+ (str14icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) && \
135
+ (m[14] == c14 || m[14] == (c14 ^ 0x20)))
136
+
137
+ #define str16icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15) \
138
+ (str15icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14) && \
139
+ (m[15] == c15 || m[15] == (c15 ^ 0x20)))
140
+
141
+ void memcache_parse_req(struct msg *r);
142
+ void memcache_parse_rsp(struct msg *r);
143
+ void memcache_pre_splitcopy(struct mbuf *mbuf, void *arg);
144
+ rstatus_t memcache_post_splitcopy(struct msg *r);
145
+ void memcache_pre_coalesce(struct msg *r);
146
+ void memcache_post_coalesce(struct msg *r);
147
+
148
+ void redis_parse_req(struct msg *r);
149
+ void redis_parse_rsp(struct msg *r);
150
+ void redis_pre_splitcopy(struct mbuf *mbuf, void *arg);
151
+ rstatus_t redis_post_splitcopy(struct msg *r);
152
+ void redis_pre_coalesce(struct msg *r);
153
+ void redis_post_coalesce(struct msg *r);
154
+
155
+ #endif
@@ -0,0 +1,2102 @@
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 <stdio.h>
19
+ #include <ctype.h>
20
+
21
+ #include <nc_core.h>
22
+ #include <nc_proto.h>
23
+
24
+ /*
25
+ * Return true, if the redis command accepts no arguments, otherwise
26
+ * return false
27
+ */
28
+ static bool
29
+ redis_arg0(struct msg *r)
30
+ {
31
+ switch (r->type) {
32
+ case MSG_REQ_REDIS_EXISTS:
33
+ case MSG_REQ_REDIS_PERSIST:
34
+ case MSG_REQ_REDIS_PTTL:
35
+ case MSG_REQ_REDIS_TTL:
36
+ case MSG_REQ_REDIS_TYPE:
37
+
38
+ case MSG_REQ_REDIS_DECR:
39
+ case MSG_REQ_REDIS_GET:
40
+ case MSG_REQ_REDIS_INCR:
41
+ case MSG_REQ_REDIS_STRLEN:
42
+
43
+ case MSG_REQ_REDIS_HGETALL:
44
+ case MSG_REQ_REDIS_HKEYS:
45
+ case MSG_REQ_REDIS_HLEN:
46
+ case MSG_REQ_REDIS_HVALS:
47
+
48
+ case MSG_REQ_REDIS_LLEN:
49
+ case MSG_REQ_REDIS_LPOP:
50
+ case MSG_REQ_REDIS_RPOP:
51
+
52
+ case MSG_REQ_REDIS_SCARD:
53
+ case MSG_REQ_REDIS_SMEMBERS:
54
+ case MSG_REQ_REDIS_SPOP:
55
+ case MSG_REQ_REDIS_SRANDMEMBER:
56
+
57
+ case MSG_REQ_REDIS_ZCARD:
58
+ return true;
59
+
60
+ default:
61
+ break;
62
+ }
63
+
64
+ return false;
65
+ }
66
+
67
+ /*
68
+ * Return true, if the redis command accepts exactly 1 argument, otherwise
69
+ * return false
70
+ */
71
+ static bool
72
+ redis_arg1(struct msg *r)
73
+ {
74
+ switch (r->type) {
75
+ case MSG_REQ_REDIS_EXPIRE:
76
+ case MSG_REQ_REDIS_EXPIREAT:
77
+ case MSG_REQ_REDIS_PEXPIRE:
78
+ case MSG_REQ_REDIS_PEXPIREAT:
79
+
80
+ case MSG_REQ_REDIS_APPEND:
81
+ case MSG_REQ_REDIS_DECRBY:
82
+ case MSG_REQ_REDIS_GETBIT:
83
+ case MSG_REQ_REDIS_GETSET:
84
+ case MSG_REQ_REDIS_INCRBY:
85
+ case MSG_REQ_REDIS_INCRBYFLOAT:
86
+ case MSG_REQ_REDIS_SET:
87
+ case MSG_REQ_REDIS_SETNX:
88
+
89
+ case MSG_REQ_REDIS_HEXISTS:
90
+ case MSG_REQ_REDIS_HGET:
91
+
92
+ case MSG_REQ_REDIS_LINDEX:
93
+ case MSG_REQ_REDIS_LPUSHX:
94
+ case MSG_REQ_REDIS_RPOPLPUSH:
95
+ case MSG_REQ_REDIS_RPUSHX:
96
+
97
+ case MSG_REQ_REDIS_SISMEMBER:
98
+
99
+ case MSG_REQ_REDIS_ZRANK:
100
+ case MSG_REQ_REDIS_ZREVRANK:
101
+ case MSG_REQ_REDIS_ZSCORE:
102
+ return true;
103
+
104
+ default:
105
+ break;
106
+ }
107
+
108
+ return false;
109
+ }
110
+
111
+ /*
112
+ * Return true, if the redis command accepts exactly 2 arguments, otherwise
113
+ * return false
114
+ */
115
+ static bool
116
+ redis_arg2(struct msg *r)
117
+ {
118
+ switch (r->type) {
119
+ case MSG_REQ_REDIS_GETRANGE:
120
+ case MSG_REQ_REDIS_PSETEX:
121
+ case MSG_REQ_REDIS_SETBIT:
122
+ case MSG_REQ_REDIS_SETEX:
123
+ case MSG_REQ_REDIS_SETRANGE:
124
+
125
+ case MSG_REQ_REDIS_HINCRBY:
126
+ case MSG_REQ_REDIS_HINCRBYFLOAT:
127
+ case MSG_REQ_REDIS_HSET:
128
+ case MSG_REQ_REDIS_HSETNX:
129
+
130
+ case MSG_REQ_REDIS_LRANGE:
131
+ case MSG_REQ_REDIS_LREM:
132
+ case MSG_REQ_REDIS_LSET:
133
+ case MSG_REQ_REDIS_LTRIM:
134
+
135
+ case MSG_REQ_REDIS_SMOVE:
136
+
137
+ case MSG_REQ_REDIS_ZCOUNT:
138
+ case MSG_REQ_REDIS_ZINCRBY:
139
+ case MSG_REQ_REDIS_ZREMRANGEBYRANK:
140
+ case MSG_REQ_REDIS_ZREMRANGEBYSCORE:
141
+ return true;
142
+
143
+ default:
144
+ break;
145
+ }
146
+
147
+ return false;
148
+ }
149
+
150
+ /*
151
+ * Return true, if the redis command accepts exactly 3 arguments, otherwise
152
+ * return false
153
+ */
154
+ static bool
155
+ redis_arg3(struct msg *r)
156
+ {
157
+ switch (r->type) {
158
+ case MSG_REQ_REDIS_LINSERT:
159
+ return true;
160
+
161
+ default:
162
+ break;
163
+ }
164
+
165
+ return false;
166
+ }
167
+
168
+ /*
169
+ * Return true, if the redis command accepts 0 or more arguments, otherwise
170
+ * return false
171
+ */
172
+ static bool
173
+ redis_argn(struct msg *r)
174
+ {
175
+ switch (r->type) {
176
+ case MSG_REQ_REDIS_BITCOUNT:
177
+
178
+ case MSG_REQ_REDIS_HDEL:
179
+ case MSG_REQ_REDIS_HMGET:
180
+ case MSG_REQ_REDIS_HMSET:
181
+
182
+ case MSG_REQ_REDIS_LPUSH:
183
+ case MSG_REQ_REDIS_RPUSH:
184
+
185
+ case MSG_REQ_REDIS_SADD:
186
+ case MSG_REQ_REDIS_SDIFF:
187
+ case MSG_REQ_REDIS_SDIFFSTORE:
188
+ case MSG_REQ_REDIS_SINTER:
189
+ case MSG_REQ_REDIS_SINTERSTORE:
190
+ case MSG_REQ_REDIS_SREM:
191
+ case MSG_REQ_REDIS_SUNION:
192
+ case MSG_REQ_REDIS_SUNIONSTORE:
193
+
194
+ case MSG_REQ_REDIS_ZADD:
195
+ case MSG_REQ_REDIS_ZINTERSTORE:
196
+ case MSG_REQ_REDIS_ZRANGE:
197
+ case MSG_REQ_REDIS_ZRANGEBYSCORE:
198
+ case MSG_REQ_REDIS_ZREM:
199
+ case MSG_REQ_REDIS_ZREVRANGE:
200
+ case MSG_REQ_REDIS_ZREVRANGEBYSCORE:
201
+ case MSG_REQ_REDIS_ZUNIONSTORE:
202
+ return true;
203
+
204
+ default:
205
+ break;
206
+ }
207
+
208
+ return false;
209
+ }
210
+
211
+ /*
212
+ * Return true, if the redis command is a vector command accepting one or
213
+ * more keys, otherwise return false
214
+ */
215
+ static bool
216
+ redis_argx(struct msg *r)
217
+ {
218
+ switch (r->type) {
219
+ case MSG_REQ_REDIS_MGET:
220
+ case MSG_REQ_REDIS_DEL:
221
+ return true;
222
+
223
+ default:
224
+ break;
225
+ }
226
+
227
+ return false;
228
+ }
229
+
230
+ /*
231
+ * Return true, if the redis command is either EVAL or EVALSHA. These commands
232
+ * have a special format with exactly 2 arguments, followed by one or more keys,
233
+ * followed by zero or more arguments (the documentation online seems to suggest
234
+ * that at least one argument is required, but that shouldn't be the case).
235
+ */
236
+ static bool
237
+ redis_argeval(struct msg *r)
238
+ {
239
+ switch (r->type) {
240
+ case MSG_REQ_REDIS_EVAL:
241
+ case MSG_REQ_REDIS_EVALSHA:
242
+ return true;
243
+
244
+ default:
245
+ break;
246
+ }
247
+
248
+ return false;
249
+ }
250
+
251
+ /*
252
+ * Reference: http://redis.io/topics/protocol
253
+ *
254
+ * Redis >= 1.2 uses the unified protocol to send requests to the Redis
255
+ * server. In the unified protocol all the arguments sent to the server
256
+ * are binary safe and every request has the following general form:
257
+ *
258
+ * *<number of arguments> CR LF
259
+ * $<number of bytes of argument 1> CR LF
260
+ * <argument data> CR LF
261
+ * ...
262
+ * $<number of bytes of argument N> CR LF
263
+ * <argument data> CR LF
264
+ *
265
+ * Before the unified request protocol, redis protocol for requests supported
266
+ * the following commands
267
+ * 1). Inline commands: simple commands where arguments are just space
268
+ * separated strings. No binary safeness is possible.
269
+ * 2). Bulk commands: bulk commands are exactly like inline commands, but
270
+ * the last argument is handled in a special way in order to allow for
271
+ * a binary-safe last argument.
272
+ *
273
+ * Nutcracker only supports the Redis unified protocol for requests.
274
+ */
275
+ void
276
+ redis_parse_req(struct msg *r)
277
+ {
278
+ struct mbuf *b;
279
+ uint8_t *p, *m;
280
+ uint8_t ch;
281
+ enum {
282
+ SW_START,
283
+ SW_NARG,
284
+ SW_NARG_LF,
285
+ SW_REQ_TYPE_LEN,
286
+ SW_REQ_TYPE_LEN_LF,
287
+ SW_REQ_TYPE,
288
+ SW_REQ_TYPE_LF,
289
+ SW_KEY_LEN,
290
+ SW_KEY_LEN_LF,
291
+ SW_KEY,
292
+ SW_KEY_LF,
293
+ SW_ARG1_LEN,
294
+ SW_ARG1_LEN_LF,
295
+ SW_ARG1,
296
+ SW_ARG1_LF,
297
+ SW_ARG2_LEN,
298
+ SW_ARG2_LEN_LF,
299
+ SW_ARG2,
300
+ SW_ARG2_LF,
301
+ SW_ARG3_LEN,
302
+ SW_ARG3_LEN_LF,
303
+ SW_ARG3,
304
+ SW_ARG3_LF,
305
+ SW_ARGN_LEN,
306
+ SW_ARGN_LEN_LF,
307
+ SW_ARGN,
308
+ SW_ARGN_LF,
309
+ SW_FRAGMENT,
310
+ SW_SENTINEL
311
+ } state;
312
+
313
+ state = r->state;
314
+ b = STAILQ_LAST(&r->mhdr, mbuf, next);
315
+
316
+ ASSERT(r->request);
317
+ ASSERT(state >= SW_START && state < SW_SENTINEL);
318
+ ASSERT(b != NULL);
319
+ ASSERT(b->pos <= b->last);
320
+
321
+ /* validate the parsing maker */
322
+ ASSERT(r->pos != NULL);
323
+ ASSERT(r->pos >= b->pos && r->pos <= b->last);
324
+
325
+ for (p = r->pos; p < b->last; p++) {
326
+ ch = *p;
327
+
328
+ switch (state) {
329
+
330
+ case SW_START:
331
+ case SW_NARG:
332
+ if (r->token == NULL) {
333
+ if (ch != '*') {
334
+ goto error;
335
+ }
336
+ r->token = p;
337
+ /* req_start <- p */
338
+ r->narg_start = p;
339
+ r->rnarg = 0;
340
+ state = SW_NARG;
341
+ } else if (isdigit(ch)) {
342
+ r->rnarg = r->rnarg * 10 + (uint32_t)(ch - '0');
343
+ } else if (ch == CR) {
344
+ if (r->rnarg == 0) {
345
+ goto error;
346
+ }
347
+ r->narg = r->rnarg;
348
+ r->narg_end = p;
349
+ r->token = NULL;
350
+ state = SW_NARG_LF;
351
+ } else {
352
+ goto error;
353
+ }
354
+
355
+ break;
356
+
357
+ case SW_NARG_LF:
358
+ switch (ch) {
359
+ case LF:
360
+ state = SW_REQ_TYPE_LEN;
361
+ break;
362
+
363
+ default:
364
+ goto error;
365
+ }
366
+
367
+ break;
368
+
369
+ case SW_REQ_TYPE_LEN:
370
+ if (r->token == NULL) {
371
+ if (ch != '$') {
372
+ goto error;
373
+ }
374
+ r->token = p;
375
+ r->rlen = 0;
376
+ } else if (isdigit(ch)) {
377
+ r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
378
+ } else if (ch == CR) {
379
+ if (r->rlen == 0 || r->rnarg == 0) {
380
+ goto error;
381
+ }
382
+ r->rnarg--;
383
+ r->token = NULL;
384
+ state = SW_REQ_TYPE_LEN_LF;
385
+ } else {
386
+ goto error;
387
+ }
388
+
389
+ break;
390
+
391
+ case SW_REQ_TYPE_LEN_LF:
392
+ switch (ch) {
393
+ case LF:
394
+ state = SW_REQ_TYPE;
395
+ break;
396
+
397
+ default:
398
+ goto error;
399
+ }
400
+
401
+ break;
402
+
403
+ case SW_REQ_TYPE:
404
+ if (r->token == NULL) {
405
+ r->token = p;
406
+ }
407
+
408
+ m = r->token + r->rlen;
409
+ if (m >= b->last) {
410
+ m = b->last - 1;
411
+ p = m;
412
+ break;
413
+ }
414
+
415
+ if (*m != CR) {
416
+ goto error;
417
+ }
418
+
419
+ p = m; /* move forward by rlen bytes */
420
+ r->rlen = 0;
421
+ m = r->token;
422
+ r->token = NULL;
423
+ r->type = MSG_UNKNOWN;
424
+
425
+ switch (p - m) {
426
+
427
+ case 3:
428
+ if (str3icmp(m, 'g', 'e', 't')) {
429
+ r->type = MSG_REQ_REDIS_GET;
430
+ break;
431
+ }
432
+
433
+ if (str3icmp(m, 's', 'e', 't')) {
434
+ r->type = MSG_REQ_REDIS_SET;
435
+ break;
436
+ }
437
+
438
+ if (str3icmp(m, 't', 't', 'l')) {
439
+ r->type = MSG_REQ_REDIS_TTL;
440
+ break;
441
+ }
442
+
443
+ if (str3icmp(m, 'd', 'e', 'l')) {
444
+ r->type = MSG_REQ_REDIS_DEL;
445
+ break;
446
+ }
447
+
448
+ break;
449
+
450
+ case 4:
451
+ if (str4icmp(m, 'p', 't', 't', 'l')) {
452
+ r->type = MSG_REQ_REDIS_PTTL;
453
+ break;
454
+ }
455
+
456
+ if (str4icmp(m, 'd', 'e', 'c', 'r')) {
457
+ r->type = MSG_REQ_REDIS_DECR;
458
+ break;
459
+ }
460
+
461
+ if (str4icmp(m, 'h', 'd', 'e', 'l')) {
462
+ r->type = MSG_REQ_REDIS_HDEL;
463
+ break;
464
+ }
465
+
466
+ if (str4icmp(m, 'h', 'g', 'e', 't')) {
467
+ r->type = MSG_REQ_REDIS_HGET;
468
+ break;
469
+ }
470
+
471
+ if (str4icmp(m, 'h', 'l', 'e', 'n')) {
472
+ r->type = MSG_REQ_REDIS_HLEN;
473
+ break;
474
+ }
475
+
476
+ if (str4icmp(m, 'h', 's', 'e', 't')) {
477
+ r->type = MSG_REQ_REDIS_HSET;
478
+ break;
479
+ }
480
+
481
+ if (str4icmp(m, 'i', 'n', 'c', 'r')) {
482
+ r->type = MSG_REQ_REDIS_INCR;
483
+ break;
484
+ }
485
+
486
+ if (str4icmp(m, 'l', 'l', 'e', 'n')) {
487
+ r->type = MSG_REQ_REDIS_LLEN;
488
+ break;
489
+ }
490
+
491
+ if (str4icmp(m, 'l', 'p', 'o', 'p')) {
492
+ r->type = MSG_REQ_REDIS_LPOP;
493
+ break;
494
+ }
495
+
496
+ if (str4icmp(m, 'l', 'r', 'e', 'm')) {
497
+ r->type = MSG_REQ_REDIS_LREM;
498
+ break;
499
+ }
500
+
501
+ if (str4icmp(m, 'l', 's', 'e', 't')) {
502
+ r->type = MSG_REQ_REDIS_LSET;
503
+ break;
504
+ }
505
+
506
+ if (str4icmp(m, 'r', 'p', 'o', 'p')) {
507
+ r->type = MSG_REQ_REDIS_RPOP;
508
+ break;
509
+ }
510
+
511
+ if (str4icmp(m, 's', 'a', 'd', 'd')) {
512
+ r->type = MSG_REQ_REDIS_SADD;
513
+ break;
514
+ }
515
+
516
+ if (str4icmp(m, 's', 'p', 'o', 'p')) {
517
+ r->type = MSG_REQ_REDIS_SPOP;
518
+ break;
519
+ }
520
+
521
+ if (str4icmp(m, 's', 'r', 'e', 'm')) {
522
+ r->type = MSG_REQ_REDIS_SREM;
523
+ break;
524
+ }
525
+
526
+ if (str4icmp(m, 't', 'y', 'p', 'e')) {
527
+ r->type = MSG_REQ_REDIS_TYPE;
528
+ break;
529
+ }
530
+
531
+ if (str4icmp(m, 'm', 'g', 'e', 't')) {
532
+ r->type = MSG_REQ_REDIS_MGET;
533
+ break;
534
+ }
535
+
536
+ if (str4icmp(m, 'z', 'a', 'd', 'd')) {
537
+ r->type = MSG_REQ_REDIS_ZADD;
538
+ break;
539
+ }
540
+
541
+ if (str4icmp(m, 'z', 'r', 'e', 'm')) {
542
+ r->type = MSG_REQ_REDIS_ZREM;
543
+ break;
544
+ }
545
+
546
+ if (str4icmp(m, 'e', 'v', 'a', 'l')) {
547
+ r->type = MSG_REQ_REDIS_EVAL;
548
+ break;
549
+ }
550
+
551
+ break;
552
+
553
+ case 5:
554
+ if (str5icmp(m, 'h', 'k', 'e', 'y', 's')) {
555
+ r->type = MSG_REQ_REDIS_HKEYS;
556
+ break;
557
+ }
558
+
559
+ if (str5icmp(m, 'h', 'm', 'g', 'e', 't')) {
560
+ r->type = MSG_REQ_REDIS_HMGET;
561
+ break;
562
+ }
563
+
564
+ if (str5icmp(m, 'h', 'm', 's', 'e', 't')) {
565
+ r->type = MSG_REQ_REDIS_HMSET;
566
+ break;
567
+ }
568
+
569
+ if (str5icmp(m, 'h', 'v', 'a', 'l', 's')) {
570
+ r->type = MSG_REQ_REDIS_HVALS;
571
+ break;
572
+ }
573
+
574
+ if (str5icmp(m, 'l', 'p', 'u', 's', 'h')) {
575
+ r->type = MSG_REQ_REDIS_LPUSH;
576
+ break;
577
+ }
578
+
579
+ if (str5icmp(m, 'l', 't', 'r', 'i', 'm')) {
580
+ r->type = MSG_REQ_REDIS_LTRIM;
581
+ break;
582
+ }
583
+
584
+ if (str5icmp(m, 'r', 'p', 'u', 's', 'h')) {
585
+ r->type = MSG_REQ_REDIS_RPUSH;
586
+ break;
587
+ }
588
+
589
+ if (str5icmp(m, 's', 'c', 'a', 'r', 'd')) {
590
+ r->type = MSG_REQ_REDIS_SCARD;
591
+ break;
592
+ }
593
+
594
+ if (str5icmp(m, 's', 'd', 'i', 'f', 'f')) {
595
+ r->type = MSG_REQ_REDIS_SDIFF;
596
+ break;
597
+ }
598
+
599
+ if (str5icmp(m, 's', 'e', 't', 'e', 'x')) {
600
+ r->type = MSG_REQ_REDIS_SETEX;
601
+ break;
602
+ }
603
+
604
+ if (str5icmp(m, 's', 'e', 't', 'n', 'x')) {
605
+ r->type = MSG_REQ_REDIS_SETNX;
606
+ break;
607
+ }
608
+
609
+ if (str5icmp(m, 's', 'm', 'o', 'v', 'e')) {
610
+ r->type = MSG_REQ_REDIS_SMOVE;
611
+ break;
612
+ }
613
+
614
+ if (str5icmp(m, 'z', 'c', 'a', 'r', 'd')) {
615
+ r->type = MSG_REQ_REDIS_ZCARD;
616
+ break;
617
+ }
618
+
619
+ if (str5icmp(m, 'z', 'r', 'a', 'n', 'k')) {
620
+ r->type = MSG_REQ_REDIS_ZRANK;
621
+ break;
622
+ }
623
+
624
+ break;
625
+
626
+ case 6:
627
+ if (str6icmp(m, 'a', 'p', 'p', 'e', 'n', 'd')) {
628
+ r->type = MSG_REQ_REDIS_APPEND;
629
+ break;
630
+ }
631
+
632
+ if (str6icmp(m, 'd', 'e', 'c', 'r', 'b', 'y')) {
633
+ r->type = MSG_REQ_REDIS_DECRBY;
634
+ break;
635
+ }
636
+
637
+ if (str6icmp(m, 'e', 'x', 'i', 's', 't', 's')) {
638
+ r->type = MSG_REQ_REDIS_EXISTS;
639
+ break;
640
+ }
641
+
642
+ if (str6icmp(m, 'e', 'x', 'p', 'i', 'r', 'e')) {
643
+ r->type = MSG_REQ_REDIS_EXPIRE;
644
+ break;
645
+ }
646
+
647
+ if (str6icmp(m, 'g', 'e', 't', 'b', 'i', 't')) {
648
+ r->type = MSG_REQ_REDIS_GETBIT;
649
+ break;
650
+ }
651
+
652
+ if (str6icmp(m, 'g', 'e', 't', 's', 'e', 't')) {
653
+ r->type = MSG_REQ_REDIS_GETSET;
654
+ break;
655
+ }
656
+
657
+ if (str6icmp(m, 'p', 's', 'e', 't', 'e', 'x')) {
658
+ r->type = MSG_REQ_REDIS_PSETEX;
659
+ break;
660
+ }
661
+
662
+ if (str6icmp(m, 'h', 's', 'e', 't', 'n', 'x')) {
663
+ r->type = MSG_REQ_REDIS_HSETNX;
664
+ break;
665
+ }
666
+
667
+ if (str6icmp(m, 'i', 'n', 'c', 'r', 'b', 'y')) {
668
+ r->type = MSG_REQ_REDIS_INCRBY;
669
+ break;
670
+ }
671
+
672
+ if (str6icmp(m, 'l', 'i', 'n', 'd', 'e', 'x')) {
673
+ r->type = MSG_REQ_REDIS_LINDEX;
674
+ break;
675
+ }
676
+
677
+ if (str6icmp(m, 'l', 'p', 'u', 's', 'h', 'x')) {
678
+ r->type = MSG_REQ_REDIS_LPUSHX;
679
+ break;
680
+ }
681
+
682
+ if (str6icmp(m, 'l', 'r', 'a', 'n', 'g', 'e')) {
683
+ r->type = MSG_REQ_REDIS_LRANGE;
684
+ break;
685
+ }
686
+
687
+ if (str6icmp(m, 'r', 'p', 'u', 's', 'h', 'x')) {
688
+ r->type = MSG_REQ_REDIS_RPUSHX;
689
+ break;
690
+ }
691
+
692
+ if (str6icmp(m, 's', 'e', 't', 'b', 'i', 't')) {
693
+ r->type = MSG_REQ_REDIS_SETBIT;
694
+ break;
695
+ }
696
+
697
+ if (str6icmp(m, 's', 'i', 'n', 't', 'e', 'r')) {
698
+ r->type = MSG_REQ_REDIS_SINTER;
699
+ break;
700
+ }
701
+
702
+ if (str6icmp(m, 's', 't', 'r', 'l', 'e', 'n')) {
703
+ r->type = MSG_REQ_REDIS_STRLEN;
704
+ break;
705
+ }
706
+
707
+ if (str6icmp(m, 's', 'u', 'n', 'i', 'o', 'n')) {
708
+ r->type = MSG_REQ_REDIS_SUNION;
709
+ break;
710
+ }
711
+
712
+ if (str6icmp(m, 'z', 'c', 'o', 'u', 'n', 't')) {
713
+ r->type = MSG_REQ_REDIS_ZCOUNT;
714
+ break;
715
+ }
716
+
717
+ if (str6icmp(m, 'z', 'r', 'a', 'n', 'g', 'e')) {
718
+ r->type = MSG_REQ_REDIS_ZRANGE;
719
+ break;
720
+ }
721
+
722
+ if (str6icmp(m, 'z', 's', 'c', 'o', 'r', 'e')) {
723
+ r->type = MSG_REQ_REDIS_ZSCORE;
724
+ break;
725
+ }
726
+
727
+ break;
728
+
729
+ case 7:
730
+ if (str7icmp(m, 'p', 'e', 'r', 's', 'i', 's', 't')) {
731
+ r->type = MSG_REQ_REDIS_PERSIST;
732
+ break;
733
+ }
734
+
735
+ if (str7icmp(m, 'p', 'e', 'x', 'p', 'i', 'r', 'e')) {
736
+ r->type = MSG_REQ_REDIS_PEXPIRE;
737
+ break;
738
+ }
739
+
740
+ if (str7icmp(m, 'h', 'e', 'x', 'i', 's', 't', 's')) {
741
+ r->type = MSG_REQ_REDIS_HEXISTS;
742
+ break;
743
+ }
744
+
745
+ if (str7icmp(m, 'h', 'g', 'e', 't', 'a', 'l', 'l')) {
746
+ r->type = MSG_REQ_REDIS_HGETALL;
747
+ break;
748
+ }
749
+
750
+ if (str7icmp(m, 'h', 'i', 'n', 'c', 'r', 'b', 'y')) {
751
+ r->type = MSG_REQ_REDIS_HINCRBY;
752
+ break;
753
+ }
754
+
755
+ if (str7icmp(m, 'l', 'i', 'n', 's', 'e', 'r', 't')) {
756
+ r->type = MSG_REQ_REDIS_LINSERT;
757
+ break;
758
+ }
759
+
760
+ if (str7icmp(m, 'z', 'i', 'n', 'c', 'r', 'b', 'y')) {
761
+ r->type = MSG_REQ_REDIS_ZINCRBY;
762
+ break;
763
+ }
764
+
765
+ if (str7icmp(m, 'e', 'v', 'a', 'l', 's', 'h', 'a')) {
766
+ r->type = MSG_REQ_REDIS_EVALSHA;
767
+ break;
768
+ }
769
+
770
+ break;
771
+
772
+ case 8:
773
+ if (str8icmp(m, 'e', 'x', 'p', 'i', 'r', 'e', 'a', 't')) {
774
+ r->type = MSG_REQ_REDIS_EXPIREAT;
775
+ break;
776
+ }
777
+
778
+ if (str8icmp(m, 'b', 'i', 't', 'c', 'o', 'u', 'n', 't')) {
779
+ r->type = MSG_REQ_REDIS_BITCOUNT;
780
+ break;
781
+ }
782
+
783
+ if (str8icmp(m, 'g', 'e', 't', 'r', 'a', 'n', 'g', 'e')) {
784
+ r->type = MSG_REQ_REDIS_GETRANGE;
785
+ break;
786
+ }
787
+
788
+ if (str8icmp(m, 's', 'e', 't', 'r', 'a', 'n', 'g', 'e')) {
789
+ r->type = MSG_REQ_REDIS_SETRANGE;
790
+ break;
791
+ }
792
+
793
+ if (str8icmp(m, 's', 'm', 'e', 'm', 'b', 'e', 'r', 's')) {
794
+ r->type = MSG_REQ_REDIS_SMEMBERS;
795
+ break;
796
+ }
797
+
798
+ if (str8icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'k')) {
799
+ r->type = MSG_REQ_REDIS_ZREVRANK;
800
+ break;
801
+ }
802
+
803
+ break;
804
+
805
+ case 9:
806
+ if (str9icmp(m, 'p', 'e', 'x', 'p', 'i', 'r', 'e', 'a', 't')) {
807
+ r->type = MSG_REQ_REDIS_PEXPIREAT;
808
+ break;
809
+ }
810
+
811
+ if (str9icmp(m, 'r', 'p', 'o', 'p', 'l', 'p', 'u', 's', 'h')) {
812
+ r->type = MSG_REQ_REDIS_RPOPLPUSH;
813
+ break;
814
+ }
815
+
816
+ if (str9icmp(m, 's', 'i', 's', 'm', 'e', 'm', 'b', 'e', 'r')) {
817
+ r->type = MSG_REQ_REDIS_SISMEMBER;
818
+ break;
819
+ }
820
+
821
+ if (str9icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'g', 'e')) {
822
+ r->type = MSG_REQ_REDIS_ZREVRANGE;
823
+ break;
824
+ }
825
+
826
+ break;
827
+
828
+ case 10:
829
+ if (str10icmp(m, 's', 'd', 'i', 'f', 'f', 's', 't', 'o', 'r', 'e')) {
830
+ r->type = MSG_REQ_REDIS_SDIFFSTORE;
831
+ break;
832
+ }
833
+
834
+ case 11:
835
+ if (str11icmp(m, 'i', 'n', 'c', 'r', 'b', 'y', 'f', 'l', 'o', 'a', 't')) {
836
+ r->type = MSG_REQ_REDIS_INCRBYFLOAT;
837
+ break;
838
+ }
839
+
840
+ if (str11icmp(m, 's', 'i', 'n', 't', 'e', 'r', 's', 't', 'o', 'r', 'e')) {
841
+ r->type = MSG_REQ_REDIS_SINTERSTORE;
842
+ break;
843
+ }
844
+
845
+ if (str11icmp(m, 's', 'r', 'a', 'n', 'd', 'm', 'e', 'm', 'b', 'e', 'r')) {
846
+ r->type = MSG_REQ_REDIS_SRANDMEMBER;
847
+ break;
848
+ }
849
+
850
+ if (str11icmp(m, 's', 'u', 'n', 'i', 'o', 'n', 's', 't', 'o', 'r', 'e')) {
851
+ r->type = MSG_REQ_REDIS_SUNIONSTORE;
852
+ break;
853
+ }
854
+
855
+ if (str11icmp(m, 'z', 'i', 'n', 't', 'e', 'r', 's', 't', 'o', 'r', 'e')) {
856
+ r->type = MSG_REQ_REDIS_ZINTERSTORE;
857
+ break;
858
+ }
859
+
860
+ if (str11icmp(m, 'z', 'u', 'n', 'i', 'o', 'n', 's', 't', 'o', 'r', 'e')) {
861
+ r->type = MSG_REQ_REDIS_ZUNIONSTORE;
862
+ break;
863
+ }
864
+
865
+ break;
866
+
867
+ case 12:
868
+ if (str12icmp(m, 'h', 'i', 'n', 'c', 'r', 'b', 'y', 'f', 'l', 'o', 'a', 't')) {
869
+ r->type = MSG_REQ_REDIS_HINCRBYFLOAT;
870
+ break;
871
+ }
872
+
873
+
874
+ break;
875
+
876
+ case 13:
877
+ if (str13icmp(m, 'z', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) {
878
+ r->type = MSG_REQ_REDIS_ZRANGEBYSCORE;
879
+ break;
880
+ }
881
+
882
+ break;
883
+
884
+ case 15:
885
+ if (str15icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'r', 'a', 'n', 'k')) {
886
+ r->type = MSG_REQ_REDIS_ZREMRANGEBYRANK;
887
+ break;
888
+ }
889
+
890
+ break;
891
+
892
+ case 16:
893
+ if (str16icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) {
894
+ r->type = MSG_REQ_REDIS_ZREMRANGEBYSCORE;
895
+ break;
896
+ }
897
+
898
+ if (str16icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) {
899
+ r->type = MSG_REQ_REDIS_ZREVRANGEBYSCORE;
900
+ break;
901
+ }
902
+
903
+ break;
904
+
905
+ default:
906
+ break;
907
+ }
908
+
909
+ if (r->type == MSG_UNKNOWN) {
910
+ log_error("parsed unsupported command '%.*s'", p - m, m);
911
+ goto error;
912
+ }
913
+
914
+ log_debug(LOG_VERB, "parsed command '%.*s'", p - m, m);
915
+
916
+ state = SW_REQ_TYPE_LF;
917
+ break;
918
+
919
+ case SW_REQ_TYPE_LF:
920
+ switch (ch) {
921
+ case LF:
922
+ if (redis_argeval(r)) {
923
+ state = SW_ARG1_LEN;
924
+ } else {
925
+ state = SW_KEY_LEN;
926
+ }
927
+ break;
928
+
929
+ default:
930
+ goto error;
931
+ }
932
+
933
+ break;
934
+
935
+ case SW_KEY_LEN:
936
+ if (r->token == NULL) {
937
+ if (ch != '$') {
938
+ goto error;
939
+ }
940
+ r->token = p;
941
+ r->rlen = 0;
942
+ } else if (isdigit(ch)) {
943
+ r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
944
+ } else if (ch == CR) {
945
+ if (r->rlen == 0) {
946
+ log_error("parsed bad req %"PRIu64" of type %d with empty "
947
+ "key", r->id, r->type);
948
+ goto error;
949
+ }
950
+ if (r->rlen > mbuf_data_size()) {
951
+ log_error("parsed bad req %"PRIu64" of type %d with key "
952
+ "length %d that exceeds maximum redis key "
953
+ "length of %d", r->id, r->type, r->rlen,
954
+ mbuf_data_size());
955
+ goto error;
956
+ }
957
+ if (r->rnarg == 0) {
958
+ goto error;
959
+ }
960
+ r->rnarg--;
961
+ r->token = NULL;
962
+ state = SW_KEY_LEN_LF;
963
+ } else {
964
+ goto error;
965
+ }
966
+
967
+ break;
968
+
969
+ case SW_KEY_LEN_LF:
970
+ switch (ch) {
971
+ case LF:
972
+ state = SW_KEY;
973
+ break;
974
+
975
+ default:
976
+ goto error;
977
+ }
978
+
979
+ break;
980
+
981
+ case SW_KEY:
982
+ if (r->token == NULL) {
983
+ r->token = p;
984
+ }
985
+
986
+ m = r->token + r->rlen;
987
+ if (m >= b->last) {
988
+ m = b->last - 1;
989
+ p = m;
990
+ break;
991
+ }
992
+
993
+ if (*m != CR) {
994
+ goto error;
995
+ }
996
+
997
+ p = m; /* move forward by rlen bytes */
998
+ r->rlen = 0;
999
+ m = r->token;
1000
+ r->token = NULL;
1001
+
1002
+ r->key_start = m;
1003
+ r->key_end = p;
1004
+
1005
+ state = SW_KEY_LF;
1006
+
1007
+ break;
1008
+
1009
+ case SW_KEY_LF:
1010
+ switch (ch) {
1011
+ case LF:
1012
+ if (redis_arg0(r)) {
1013
+ if (r->rnarg != 0) {
1014
+ goto error;
1015
+ }
1016
+ goto done;
1017
+ } else if (redis_arg1(r)) {
1018
+ if (r->rnarg != 1) {
1019
+ goto error;
1020
+ }
1021
+ state = SW_ARG1_LEN;
1022
+ } else if (redis_arg2(r)) {
1023
+ if (r->rnarg != 2) {
1024
+ goto error;
1025
+ }
1026
+ state = SW_ARG1_LEN;
1027
+ } else if (redis_arg3(r)) {
1028
+ if (r->rnarg != 3) {
1029
+ goto error;
1030
+ }
1031
+ state = SW_ARG1_LEN;
1032
+ } else if (redis_argn(r)) {
1033
+ if (r->rnarg == 0) {
1034
+ goto done;
1035
+ }
1036
+ state = SW_ARG1_LEN;
1037
+ } else if (redis_argx(r)) {
1038
+ if (r->rnarg == 0) {
1039
+ goto done;
1040
+ }
1041
+ state = SW_FRAGMENT;
1042
+ } else if (redis_argeval(r)) {
1043
+ if (r->rnarg == 0) {
1044
+ goto done;
1045
+ }
1046
+ state = SW_ARGN_LEN;
1047
+ } else {
1048
+ goto error;
1049
+ }
1050
+
1051
+ break;
1052
+
1053
+ default:
1054
+ goto error;
1055
+ }
1056
+
1057
+ break;
1058
+
1059
+ case SW_FRAGMENT:
1060
+ r->token = p;
1061
+ goto fragment;
1062
+
1063
+ case SW_ARG1_LEN:
1064
+ if (r->token == NULL) {
1065
+ if (ch != '$') {
1066
+ goto error;
1067
+ }
1068
+ r->rlen = 0;
1069
+ r->token = p;
1070
+ } else if (isdigit(ch)) {
1071
+ r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
1072
+ } else if (ch == CR) {
1073
+ if ((p - r->token) <= 1 || r->rnarg == 0) {
1074
+ goto error;
1075
+ }
1076
+ r->rnarg--;
1077
+ r->token = NULL;
1078
+ state = SW_ARG1_LEN_LF;
1079
+ } else {
1080
+ goto error;
1081
+ }
1082
+
1083
+ break;
1084
+
1085
+ case SW_ARG1_LEN_LF:
1086
+ switch (ch) {
1087
+ case LF:
1088
+ state = SW_ARG1;
1089
+ break;
1090
+
1091
+ default:
1092
+ goto error;
1093
+ }
1094
+
1095
+ break;
1096
+
1097
+ case SW_ARG1:
1098
+ m = p + r->rlen;
1099
+ if (m >= b->last) {
1100
+ r->rlen -= (uint32_t)(b->last - p);
1101
+ m = b->last - 1;
1102
+ p = m;
1103
+ break;
1104
+ }
1105
+
1106
+ if (*m != CR) {
1107
+ goto error;
1108
+ }
1109
+
1110
+ p = m; /* move forward by rlen bytes */
1111
+ r->rlen = 0;
1112
+
1113
+ state = SW_ARG1_LF;
1114
+
1115
+ break;
1116
+
1117
+ case SW_ARG1_LF:
1118
+ switch (ch) {
1119
+ case LF:
1120
+ if (redis_arg1(r)) {
1121
+ if (r->rnarg != 0) {
1122
+ goto error;
1123
+ }
1124
+ goto done;
1125
+ } else if (redis_arg2(r)) {
1126
+ if (r->rnarg != 1) {
1127
+ goto error;
1128
+ }
1129
+ state = SW_ARG2_LEN;
1130
+ } else if (redis_arg3(r)) {
1131
+ if (r->rnarg != 2) {
1132
+ goto error;
1133
+ }
1134
+ state = SW_ARG2_LEN;
1135
+ } else if (redis_argn(r)) {
1136
+ if (r->rnarg == 0) {
1137
+ goto done;
1138
+ }
1139
+ state = SW_ARGN_LEN;
1140
+ } else if (redis_argeval(r)) {
1141
+ if (r->rnarg < 2) {
1142
+ goto error;
1143
+ }
1144
+ state = SW_ARG2_LEN;
1145
+ } else {
1146
+ goto error;
1147
+ }
1148
+
1149
+ break;
1150
+
1151
+ default:
1152
+ goto error;
1153
+ }
1154
+
1155
+ break;
1156
+
1157
+ case SW_ARG2_LEN:
1158
+ if (r->token == NULL) {
1159
+ if (ch != '$') {
1160
+ goto error;
1161
+ }
1162
+ r->rlen = 0;
1163
+ r->token = p;
1164
+ } else if (isdigit(ch)) {
1165
+ r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
1166
+ } else if (ch == CR) {
1167
+ if ((p - r->token) <= 1 || r->rnarg == 0) {
1168
+ goto error;
1169
+ }
1170
+ r->rnarg--;
1171
+ r->token = NULL;
1172
+ state = SW_ARG2_LEN_LF;
1173
+ } else {
1174
+ goto error;
1175
+ }
1176
+
1177
+ break;
1178
+
1179
+ case SW_ARG2_LEN_LF:
1180
+ switch (ch) {
1181
+ case LF:
1182
+ state = SW_ARG2;
1183
+ break;
1184
+
1185
+ default:
1186
+ goto error;
1187
+ }
1188
+
1189
+ break;
1190
+
1191
+ case SW_ARG2:
1192
+ if (r->token == NULL && redis_argeval(r)) {
1193
+ /*
1194
+ * For EVAL/EVALSHA, ARG2 represents the # key/arg pairs which must
1195
+ * be tokenized and stored in contiguous memory.
1196
+ */
1197
+ r->token = p;
1198
+ }
1199
+
1200
+ m = p + r->rlen;
1201
+ if (m >= b->last) {
1202
+ r->rlen -= (uint32_t)(b->last - p);
1203
+ m = b->last - 1;
1204
+ p = m;
1205
+ break;
1206
+ }
1207
+
1208
+ if (*m != CR) {
1209
+ goto error;
1210
+ }
1211
+
1212
+ p = m; /* move forward by rlen bytes */
1213
+ r->rlen = 0;
1214
+
1215
+ if (redis_argeval(r)) {
1216
+ uint32_t nkey;
1217
+ uint8_t *chp;
1218
+
1219
+ /*
1220
+ * For EVAL/EVALSHA, we need to find the integer value of this
1221
+ * argument. It tells us the number of keys in the script, and
1222
+ * we need to error out if number of keys is 0. At this point,
1223
+ * both p and m point to the end of the argument and r->token
1224
+ * points to the start.
1225
+ */
1226
+ if (p - r->token < 1) {
1227
+ goto error;
1228
+ }
1229
+
1230
+ for (nkey = 0, chp = r->token; chp < p; chp++) {
1231
+ if (isdigit(*chp)) {
1232
+ nkey = nkey * 10 + (uint32_t)(*chp - '0');
1233
+ } else {
1234
+ goto error;
1235
+ }
1236
+ }
1237
+ if (nkey == 0) {
1238
+ goto error;
1239
+ }
1240
+
1241
+ r->token = NULL;
1242
+ }
1243
+
1244
+ state = SW_ARG2_LF;
1245
+
1246
+ break;
1247
+
1248
+ case SW_ARG2_LF:
1249
+ switch (ch) {
1250
+ case LF:
1251
+ if (redis_arg2(r)) {
1252
+ if (r->rnarg != 0) {
1253
+ goto error;
1254
+ }
1255
+ goto done;
1256
+ } else if (redis_arg3(r)) {
1257
+ if (r->rnarg != 1) {
1258
+ goto error;
1259
+ }
1260
+ state = SW_ARG3_LEN;
1261
+ } else if (redis_argn(r)) {
1262
+ if (r->rnarg == 0) {
1263
+ goto done;
1264
+ }
1265
+ state = SW_ARGN_LEN;
1266
+ } else if (redis_argeval(r)) {
1267
+ if (r->rnarg < 1) {
1268
+ goto error;
1269
+ }
1270
+ state = SW_KEY_LEN;
1271
+ } else {
1272
+ goto error;
1273
+ }
1274
+
1275
+ break;
1276
+
1277
+ default:
1278
+ goto error;
1279
+ }
1280
+
1281
+ break;
1282
+
1283
+ case SW_ARG3_LEN:
1284
+ if (r->token == NULL) {
1285
+ if (ch != '$') {
1286
+ goto error;
1287
+ }
1288
+ r->rlen = 0;
1289
+ r->token = p;
1290
+ } else if (isdigit(ch)) {
1291
+ r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
1292
+ } else if (ch == CR) {
1293
+ if ((p - r->token) <= 1 || r->rnarg == 0) {
1294
+ goto error;
1295
+ }
1296
+ r->rnarg--;
1297
+ r->token = NULL;
1298
+ state = SW_ARG3_LEN_LF;
1299
+ } else {
1300
+ goto error;
1301
+ }
1302
+
1303
+ break;
1304
+
1305
+ case SW_ARG3_LEN_LF:
1306
+ switch (ch) {
1307
+ case LF:
1308
+ state = SW_ARG3;
1309
+ break;
1310
+
1311
+ default:
1312
+ goto error;
1313
+ }
1314
+
1315
+ break;
1316
+
1317
+ case SW_ARG3:
1318
+ m = p + r->rlen;
1319
+ if (m >= b->last) {
1320
+ r->rlen -= (uint32_t)(b->last - p);
1321
+ m = b->last - 1;
1322
+ p = m;
1323
+ break;
1324
+ }
1325
+
1326
+ if (*m != CR) {
1327
+ goto error;
1328
+ }
1329
+
1330
+ p = m; /* move forward by rlen bytes */
1331
+ r->rlen = 0;
1332
+ state = SW_ARG3_LF;
1333
+
1334
+ break;
1335
+
1336
+ case SW_ARG3_LF:
1337
+ switch (ch) {
1338
+ case LF:
1339
+ if (redis_arg3(r)) {
1340
+ if (r->rnarg != 0) {
1341
+ goto error;
1342
+ }
1343
+ goto done;
1344
+ } else if (redis_argn(r)) {
1345
+ if (r->rnarg == 0) {
1346
+ goto done;
1347
+ }
1348
+ state = SW_ARGN_LEN;
1349
+ } else {
1350
+ goto error;
1351
+ }
1352
+
1353
+ break;
1354
+
1355
+ default:
1356
+ goto error;
1357
+ }
1358
+
1359
+ break;
1360
+
1361
+ case SW_ARGN_LEN:
1362
+ if (r->token == NULL) {
1363
+ if (ch != '$') {
1364
+ goto error;
1365
+ }
1366
+ r->rlen = 0;
1367
+ r->token = p;
1368
+ } else if (isdigit(ch)) {
1369
+ r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
1370
+ } else if (ch == CR) {
1371
+ if ((p - r->token) <= 1 || r->rnarg == 0) {
1372
+ goto error;
1373
+ }
1374
+ r->rnarg--;
1375
+ r->token = NULL;
1376
+ state = SW_ARGN_LEN_LF;
1377
+ } else {
1378
+ goto error;
1379
+ }
1380
+
1381
+ break;
1382
+
1383
+ case SW_ARGN_LEN_LF:
1384
+ switch (ch) {
1385
+ case LF:
1386
+ state = SW_ARGN;
1387
+ break;
1388
+
1389
+ default:
1390
+ goto error;
1391
+ }
1392
+
1393
+ break;
1394
+
1395
+ case SW_ARGN:
1396
+ m = p + r->rlen;
1397
+ if (m >= b->last) {
1398
+ r->rlen -= (uint32_t)(b->last - p);
1399
+ m = b->last - 1;
1400
+ p = m;
1401
+ break;
1402
+ }
1403
+
1404
+ if (*m != CR) {
1405
+ goto error;
1406
+ }
1407
+
1408
+ p = m; /* move forward by rlen bytes */
1409
+ r->rlen = 0;
1410
+ state = SW_ARGN_LF;
1411
+
1412
+ break;
1413
+
1414
+ case SW_ARGN_LF:
1415
+ switch (ch) {
1416
+ case LF:
1417
+ if (redis_argn(r) || redis_argeval(r)) {
1418
+ if (r->rnarg == 0) {
1419
+ goto done;
1420
+ }
1421
+ state = SW_ARGN_LEN;
1422
+ } else {
1423
+ goto error;
1424
+ }
1425
+
1426
+ break;
1427
+
1428
+ default:
1429
+ goto error;
1430
+ }
1431
+
1432
+ break;
1433
+
1434
+ case SW_SENTINEL:
1435
+ default:
1436
+ NOT_REACHED();
1437
+ break;
1438
+ }
1439
+ }
1440
+
1441
+ ASSERT(p == b->last);
1442
+ r->pos = p;
1443
+ r->state = state;
1444
+
1445
+ if (b->last == b->end && r->token != NULL) {
1446
+ r->pos = r->token;
1447
+ r->token = NULL;
1448
+ r->result = MSG_PARSE_REPAIR;
1449
+ } else {
1450
+ r->result = MSG_PARSE_AGAIN;
1451
+ }
1452
+
1453
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
1454
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
1455
+ r->state, r->pos - b->pos, b->last - b->pos);
1456
+ return;
1457
+
1458
+ fragment:
1459
+ ASSERT(p != b->last);
1460
+ ASSERT(r->token != NULL);
1461
+ r->pos = r->token;
1462
+ r->token = NULL;
1463
+ r->state = state;
1464
+ r->result = MSG_PARSE_FRAGMENT;
1465
+
1466
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
1467
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
1468
+ r->state, r->pos - b->pos, b->last - b->pos);
1469
+ return;
1470
+
1471
+ done:
1472
+ ASSERT(r->type > MSG_UNKNOWN && r->type < MSG_SENTINEL);
1473
+ r->pos = p + 1;
1474
+ ASSERT(r->pos <= b->last);
1475
+ r->state = SW_START;
1476
+ r->token = NULL;
1477
+ r->result = MSG_PARSE_OK;
1478
+
1479
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d "
1480
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
1481
+ r->state, r->pos - b->pos, b->last - b->pos);
1482
+ return;
1483
+
1484
+ error:
1485
+ r->result = MSG_PARSE_ERROR;
1486
+ r->state = state;
1487
+ errno = EINVAL;
1488
+
1489
+ log_hexdump(LOG_INFO, b->pos, mbuf_length(b), "parsed bad req %"PRIu64" "
1490
+ "res %d type %d state %d", r->id, r->result, r->type,
1491
+ r->state);
1492
+ }
1493
+
1494
+ /*
1495
+ * Reference: http://redis.io/topics/protocol
1496
+ *
1497
+ * Redis will reply to commands with different kinds of replies. It is
1498
+ * possible to check the kind of reply from the first byte sent by the
1499
+ * server:
1500
+ * - with a single line reply the first byte of the reply will be "+"
1501
+ * - with an error message the first byte of the reply will be "-"
1502
+ * - with an integer number the first byte of the reply will be ":"
1503
+ * - with bulk reply the first byte of the reply will be "$"
1504
+ * - with multi-bulk reply the first byte of the reply will be "*"
1505
+ *
1506
+ * 1). Status reply (or single line reply) is in the form of a single line
1507
+ * string starting with "+" terminated by "\r\n".
1508
+ * 2). Error reply are similar to status replies. The only difference is
1509
+ * that the first byte is "-" instead of "+".
1510
+ * 3). Integer reply is just a CRLF terminated string representing an
1511
+ * integer, and prefixed by a ":" byte.
1512
+ * 4). Bulk reply is used by server to return a single binary safe string.
1513
+ * The first reply line is a "$" byte followed by the number of bytes
1514
+ * of the actual reply, followed by CRLF, then the actual data bytes,
1515
+ * followed by additional two bytes for the final CRLF. If the requested
1516
+ * value does not exist the bulk reply will use the special value '-1'
1517
+ * as the data length.
1518
+ * 5). Multi-bulk reply is used by the server to return many binary safe
1519
+ * strings (bulks) with the initial line indicating how many bulks that
1520
+ * will follow. The first byte of a multi bulk reply is always *.
1521
+ */
1522
+ void
1523
+ redis_parse_rsp(struct msg *r)
1524
+ {
1525
+ struct mbuf *b;
1526
+ uint8_t *p, *m;
1527
+ uint8_t ch;
1528
+ enum {
1529
+ SW_START,
1530
+ SW_STATUS,
1531
+ SW_ERROR,
1532
+ SW_INTEGER,
1533
+ SW_INTEGER_START,
1534
+ SW_BULK,
1535
+ SW_BULK_LF,
1536
+ SW_BULK_ARG,
1537
+ SW_BULK_ARG_LF,
1538
+ SW_MULTIBULK,
1539
+ SW_MULTIBULK_NARG_LF,
1540
+ SW_MULTIBULK_ARGN_LEN,
1541
+ SW_MULTIBULK_ARGN_LEN_LF,
1542
+ SW_MULTIBULK_ARGN,
1543
+ SW_MULTIBULK_ARGN_LF,
1544
+ SW_RUNTO_CRLF,
1545
+ SW_ALMOST_DONE,
1546
+ SW_SENTINEL
1547
+ } state;
1548
+
1549
+ state = r->state;
1550
+ b = STAILQ_LAST(&r->mhdr, mbuf, next);
1551
+
1552
+ ASSERT(!r->request);
1553
+ ASSERT(state >= SW_START && state < SW_SENTINEL);
1554
+ ASSERT(b != NULL);
1555
+ ASSERT(b->pos <= b->last);
1556
+
1557
+ /* validate the parsing marker */
1558
+ ASSERT(r->pos != NULL);
1559
+ ASSERT(r->pos >= b->pos && r->pos <= b->last);
1560
+
1561
+ for (p = r->pos; p < b->last; p++) {
1562
+ ch = *p;
1563
+
1564
+ switch (state) {
1565
+ case SW_START:
1566
+ r->type = MSG_UNKNOWN;
1567
+ switch (ch) {
1568
+ case '+':
1569
+ p = p - 1; /* go back by 1 byte */
1570
+ r->type = MSG_RSP_REDIS_STATUS;
1571
+ state = SW_STATUS;
1572
+ break;
1573
+
1574
+ case '-':
1575
+ r->type = MSG_RSP_REDIS_ERROR;
1576
+ p = p - 1; /* go back by 1 byte */
1577
+ state = SW_ERROR;
1578
+ break;
1579
+
1580
+ case ':':
1581
+ r->type = MSG_RSP_REDIS_INTEGER;
1582
+ p = p - 1; /* go back by 1 byte */
1583
+ state = SW_INTEGER;
1584
+ break;
1585
+
1586
+ case '$':
1587
+ r->type = MSG_RSP_REDIS_BULK;
1588
+ p = p - 1; /* go back by 1 byte */
1589
+ state = SW_BULK;
1590
+ break;
1591
+
1592
+ case '*':
1593
+ r->type = MSG_RSP_REDIS_MULTIBULK;
1594
+ p = p - 1; /* go back by 1 byte */
1595
+ state = SW_MULTIBULK;
1596
+ break;
1597
+
1598
+ default:
1599
+ goto error;
1600
+ }
1601
+
1602
+ break;
1603
+
1604
+ case SW_STATUS:
1605
+ /* rsp_start <- p */
1606
+ state = SW_RUNTO_CRLF;
1607
+ break;
1608
+
1609
+ case SW_ERROR:
1610
+ /* rsp_start <- p */
1611
+ state = SW_RUNTO_CRLF;
1612
+ break;
1613
+
1614
+ case SW_INTEGER:
1615
+ /* rsp_start <- p */
1616
+ state = SW_INTEGER_START;
1617
+ r->integer = 0;
1618
+ break;
1619
+
1620
+ case SW_INTEGER_START:
1621
+ if (ch == CR) {
1622
+ state = SW_ALMOST_DONE;
1623
+ } else if (ch == '-') {
1624
+ ;
1625
+ } else if (isdigit(ch)) {
1626
+ r->integer = r->integer * 10 + (uint32_t)(ch - '0');
1627
+ } else {
1628
+ goto error;
1629
+ }
1630
+ break;
1631
+
1632
+ case SW_RUNTO_CRLF:
1633
+ switch (ch) {
1634
+ case CR:
1635
+ state = SW_ALMOST_DONE;
1636
+ break;
1637
+
1638
+ default:
1639
+ break;
1640
+ }
1641
+
1642
+ break;
1643
+
1644
+ case SW_ALMOST_DONE:
1645
+ switch (ch) {
1646
+ case LF:
1647
+ /* rsp_end <- p */
1648
+ goto done;
1649
+
1650
+ default:
1651
+ goto error;
1652
+ }
1653
+
1654
+ break;
1655
+
1656
+ case SW_BULK:
1657
+ if (r->token == NULL) {
1658
+ if (ch != '$') {
1659
+ goto error;
1660
+ }
1661
+ /* rsp_start <- p */
1662
+ r->token = p;
1663
+ r->rlen = 0;
1664
+ } else if (ch == '-') {
1665
+ state = SW_RUNTO_CRLF;
1666
+ } else if (isdigit(ch)) {
1667
+ r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
1668
+ } else if (ch == CR) {
1669
+ if ((p - r->token) <= 1) {
1670
+ goto error;
1671
+ }
1672
+ r->token = NULL;
1673
+ state = SW_BULK_LF;
1674
+ } else {
1675
+ goto error;
1676
+ }
1677
+
1678
+ break;
1679
+
1680
+ case SW_BULK_LF:
1681
+ switch (ch) {
1682
+ case LF:
1683
+ state = SW_BULK_ARG;
1684
+ break;
1685
+
1686
+ default:
1687
+ goto error;
1688
+ }
1689
+
1690
+ break;
1691
+
1692
+ case SW_BULK_ARG:
1693
+ m = p + r->rlen;
1694
+ if (m >= b->last) {
1695
+ r->rlen -= (uint32_t)(b->last - p);
1696
+ m = b->last - 1;
1697
+ p = m;
1698
+ break;
1699
+ }
1700
+
1701
+ if (*m != CR) {
1702
+ goto error;
1703
+ }
1704
+
1705
+ p = m; /* move forward by rlen bytes */
1706
+ r->rlen = 0;
1707
+
1708
+ state = SW_BULK_ARG_LF;
1709
+
1710
+ break;
1711
+
1712
+ case SW_BULK_ARG_LF:
1713
+ switch (ch) {
1714
+ case LF:
1715
+ goto done;
1716
+
1717
+ default:
1718
+ goto error;
1719
+ }
1720
+
1721
+ break;
1722
+
1723
+ case SW_MULTIBULK:
1724
+ if (r->token == NULL) {
1725
+ if (ch != '*') {
1726
+ goto error;
1727
+ }
1728
+ r->token = p;
1729
+ /* rsp_start <- p */
1730
+ r->narg_start = p;
1731
+ r->rnarg = 0;
1732
+ } else if (isdigit(ch)) {
1733
+ r->rnarg = r->rnarg * 10 + (uint32_t)(ch - '0');
1734
+ } else if (ch == CR) {
1735
+ if ((p - r->token) <= 1) {
1736
+ goto error;
1737
+ }
1738
+ r->narg = r->rnarg;
1739
+ r->narg_end = p;
1740
+ r->token = NULL;
1741
+ state = SW_MULTIBULK_NARG_LF;
1742
+ } else {
1743
+ goto error;
1744
+ }
1745
+
1746
+ break;
1747
+
1748
+ case SW_MULTIBULK_NARG_LF:
1749
+ switch (ch) {
1750
+ case LF:
1751
+ if (r->rnarg == 0) {
1752
+ /* response is '*0\r\n' */
1753
+ goto done;
1754
+ }
1755
+ state = SW_MULTIBULK_ARGN_LEN;
1756
+ break;
1757
+
1758
+ default:
1759
+ goto error;
1760
+ }
1761
+
1762
+ break;
1763
+
1764
+ case SW_MULTIBULK_ARGN_LEN:
1765
+ if (r->token == NULL) {
1766
+ if (ch != '$') {
1767
+ goto error;
1768
+ }
1769
+ r->token = p;
1770
+ r->rlen = 0;
1771
+ } else if (isdigit(ch)) {
1772
+ r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
1773
+ } else if (ch == '-') {
1774
+ ;
1775
+ } else if (ch == CR) {
1776
+ if ((p - r->token) <= 1 || r->rnarg == 0) {
1777
+ goto error;
1778
+ }
1779
+
1780
+ if (r->rlen == 1 && (p - r->token) == 3) {
1781
+ /* handles not-found reply = '$-1'*/
1782
+ r->rlen = 0;
1783
+ state = SW_MULTIBULK_ARGN_LF;
1784
+ } else {
1785
+ state = SW_MULTIBULK_ARGN_LEN_LF;
1786
+ }
1787
+ r->rnarg--;
1788
+ r->token = NULL;
1789
+
1790
+ } else {
1791
+ goto error;
1792
+ }
1793
+
1794
+ break;
1795
+
1796
+ case SW_MULTIBULK_ARGN_LEN_LF:
1797
+ switch (ch) {
1798
+ case LF:
1799
+ state = SW_MULTIBULK_ARGN;
1800
+ break;
1801
+
1802
+ default:
1803
+ goto error;
1804
+ }
1805
+
1806
+ break;
1807
+
1808
+ case SW_MULTIBULK_ARGN:
1809
+ m = p + r->rlen;
1810
+ if (m >= b->last) {
1811
+ r->rlen -= (uint32_t)(b->last - p);
1812
+ m = b->last - 1;
1813
+ p = m;
1814
+ break;
1815
+ }
1816
+
1817
+ if (*m != CR) {
1818
+ goto error;
1819
+ }
1820
+
1821
+ p += r->rlen; /* move forward by rlen bytes */
1822
+ r->rlen = 0;
1823
+
1824
+ state = SW_MULTIBULK_ARGN_LF;
1825
+
1826
+ break;
1827
+
1828
+ case SW_MULTIBULK_ARGN_LF:
1829
+ switch (ch) {
1830
+ case LF:
1831
+ if (r->rnarg == 0) {
1832
+ goto done;
1833
+ }
1834
+
1835
+ state = SW_MULTIBULK_ARGN_LEN;
1836
+ break;
1837
+
1838
+ default:
1839
+ goto error;
1840
+ }
1841
+
1842
+ break;
1843
+
1844
+ case SW_SENTINEL:
1845
+ default:
1846
+ NOT_REACHED();
1847
+ break;
1848
+ }
1849
+ }
1850
+
1851
+ ASSERT(p == b->last);
1852
+ r->pos = p;
1853
+ r->state = state;
1854
+
1855
+ if (b->last == b->end && r->token != NULL) {
1856
+ r->pos = r->token;
1857
+ r->token = NULL;
1858
+ r->result = MSG_PARSE_REPAIR;
1859
+ } else {
1860
+ r->result = MSG_PARSE_AGAIN;
1861
+ }
1862
+
1863
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed rsp %"PRIu64" res %d "
1864
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
1865
+ r->state, r->pos - b->pos, b->last - b->pos);
1866
+ return;
1867
+
1868
+ done:
1869
+ ASSERT(r->type > MSG_UNKNOWN && r->type < MSG_SENTINEL);
1870
+ r->pos = p + 1;
1871
+ ASSERT(r->pos <= b->last);
1872
+ r->state = SW_START;
1873
+ r->token = NULL;
1874
+ r->result = MSG_PARSE_OK;
1875
+
1876
+ log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed rsp %"PRIu64" res %d "
1877
+ "type %d state %d rpos %d of %d", r->id, r->result, r->type,
1878
+ r->state, r->pos - b->pos, b->last - b->pos);
1879
+ return;
1880
+
1881
+ error:
1882
+ r->result = MSG_PARSE_ERROR;
1883
+ r->state = state;
1884
+ errno = EINVAL;
1885
+
1886
+ log_hexdump(LOG_INFO, b->pos, mbuf_length(b), "parsed bad rsp %"PRIu64" "
1887
+ "res %d type %d state %d", r->id, r->result, r->type,
1888
+ r->state);
1889
+ }
1890
+
1891
+ /*
1892
+ * Pre-split copy handler invoked when the request is a multi vector -
1893
+ * 'mget' or 'del' request and is about to be split into two requests
1894
+ */
1895
+ void
1896
+ redis_pre_splitcopy(struct mbuf *mbuf, void *arg)
1897
+ {
1898
+ struct msg *r = arg;
1899
+ int n;
1900
+
1901
+ ASSERT(r->request);
1902
+ ASSERT(r->narg > 1);
1903
+ ASSERT(mbuf_empty(mbuf));
1904
+
1905
+ switch (r->type) {
1906
+ case MSG_REQ_REDIS_MGET:
1907
+ n = nc_snprintf(mbuf->last, mbuf_size(mbuf), "*%d\r\n$4\r\nmget\r\n",
1908
+ r->narg - 1);
1909
+ break;
1910
+
1911
+ case MSG_REQ_REDIS_DEL:
1912
+ n = nc_snprintf(mbuf->last, mbuf_size(mbuf), "*%d\r\n$3\r\ndel\r\n",
1913
+ r->narg - 1);
1914
+ break;
1915
+
1916
+ default:
1917
+ n = 0;
1918
+ NOT_REACHED();
1919
+ }
1920
+
1921
+ mbuf->last += n;
1922
+ }
1923
+
1924
+ /*
1925
+ * Post-split copy handler invoked when the request is a multi vector -
1926
+ * 'mget' or 'del' request and has already been split into two requests
1927
+ */
1928
+ rstatus_t
1929
+ redis_post_splitcopy(struct msg *r)
1930
+ {
1931
+ struct mbuf *hbuf, *nhbuf; /* head mbuf and new head mbuf */
1932
+ struct string hstr = string("*2"); /* header string */
1933
+
1934
+ ASSERT(r->request);
1935
+ ASSERT(r->type == MSG_REQ_REDIS_MGET || r->type == MSG_REQ_REDIS_DEL);
1936
+ ASSERT(!STAILQ_EMPTY(&r->mhdr));
1937
+
1938
+ nhbuf = mbuf_get();
1939
+ if (nhbuf == NULL) {
1940
+ return NC_ENOMEM;
1941
+ }
1942
+
1943
+ /*
1944
+ * Fix the head mbuf in the head (A) msg. The fix is straightforward
1945
+ * as we just need to skip over the narg token
1946
+ */
1947
+ hbuf = STAILQ_FIRST(&r->mhdr);
1948
+ ASSERT(hbuf->pos == r->narg_start);
1949
+ ASSERT(hbuf->pos < r->narg_end && r->narg_end <= hbuf->last);
1950
+ hbuf->pos = r->narg_end;
1951
+
1952
+ /*
1953
+ * Add a new head mbuf in the head (A) msg that just contains '*2'
1954
+ * token
1955
+ */
1956
+ STAILQ_INSERT_HEAD(&r->mhdr, nhbuf, next);
1957
+ mbuf_copy(nhbuf, hstr.data, hstr.len);
1958
+
1959
+ /* fix up the narg_start and narg_end */
1960
+ r->narg_start = nhbuf->pos;
1961
+ r->narg_end = nhbuf->last;
1962
+
1963
+ return NC_OK;
1964
+ }
1965
+
1966
+ /*
1967
+ * Pre-coalesce handler is invoked when the message is a response to
1968
+ * the fragmented multi vector request - 'mget' or 'del' and all the
1969
+ * responses to the fragmented request vector hasn't been received
1970
+ */
1971
+ void
1972
+ redis_pre_coalesce(struct msg *r)
1973
+ {
1974
+ struct msg *pr = r->peer; /* peer request */
1975
+ struct mbuf *mbuf;
1976
+
1977
+ ASSERT(!r->request);
1978
+ ASSERT(pr->request);
1979
+
1980
+ if (pr->frag_id == 0) {
1981
+ /* do nothing, if not a response to a fragmented request */
1982
+ return;
1983
+ }
1984
+
1985
+ switch (r->type) {
1986
+ case MSG_RSP_REDIS_INTEGER:
1987
+ /* only redis 'del' fragmented request sends back integer reply */
1988
+ ASSERT(pr->type == MSG_REQ_REDIS_DEL);
1989
+
1990
+ mbuf = STAILQ_FIRST(&r->mhdr);
1991
+ /*
1992
+ * Our response parser guarantees that the integer reply will be
1993
+ * completely encapsulated in a single mbuf and we should skip over
1994
+ * all the mbuf contents and discard it as the parser has already
1995
+ * parsed the integer reply and stored it in msg->integer
1996
+ */
1997
+ ASSERT(mbuf == STAILQ_LAST(&r->mhdr, mbuf, next));
1998
+ ASSERT(r->mlen == mbuf_length(mbuf));
1999
+
2000
+ r->mlen -= mbuf_length(mbuf);
2001
+ mbuf_rewind(mbuf);
2002
+
2003
+ /* accumulate the integer value in frag_owner of peer request */
2004
+ pr->frag_owner->integer += r->integer;
2005
+ break;
2006
+
2007
+ case MSG_RSP_REDIS_MULTIBULK:
2008
+ /* only redis 'mget' fragmented request sends back multi-bulk reply */
2009
+ ASSERT(pr->type == MSG_REQ_REDIS_MGET);
2010
+
2011
+ mbuf = STAILQ_FIRST(&r->mhdr);
2012
+ /*
2013
+ * Muti-bulk reply can span over multiple mbufs and in each reply
2014
+ * we should skip over the narg token. Our response parser
2015
+ * guarantees thaat the narg token and the immediately following
2016
+ * '\r\n' will exist in a contiguous region in the first mbuf
2017
+ */
2018
+ ASSERT(r->narg_start == mbuf->pos);
2019
+ ASSERT(r->narg_start < r->narg_end);
2020
+
2021
+ r->narg_end += CRLF_LEN;
2022
+ r->mlen -= (uint32_t)(r->narg_end - r->narg_start);
2023
+ mbuf->pos = r->narg_end;
2024
+
2025
+ if (pr->first_fragment) {
2026
+ mbuf = mbuf_get();
2027
+ if (mbuf == NULL) {
2028
+ pr->error = 1;
2029
+ pr->err = EINVAL;
2030
+ return;
2031
+ }
2032
+ STAILQ_INSERT_HEAD(&r->mhdr, mbuf, next);
2033
+ }
2034
+ break;
2035
+
2036
+ default:
2037
+ /*
2038
+ * Valid responses for a fragmented request are MSG_RSP_REDIS_INTEGER or,
2039
+ * MSG_RSP_REDIS_MULTIBULK. For an invalid response, we send out -ERR
2040
+ * with EINVAL errno
2041
+ */
2042
+ mbuf = STAILQ_FIRST(&r->mhdr);
2043
+ log_hexdump(LOG_ERR, mbuf->pos, mbuf_length(mbuf), "rsp fragment "
2044
+ "with unknown type %d", r->type);
2045
+ pr->error = 1;
2046
+ pr->err = EINVAL;
2047
+ break;
2048
+ }
2049
+ }
2050
+
2051
+ /*
2052
+ * Post-coalesce handler is invoked when the message is a response to
2053
+ * the fragmented multi vector request - 'mget' or 'del' and all the
2054
+ * responses to the fragmented request vector has been received and
2055
+ * the fragmented request is consider to be done
2056
+ */
2057
+ void
2058
+ redis_post_coalesce(struct msg *r)
2059
+ {
2060
+ struct msg *pr = r->peer; /* peer response */
2061
+ struct mbuf *mbuf;
2062
+ int n;
2063
+
2064
+ ASSERT(r->request && r->first_fragment);
2065
+ if (r->error || r->ferror) {
2066
+ /* do nothing, if msg is in error */
2067
+ return;
2068
+ }
2069
+
2070
+ ASSERT(!pr->request);
2071
+
2072
+ switch (pr->type) {
2073
+ case MSG_RSP_REDIS_INTEGER:
2074
+ /* only redis 'del' fragmented request sends back integer reply */
2075
+ ASSERT(r->type == MSG_REQ_REDIS_DEL);
2076
+
2077
+ mbuf = STAILQ_FIRST(&pr->mhdr);
2078
+
2079
+ ASSERT(pr->mlen == 0);
2080
+ ASSERT(mbuf_empty(mbuf));
2081
+
2082
+ n = nc_scnprintf(mbuf->last, mbuf_size(mbuf), ":%d\r\n", r->integer);
2083
+ mbuf->last += n;
2084
+ pr->mlen += (uint32_t)n;
2085
+ break;
2086
+
2087
+ case MSG_RSP_REDIS_MULTIBULK:
2088
+ /* only redis 'mget' fragmented request sends back multi-bulk reply */
2089
+ ASSERT(r->type == MSG_REQ_REDIS_MGET);
2090
+
2091
+ mbuf = STAILQ_FIRST(&pr->mhdr);
2092
+ ASSERT(mbuf_empty(mbuf));
2093
+
2094
+ n = nc_scnprintf(mbuf->last, mbuf_size(mbuf), "*%d\r\n", r->nfrag);
2095
+ mbuf->last += n;
2096
+ pr->mlen += (uint32_t)n;
2097
+ break;
2098
+
2099
+ default:
2100
+ NOT_REACHED();
2101
+ }
2102
+ }