Fix to make all keys null terminated (sort of surprised that I had not done
[awesomized/libmemcached] / lib / memcached_fetch.c
1 #include "common.h"
2 #include "memcached_io.h"
3
4 memcached_return value_fetch(memcached_st *ptr,
5 char *buffer,
6 memcached_result_st *result,
7 unsigned int server_key)
8 {
9 memcached_return rc;
10 char *string_ptr;
11 char *end_ptr;
12 char *next_ptr;
13 size_t value_length;
14
15 end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
16
17 result->key_length= 0;
18 result->flags= 0;
19 memcached_string_reset(&result->value);
20
21 string_ptr= buffer;
22 string_ptr+= 6; /* "VALUE " */
23
24
25 /* We load the key */
26 {
27 char *key;
28
29 key= result->key;
30 result->key_length= 0;
31
32 for (; isgraph(*string_ptr); string_ptr++)
33 {
34 *key= *string_ptr;
35 key++;
36 result->key_length++;
37 }
38 result->key[result->key_length]= 0;
39 }
40
41 if (end_ptr == string_ptr)
42 goto read_error;
43
44 /* Flags fetch move past space */
45 string_ptr++;
46 if (end_ptr == string_ptr)
47 goto read_error;
48 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
49 result->flags= (uint32_t)strtol(next_ptr, &string_ptr, 10);
50
51 if (end_ptr == string_ptr)
52 goto read_error;
53
54 /* Length fetch move past space*/
55 string_ptr++;
56 if (end_ptr == string_ptr)
57 goto read_error;
58
59 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
60 value_length= (size_t)strtoll(next_ptr, &string_ptr, 10);
61
62 if (end_ptr == string_ptr)
63 goto read_error;
64
65 /* Skip spaces */
66 if (*string_ptr == '\r')
67 {
68 /* Skip past the \r\n */
69 string_ptr+= 2;
70 result->cas= 0;
71 }
72 else
73 {
74 string_ptr++;
75 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
76 result->cas= (size_t)strtoll(next_ptr, &string_ptr, 10);
77 }
78
79 if (end_ptr < string_ptr)
80 goto read_error;
81
82 if (value_length)
83 {
84 size_t read_length;
85 size_t to_read;
86 char *value_ptr;
87
88 /* We add two bytes so that we can walk the \r\n */
89 rc= memcached_string_check(&result->value, value_length+2);
90 if (rc != MEMCACHED_SUCCESS)
91 {
92 value_length= 0;
93 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
94 }
95
96 value_ptr= memcached_string_value(&result->value);
97 read_length= 0;
98 /*
99 We read the \r\n into the string since not doing so is more
100 cycles then the waster of memory to do so.
101
102 We are null terminating through, which will most likely make
103 some people lazy about using the return length.
104 */
105 to_read= (value_length) + 2;
106
107 read_length= memcached_io_read(ptr, server_key,
108 value_ptr, to_read);
109
110 if (read_length != (size_t)(value_length + 2))
111 {
112 goto read_error;
113 }
114
115 /* This next bit blows the API, but this is internal....*/
116 {
117 char *char_ptr;
118 char_ptr= memcached_string_value(&result->value);;
119 char_ptr[value_length]= 0;
120 char_ptr[value_length + 1]= 0;
121 memcached_string_set_length(&result->value, value_length);
122 }
123
124 return MEMCACHED_SUCCESS;
125 }
126
127 return rc;
128
129 read_error:
130 return MEMCACHED_PARTIAL_READ;
131 }
132
133 char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
134 size_t *value_length,
135 uint32_t *flags,
136 memcached_return *error)
137 {
138 memcached_result_st *result_buffer= &ptr->result;
139
140 while (ptr->cursor_server < ptr->number_of_hosts)
141 {
142 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
143
144 if (memcached_server_response_count(ptr, ptr->cursor_server) == 0)
145 {
146 ptr->cursor_server++;
147 continue;
148 }
149
150 *error= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, result_buffer, ptr->cursor_server);
151
152 if (*error == MEMCACHED_END) /* END means that we move on to the next */
153 {
154 memcached_server_response_reset(ptr, ptr->cursor_server);
155 ptr->cursor_server++;
156 continue;
157 }
158 else if (*error == MEMCACHED_SUCCESS)
159 {
160 *value_length= memcached_string_length(&result_buffer->value);
161
162 if (key)
163 {
164 strncpy(key, result_buffer->key, result_buffer->key_length);
165 *key_length= result_buffer->key_length;
166 }
167 *flags= result_buffer->flags;
168
169 return memcached_string_c_copy(&result_buffer->value);
170 }
171 else
172 {
173 *value_length= 0;
174 return NULL;
175 }
176 }
177
178 ptr->cursor_server= 0;
179 *value_length= 0;
180 return NULL;
181 }
182
183 memcached_result_st *memcached_fetch_result(memcached_st *ptr,
184 memcached_result_st *result,
185 memcached_return *error)
186 {
187 if (result == NULL)
188 result= memcached_result_create(ptr, NULL);
189
190 WATCHPOINT_ASSERT(result->value.is_allocated != MEMCACHED_USED);
191
192 if (ptr->flags & MEM_NO_BLOCK)
193 memcached_io_preread(ptr);
194
195 while (ptr->cursor_server < ptr->number_of_hosts)
196 {
197 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
198
199 if (memcached_server_response_count(ptr, ptr->cursor_server) == 0)
200 {
201 ptr->cursor_server++;
202 continue;
203 }
204
205 *error= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, result, ptr->cursor_server);
206
207 if (*error == MEMCACHED_END) /* END means that we move on to the next */
208 {
209 memcached_server_response_reset(ptr, ptr->cursor_server);
210 ptr->cursor_server++;
211 continue;
212 }
213 else if (*error == MEMCACHED_SUCCESS)
214 return result;
215 else
216 return NULL;
217 }
218
219 /* We have completed reading data */
220 if (result->is_allocated == MEMCACHED_ALLOCATED)
221 memcached_result_free(result);
222 else
223 memcached_string_reset(&result->value);
224
225 ptr->cursor_server= 0;
226 return NULL;
227 }