nutcracker 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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
+ }