Fixed bug where zero length key was provided.
[awesomized/libmemcached] / lib / memcached_get.c
1 #include "common.h"
2 #include "memcached_io.h"
3
4 static memcached_return memcached_value_fetch(memcached_st *ptr, char *key, size_t *key_length,
5 memcached_string_st *value,
6 uint16_t *flags,
7 char load_key,
8 unsigned int server_key)
9 {
10 memcached_return rc;
11 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
12 char *string_ptr;
13 char *end_ptr;
14
15 memset(buffer, 0, MEMCACHED_DEFAULT_COMMAND_SIZE);
16 end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
17
18 *flags= 0;
19
20 memcached_string_reset(value);
21
22 rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
23
24 if (rc == MEMCACHED_SUCCESS)
25 {
26 char *next_ptr;
27 size_t value_length;
28
29 string_ptr= buffer;
30 string_ptr+= 6; /* "VALUE " */
31
32 /* We load the key */
33 if (load_key)
34 {
35 memset(key, 0, MEMCACHED_MAX_KEY);
36 *key_length= 0;
37
38 for (; end_ptr > string_ptr && *string_ptr != ' '; string_ptr++)
39 {
40 *key= *string_ptr;
41 key++;
42 (*key_length)++;
43 }
44 }
45 else /* Skip characters */
46 for (; end_ptr > string_ptr && *string_ptr != ' '; string_ptr++);
47
48 if (end_ptr == string_ptr)
49 goto read_error;
50
51 /* Flags fetch move past space */
52 string_ptr++;
53 if (end_ptr == string_ptr)
54 goto read_error;
55 for (next_ptr= string_ptr; end_ptr > string_ptr && *string_ptr != ' '; string_ptr++);
56 *flags= (uint16_t)strtol(next_ptr, &string_ptr, 10);
57
58 if (end_ptr == string_ptr)
59 goto read_error;
60
61 /* Length fetch move past space*/
62 string_ptr++;
63 if (end_ptr == string_ptr)
64 goto read_error;
65
66 for (next_ptr= string_ptr; end_ptr > string_ptr && *string_ptr != ' '; string_ptr++);
67 value_length= (size_t)strtoll(next_ptr, &string_ptr, 10);
68
69 if (end_ptr == string_ptr)
70 goto read_error;
71
72 /* Skip past the \r\n */
73 string_ptr+= 2;
74
75 if (end_ptr < string_ptr)
76 goto read_error;
77
78 if (value_length)
79 {
80 size_t read_length;
81 size_t to_read;
82 char *value_ptr;
83
84 /* We add two bytes so that we can walk the \r\n */
85 rc= memcached_string_check(value, value_length+2);
86 if (rc != MEMCACHED_SUCCESS)
87 {
88 value_length= 0;
89 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
90 }
91
92 value_ptr= memcached_string_value(value);
93 read_length= 0;
94 /*
95 We read the \r\n into the string since not doing so is more
96 cycles then the waster of memory to do so.
97
98 We are null terminating through, which will most likely make
99 some people lazy about using the return length.
100 */
101 to_read= (value_length) + 2;
102
103 read_length= memcached_io_read(ptr, server_key,
104 value_ptr, to_read);
105
106 if (read_length != (size_t)(value_length + 2))
107 {
108 goto read_error;
109 }
110
111 /* This next bit blows the API, but this is internal....*/
112 {
113 char *char_ptr;
114 char_ptr= memcached_string_value(value);;
115 char_ptr[value_length]= 0;
116 char_ptr[value_length + 1]= 0;
117 memcached_string_set_length(value, value_length);
118 }
119
120 return MEMCACHED_SUCCESS;
121 }
122 }
123 else if (rc == MEMCACHED_END)
124 rc= MEMCACHED_NOTFOUND;
125
126 return rc;
127
128 read_error:
129 return MEMCACHED_PARTIAL_READ;
130 }
131
132 /*
133 What happens if no servers exist?
134 */
135 char *memcached_get(memcached_st *ptr, char *key, size_t key_length,
136 size_t *value_length,
137 uint16_t *flags,
138 memcached_return *error)
139 {
140 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
141 char *buf_ptr= buffer;
142 unsigned int server_key;
143 memcached_string_st *result_buffer;
144 LIBMEMCACHED_MEMCACHED_GET_START();
145
146 if (key_length == 0)
147 return MEMCACHED_NO_KEY_PROVIDED;
148
149 if (ptr->hosts == NULL || ptr->number_of_hosts == 0)
150 {
151 *error= MEMCACHED_NO_SERVERS;
152 return NULL;
153 }
154
155 server_key= memcached_generate_hash(ptr, key, key_length);
156 result_buffer= &ptr->result_buffer;
157
158 *value_length= 0;
159 *error= memcached_connect(ptr, server_key);
160
161 if (*error != MEMCACHED_SUCCESS)
162 goto error;
163
164 memcpy(buf_ptr, "get ", 4);
165 buf_ptr+= 4;
166 memcpy(buf_ptr, key, key_length);
167 buf_ptr+= key_length;
168 memcpy(buf_ptr, "\r\n", 2);
169 buf_ptr+= 2;
170
171 if ((memcached_io_write(ptr, server_key, buffer, (size_t)(buf_ptr - buffer), 1)) == -1)
172 {
173 *error= MEMCACHED_WRITE_FAILURE;
174 goto error;
175 }
176
177 *error= memcached_value_fetch(ptr, key, &key_length, result_buffer,
178 flags, 0, server_key);
179 *value_length= memcached_string_length(result_buffer);
180 if (*error == MEMCACHED_END && *value_length == 0)
181 {
182 *error= MEMCACHED_NOTFOUND;
183 goto error;
184 }
185 else if (*error == MEMCACHED_END)
186 {
187 WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */
188 }
189 else if (*error == MEMCACHED_SUCCESS)
190 {
191 memcached_return rc;
192 /* We need to read END */
193 rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
194
195 if (rc != MEMCACHED_END)
196 {
197 *error= MEMCACHED_PROTOCOL_ERROR;
198 goto error;
199 }
200 }
201 else
202 goto error;
203
204 LIBMEMCACHED_MEMCACHED_GET_END();
205
206
207 return memcached_string_c_copy(result_buffer);
208
209 error:
210 *value_length= 0;
211
212 LIBMEMCACHED_MEMCACHED_GET_END();
213
214 return NULL;
215 }
216
217 memcached_return memcached_mget(memcached_st *ptr,
218 char **keys, size_t *key_length,
219 unsigned int number_of_keys)
220 {
221 unsigned int x;
222 memcached_return rc= MEMCACHED_NOTFOUND;
223 char *cursor_key_exec;
224 LIBMEMCACHED_MEMCACHED_MGET_START();
225 ptr->cursor_server= 0;
226
227 if (number_of_keys == 0)
228 return MEMCACHED_NOTFOUND;
229
230 if (ptr->number_of_hosts == 0)
231 return MEMCACHED_NO_SERVERS;
232
233 cursor_key_exec= (char *)malloc(sizeof(char) * ptr->number_of_hosts);
234 memset(cursor_key_exec, 0, sizeof(char) * ptr->number_of_hosts);
235
236 for (x= 0; x < number_of_keys; x++)
237 {
238 unsigned int server_key;
239
240 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
241
242 if (cursor_key_exec[server_key] == 0)
243 {
244 rc= memcached_connect(ptr, server_key);
245
246 if ((memcached_io_write(ptr, server_key, "get ", 4, 0)) == -1)
247 {
248 memcached_quit(ptr);
249 rc= MEMCACHED_SOME_ERRORS;
250 break;
251 }
252 }
253
254 if ((memcached_io_write(ptr, server_key, keys[x], key_length[x], 0)) == -1)
255 {
256 memcached_quit(ptr);
257 rc= MEMCACHED_SOME_ERRORS;
258 break;
259 }
260
261 if ((memcached_io_write(ptr, server_key, " ", 1, 0)) == -1)
262 {
263 memcached_quit(ptr);
264 rc= MEMCACHED_SOME_ERRORS;
265 break;
266 }
267 cursor_key_exec[server_key]= 1;
268 }
269
270
271 /*
272 Should we muddle on if some servers are dead?
273 */
274 for (x= 0; x < ptr->number_of_hosts; x++)
275 {
276 if (cursor_key_exec[x])
277 {
278 /* We need to doo something about non-connnected hosts in the future */
279 if ((memcached_io_write(ptr, x, "\r\n", 2, 1)) == -1)
280 {
281 memcached_quit(ptr);
282 rc= MEMCACHED_SOME_ERRORS;
283 break;
284 }
285
286 ptr->hosts[x].cursor_active= 1;
287 }
288 else
289 ptr->hosts[x].cursor_active= 0;
290 }
291
292 free(cursor_key_exec);
293
294 LIBMEMCACHED_MEMCACHED_MGET_END();
295 return rc;
296 }
297
298 char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
299 size_t *value_length,
300 uint16_t *flags,
301 memcached_return *error)
302 {
303 memcached_string_st *result_buffer;
304 result_buffer= &ptr->result_buffer;
305
306 while (ptr->cursor_server < ptr->number_of_hosts)
307 {
308 if (!ptr->hosts[ptr->cursor_server].cursor_active)
309 {
310 ptr->cursor_server++;
311 continue;
312 }
313
314 *error = memcached_value_fetch(ptr, key, key_length, result_buffer,
315 flags, 1, ptr->cursor_server);
316 *value_length= memcached_string_length(result_buffer);
317
318 if (*error == MEMCACHED_NOTFOUND)
319 ptr->cursor_server++;
320 else if (*error == MEMCACHED_END && *value_length == 0)
321 return NULL;
322 else if (*error == MEMCACHED_END)
323 {
324 WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */
325 return NULL;
326 }
327 else if (*error != MEMCACHED_SUCCESS)
328 return NULL;
329 else
330 return memcached_string_c_copy(result_buffer);
331
332 }
333
334 *value_length= 0;
335 return NULL;
336 }
337
338 memcached_result_st *memcached_fetch_result(memcached_st *ptr,
339 memcached_result_st *result,
340 memcached_return *error)
341 {
342 if (result == NULL)
343 result= memcached_result_create(ptr, NULL);
344
345 while (ptr->cursor_server < ptr->number_of_hosts)
346 {
347 if (!ptr->hosts[ptr->cursor_server].cursor_active)
348 {
349 ptr->cursor_server++;
350 continue;
351 }
352
353 *error= memcached_value_fetch(ptr, result->key, &result->key_length,
354 &result->value,
355 &result->flags,
356 1, ptr->cursor_server);
357
358 if (*error == MEMCACHED_NOTFOUND)
359 ptr->cursor_server++;
360 else if (*error == MEMCACHED_END && memcached_string_length((memcached_string_st *)(&result->value)) == 0)
361 return NULL;
362 else if (*error == MEMCACHED_END)
363 {
364 WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */
365 return NULL;
366 }
367 else if (*error != MEMCACHED_SUCCESS)
368 return NULL;
369 else
370 return result;
371
372 }
373
374 return NULL;
375 }