Fixed strings returned by get to be null terminated (request by Cal
[awesomized/libmemcached] / lib / memcached_get.c
1 #include "common.h"
2 #include "memcached_io.h"
3
4 static char *memcached_value_fetch(memcached_st *ptr, char *key, size_t *key_length,
5 size_t *value_length,
6 uint16_t *flags,
7 memcached_return *error,
8 char load_key,
9 unsigned int server_key)
10 {
11 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
12 char *string_ptr;
13 char *end_ptr;
14
15 assert(value_length);
16 assert(flags);
17 assert(error);
18
19 memset(buffer, 0, MEMCACHED_DEFAULT_COMMAND_SIZE);
20 end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
21
22 *value_length= 0;
23
24 *error= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
25
26 if (*error == MEMCACHED_SUCCESS)
27 {
28 char *next_ptr;
29
30 string_ptr= buffer;
31 string_ptr+= 6; /* "VALUE " */
32
33 /* We load the key */
34 if (load_key)
35 {
36 memset(key, 0, MEMCACHED_MAX_KEY);
37 *key_length= 0;
38
39 for (; end_ptr == string_ptr || *string_ptr != ' '; string_ptr++)
40 {
41 *key= *string_ptr;
42 key++;
43 (*key_length)++;
44 }
45 }
46 else /* Skip characters */
47 for (; end_ptr == string_ptr || *string_ptr != ' '; string_ptr++);
48
49 if (end_ptr == string_ptr)
50 goto read_error;
51
52 /* Flags fetch move past space */
53 string_ptr++;
54 if (end_ptr == string_ptr)
55 goto read_error;
56 for (next_ptr= string_ptr; end_ptr == string_ptr || *string_ptr != ' '; string_ptr++);
57 *flags= (uint16_t)strtol(next_ptr, &string_ptr, 10);
58
59 if (end_ptr == string_ptr)
60 goto read_error;
61
62 /* Length fetch move past space*/
63 string_ptr++;
64 if (end_ptr == string_ptr)
65 goto read_error;
66
67 for (next_ptr= string_ptr; end_ptr == string_ptr || *string_ptr != ' '; string_ptr++);
68 *value_length= (size_t)strtoll(next_ptr, &string_ptr, 10);
69
70 if (end_ptr == string_ptr)
71 goto read_error;
72
73 /* Skip past the \r\n */
74 string_ptr+= 2;
75
76 if (end_ptr < string_ptr)
77 goto read_error;
78
79 if (*value_length)
80 {
81 size_t read_length;
82 size_t to_read;
83 char *value;
84 char *value_ptr;
85
86 /* We add two bytes so that we can walk the \r\n */
87 value= (char *)malloc(((*value_length) +2) * sizeof(char));
88 memset(value, 0, ((*value_length) +2) * sizeof(char));
89
90 if (!value)
91 {
92 *value_length= 0;
93 *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
94 return NULL;
95 }
96
97 value_ptr= value;
98 read_length= 0;
99 /*
100 We read the \r\n into the string since not doing so is more
101 cycles then the waster of memory to do so.
102
103 We are null terminating through, which will most likely make
104 some people lazy about using the return length.
105 */
106 to_read= (*value_length) + 2;
107
108 read_length= memcached_io_read(ptr, server_key,
109 value_ptr, to_read);
110
111 if (read_length != (size_t)(*value_length + 2))
112 {
113 free(value);
114 goto read_error;
115 }
116
117 value[*value_length]= 0;
118 value[(*value_length) + 1]= 0;
119
120 return value;
121 }
122 }
123 else if (*error == MEMCACHED_END)
124 *error= MEMCACHED_NOTFOUND;
125
126 return NULL;
127 read_error:
128 *error= MEMCACHED_PARTIAL_READ;
129 return NULL;
130 }
131
132 char *memcached_get(memcached_st *ptr, char *key, size_t key_length,
133 size_t *value_length,
134 uint16_t *flags,
135 memcached_return *error)
136 {
137 size_t send_length;
138 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
139 unsigned int server_key;
140 char *value;
141 LIBMEMCACHED_MEMCACHED_GET_START();
142
143 server_key= memcached_generate_hash(ptr, key, key_length);
144
145 *value_length= 0;
146 *error= memcached_connect(ptr, server_key);
147
148 if (*error != MEMCACHED_SUCCESS)
149 goto error;
150
151 send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, "get %.*s\r\n",
152 (int)key_length, key);
153
154 if ((memcached_io_write(ptr, server_key, buffer, send_length, 1)) == -1)
155 {
156 *error= MEMCACHED_WRITE_FAILURE;
157 goto error;
158 }
159
160 value= memcached_value_fetch(ptr, key, &key_length, value_length, flags,
161 error, 0, server_key);
162 if (*error == MEMCACHED_END && *value_length == 0)
163 {
164 *error= MEMCACHED_NOTFOUND;
165 goto error;
166 }
167 else if (*error == MEMCACHED_SUCCESS)
168 {
169 memcached_return rc;
170 /* We need to read END */
171 rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
172
173 if (rc != MEMCACHED_END)
174 {
175 *error= MEMCACHED_PROTOCOL_ERROR;
176 goto error;
177 }
178 }
179 else
180 goto error;
181
182 LIBMEMCACHED_MEMCACHED_GET_END();
183
184 return value;
185
186 error:
187 free(value);
188 *value_length= 0;
189
190 LIBMEMCACHED_MEMCACHED_GET_END();
191
192 return NULL;
193 }
194
195 memcached_return memcached_mget(memcached_st *ptr,
196 char **keys, size_t *key_length,
197 unsigned int number_of_keys)
198 {
199 char buffer[HUGE_STRING_LEN];
200 unsigned int x;
201 memcached_return rc;
202 memcached_string_st **cursor_key_exec;
203 LIBMEMCACHED_MEMCACHED_MGET_START();
204
205 ptr->cursor_server= 0;
206 memset(buffer, 0, HUGE_STRING_LEN);
207
208 cursor_key_exec= (memcached_string_st **)malloc(sizeof(memcached_string_st *) * ptr->number_of_hosts);
209 memset(cursor_key_exec, 0, sizeof(memcached_string_st *) * ptr->number_of_hosts);
210
211
212 for (x= 0; x < number_of_keys; x++)
213 {
214 unsigned int server_key;
215
216 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
217
218 if (cursor_key_exec[server_key])
219 {
220 memcached_string_st *string= cursor_key_exec[server_key];
221
222 memcached_string_append_character(ptr, string, ' ');
223 memcached_string_append(ptr, string, keys[x], key_length[x]);
224 }
225 else
226 {
227 memcached_string_st *string= memcached_string_create(ptr, SMALL_STRING_LEN);
228
229 /* We need to figure out the correct way to error in case of this failure */
230 if (!string)
231 assert(0);
232
233 memcached_string_append(ptr, string, "get ", 4);
234 memcached_string_append(ptr, string, keys[x], key_length[x]);
235
236 cursor_key_exec[server_key]= string;
237 }
238 }
239
240
241 /*
242 Should we muddle on if some servers are dead?
243 */
244 for (x= 0; x < ptr->number_of_hosts; x++)
245 {
246 if (cursor_key_exec[x])
247 {
248 /* We need to doo something about non-connnected hosts in the future */
249 rc= memcached_connect(ptr, x);
250
251 memcached_string_st *string= cursor_key_exec[x];
252 memcached_string_append(ptr, string, "\r\n", 2);
253
254 if ((memcached_io_write(ptr, x, string->string,
255 memcached_string_length(ptr, string), 1)) == -1)
256 {
257 memcached_quit(ptr);
258 rc= MEMCACHED_SOME_ERRORS;
259 }
260 memcached_string_free(ptr, string);
261 cursor_key_exec[x]= NULL; /* Remove warning */
262 }
263 }
264
265 free(cursor_key_exec);
266
267 LIBMEMCACHED_MEMCACHED_MGET_END();
268 return rc;
269 }
270
271 char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
272 size_t *value_length,
273 uint16_t *flags,
274 memcached_return *error)
275 {
276 char *value_check;
277
278 while (ptr->cursor_server < ptr->number_of_hosts)
279 {
280 value_check= memcached_value_fetch(ptr, key, key_length, value_length, flags,
281 error, 1, ptr->cursor_server);
282
283 if (*error == MEMCACHED_NOTFOUND)
284 ptr->cursor_server++;
285 else if (*error != MEMCACHED_SUCCESS)
286 return NULL;
287 else
288 return value_check;
289 }
290
291 return NULL;
292 }