12 "replace", // MEMCACHE_CMD_STORE_REPLACE |
13 "replace", // MEMCACHE_CMD_STORE_REPLACE |
13 "append", // MEMCACHE_CMD_STORE_APPEND |
14 "append", // MEMCACHE_CMD_STORE_APPEND |
14 "prepend" // MEMCACHE_CMD_STORE_PREPEND |
15 "prepend" // MEMCACHE_CMD_STORE_PREPEND |
15 }; |
16 }; |
16 |
17 |
17 /* |
|
18 static struct memcache_reply_info { |
18 static struct memcache_reply_info { |
19 enum memcache_reply type; |
19 enum memcache_reply type; |
20 char *name; |
20 char *name; |
21 int has_data; |
21 |
22 |
22 } memcache_cmd_replies[MEMCACHE_RPL_MAX] = { |
23 } *memcache_cmd_replies[MEMCACHE_RPL_MAX] = { |
23 { MEMCACHE_RPL_INVALID, NULL }, |
24 MEMCACHE_RPL_INVALID, |
24 { MEMCACHE_RPL_ERROR, "ERROR" }, |
25 |
25 { MEMCACHE_RPL_CLIENT_ERROR, "CLIENT_ERROR" }, |
26 MEMCACHE_RPL_ERROR, |
26 { MEMCACHE_RPL_SERVER_ERROR, "SERVER_ERROR" }, |
27 MEMCACHE_RPL_CLIENT_ERROR, |
|
28 MEMCACHE_RPL_SERVER_ERROR, |
|
29 |
27 |
30 // MEMCACHE_CMD_FETCH_* |
28 // MEMCACHE_CMD_FETCH_* |
31 MEMCACHE_RPL_VALUE, |
29 { MEMCACHE_RPL_VALUE, "VALUE" }, |
32 MEMCACHE_RPL_END, |
30 { MEMCACHE_RPL_END, "END" }, |
33 |
31 |
34 // MEMCACHE_CMD_STORE_* |
32 // MEMCACHE_CMD_STORE_* |
35 MEMCACHE_RPL_STORED, |
33 { MEMCACHE_RPL_STORED, "STORED" }, |
36 MEMCACHE_RPL_NOT_STORED, |
34 { MEMCACHE_RPL_NOT_STORED, "NOT_STORED" }, |
37 MEMCACHE_RPL_EXISTS, |
35 { MEMCACHE_RPL_EXISTS, "EXISTS" }, |
38 MEMCACHE_RPL_NOT_FOUND, |
36 { MEMCACHE_RPL_NOT_FOUND, "NOT_FOUND" } |
39 |
|
40 }; |
37 }; |
41 |
38 |
42 */ |
39 |
43 |
40 |
44 int memcache_cmd_init (struct memcache_cmd *cmd, enum memcache_command cmd_type, struct memcache_key *key, struct memcache_obj *obj) { |
41 int memcache_cmd_init (struct memcache_cmd *cmd, enum memcache_command cmd_type, struct memcache_key *key, struct memcache_obj *obj) { |
45 // shouldn't already have a request header yet? |
42 // shouldn't already have a request header yet? |
46 assert(cmd->req_header == NULL); |
43 assert(cmd->req_header == NULL); |
47 |
44 |
115 return -1; |
112 return -1; |
116 |
113 |
117 } |
114 } |
118 |
115 |
119 int memcache_cmd_parse_header (struct evbuffer *buf, char **header_data, enum memcache_reply *reply_type, struct memcache_key *key, struct memcache_obj *obj, int *has_data) { |
116 int memcache_cmd_parse_header (struct evbuffer *buf, char **header_data, enum memcache_reply *reply_type, struct memcache_key *key, struct memcache_obj *obj, int *has_data) { |
120 // XXX: implement |
117 size_t line_length, buf_size; |
121 assert(0); |
118 char *line = NULL, *token_cursor, *token, *invalid; |
|
119 int i; |
|
120 |
|
121 // take note of how long the buffer is |
|
122 buf_size = evbuffer_get_length(buf); |
|
123 |
|
124 // first, try and read a full line |
|
125 if ((line = evbuffer_readln(buf, &line_length, EVBUFFER_EOL_CRLF_STRICT)) == NULL) { |
|
126 // check if any data was consumed |
|
127 if (evbuffer_get_length(buf) != buf_size) { |
|
128 // faaaail! |
|
129 return -1; |
|
130 |
|
131 } else { |
|
132 // no complete line found |
|
133 return 0; |
|
134 } |
|
135 } |
|
136 |
|
137 // just check to make sure that it really is null-delimited |
|
138 assert(line[line_length - 1] == '\0'); |
|
139 |
|
140 // empty lines? |
|
141 if (line_length == 0) { |
|
142 PWARNING("empty reply line !?!"); |
|
143 return 0; |
|
144 } |
|
145 |
|
146 // use strsep |
|
147 token_cursor = line; |
|
148 |
|
149 // the first token should be the reply name |
|
150 if ((token = strsep(&token_cursor, " ")) == NULL) |
|
151 ERROR("no reply name in response line: %s", line); |
|
152 |
|
153 // figure out the reply type |
|
154 for (i = MEMCACHE_RPL_INVALID + 1; i < MEMCACHE_RPL_MAX; i++) { |
|
155 if (strcmp(token, memcache_cmd_replies[i].name) == 0) |
|
156 break; |
|
157 } |
|
158 |
|
159 // did we figure out what this reply means? |
|
160 if (i == MEMCACHE_RPL_MAX) |
|
161 ERROR("unrecognized reply: %s", line); |
|
162 |
|
163 // we found the type |
|
164 *reply_type = memcache_cmd_replies[i].type; |
|
165 |
|
166 // default to no data |
|
167 *has_data = 0; |
|
168 |
|
169 switch (*reply_type) { |
|
170 case MEMCACHE_RPL_ERROR: |
|
171 // no additional data |
|
172 |
|
173 break; |
|
174 |
|
175 case MEMCACHE_RPL_CLIENT_ERROR: |
|
176 case MEMCACHE_RPL_SERVER_ERROR: |
|
177 // the rest of the line is a human-readable error message |
|
178 WARNING("received a %s reply: %s", token, token_cursor); |
|
179 |
|
180 break; |
|
181 |
|
182 case MEMCACHE_RPL_VALUE: |
|
183 // <key> <flags> <bytes> [<cas unique>] |
|
184 |
|
185 // the key field |
|
186 if ((key->buf = strsep(&token_cursor, " ")) == NULL) |
|
187 ERROR("missing key in VALUE reply"); |
|
188 |
|
189 if ((key->len = strlen(key->buf)) == 0) |
|
190 ERROR("zero-length key in VALUE reply"); |
|
191 |
|
192 // the flags field |
|
193 if ((token = strsep(&token_cursor, " ")) == NULL) |
|
194 ERROR("missing flags in VALUE reply"); |
|
195 |
|
196 obj->flags = (u_int32_t) strtol(token, &invalid, 10); |
|
197 |
|
198 if (*invalid != '\0') |
|
199 ERROR("invalid flags in VALUE reply: %s (%s)", token, invalid); |
|
200 |
|
201 // the bytes field |
|
202 if ((token = strsep(&token_cursor, " ")) == NULL) |
|
203 ERROR("missing bytes in VALUE reply"); |
|
204 |
|
205 obj->bytes = (u_int32_t) strtol(token, &invalid, 10); |
|
206 |
|
207 if (*invalid != '\0') |
|
208 ERROR("invalid bytes in VALUE reply: %s (%s)", token, invalid); |
|
209 |
|
210 // the optional cas field |
|
211 if ((token = strsep(&token_cursor, " ")) != NULL) { |
|
212 // there is a cas value present |
|
213 obj->cas = (u_int64_t) strtoll(token, &invalid, 10); |
|
214 |
|
215 if (*invalid != '\0') |
|
216 ERROR("invalid cas value in VALUE reply: %s (%s)", token, invalid); |
|
217 |
|
218 } else { |
|
219 obj->cas = 0; |
|
220 |
|
221 } |
|
222 |
|
223 // and we do have data following this |
|
224 *has_data = 1; |
|
225 |
|
226 break; |
|
227 |
|
228 case MEMCACHE_RPL_END: |
|
229 // no additional data |
|
230 |
|
231 break; |
|
232 |
|
233 case MEMCACHE_RPL_STORED: |
|
234 case MEMCACHE_RPL_NOT_STORED: |
|
235 case MEMCACHE_RPL_EXISTS: |
|
236 case MEMCACHE_RPL_NOT_FOUND: |
|
237 // no additional data |
|
238 |
|
239 break; |
|
240 |
|
241 default: |
|
242 assert(0); |
|
243 }; |
|
244 |
|
245 // success |
|
246 *header_data = line; |
|
247 |
|
248 return 0; |
|
249 |
|
250 error: |
|
251 free(line); |
|
252 |
|
253 return -1; |
122 } |
254 } |
123 |
255 |