First import.
[awesomized/libmemcached] / lib / memcached.c
1 /*
2 Memcached library
3 */
4 #include <memcached.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12 #include <netdb.h>
13 #include <unistd.h>
14 #include <limits.h>
15 #include <assert.h>
16
17
18 memcached_st *memcached_init(memcached_st *ptr)
19 {
20 if (!ptr)
21 {
22 ptr= (memcached_st *)malloc(sizeof(memcached_st));
23
24 if (!ptr)
25 return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
26
27 memset(ptr, 0, sizeof(memcached_st));
28 ptr->is_allocated= MEMCACHED_ALLOCATED;
29 }
30 else
31 {
32 memset(ptr, 0, sizeof(memcached_st));
33 }
34 ptr->fd= -1;
35
36 return ptr;
37 }
38
39 void memcached_server_add(memcached_st *ptr, char *server_name, unsigned int port)
40 {
41 }
42
43 static memcached_return memcached_connect(memcached_st *ptr)
44 {
45 int rc;
46 struct sockaddr_in localAddr, servAddr;
47 struct hostent *h;
48 char *server_name= "localhost";
49
50 if (ptr->connected)
51 return MEMCACHED_SUCCESS;
52
53
54 if ((h= gethostbyname(server_name)) == NULL)
55 {
56 fprintf(stderr, "unknown host '%s'\n", server_name);
57 return MEMCACHED_HOST_LOCKUP_FAILURE;
58 }
59
60 servAddr.sin_family= h->h_addrtype;
61 memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
62 servAddr.sin_port = htons(MEMCACHED_DEFAULT_PORT);
63
64 /* Create the socket */
65 if ((ptr->fd= socket(AF_INET, SOCK_STREAM, 0)) < 0)
66 {
67 fprintf(stderr, "cannot open socket");
68 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
69 }
70
71
72 /* bind any port number */
73 localAddr.sin_family = AF_INET;
74 localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
75 localAddr.sin_port = htons(0);
76
77 if (bind(ptr->fd, (struct sockaddr *) &localAddr, sizeof(localAddr)) < 0)
78 {
79 fprintf(stderr, "cannot bind port TCP %u\n", MEMCACHED_DEFAULT_PORT);
80 return(MEMCACHED_CONNECTION_BIND_FAILURE);
81 }
82
83 /* connect to server */
84 if (connect(ptr->fd, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
85 {
86 fprintf(stderr, "cannot connect to host '%s'\n", server_name);
87 return MEMCACHED_HOST_LOCKUP_FAILURE;
88 }
89
90 ptr->connected= 1;
91
92 return MEMCACHED_SUCCESS;
93 }
94
95 static memcached_return memcached_response(memcached_st *ptr,
96 char *buffer, size_t buffer_length)
97 {
98 size_t send_length;
99 send_length= read(ptr->fd, buffer, buffer_length);
100
101 /* This should never happen, if it does it means that key must now be quite large. */
102 assert(send_length != buffer_length);
103
104 if (send_length)
105 switch(buffer[0])
106 {
107 case 'V': /* VALUE */
108 return MEMCACHED_SUCCESS;
109 case 'O': /* OK */
110 return MEMCACHED_SUCCESS;
111 case 'S': /* STORED */
112 {
113 if (buffer[1] == 'T')
114 return MEMCACHED_SUCCESS;
115 else if (buffer[1] == 'E')
116 return MEMCACHED_SERVER_ERROR;
117 else
118 return MEMCACHED_UNKNOWN_READ_FAILURE;
119 }
120 case 'D': /* DELETED */
121 return MEMCACHED_SUCCESS;
122 case 'N': /* NOT_FOUND */
123 {
124 if (buffer[4] == 'F')
125 return MEMCACHED_NOTFOUND;
126 else if (buffer[4] == 'S')
127 return MEMCACHED_NOTSTORED;
128 else
129 return MEMCACHED_UNKNOWN_READ_FAILURE;
130 }
131 case 'E': /* PROTOCOL ERROR */
132 return MEMCACHED_PROTOCOL_ERROR;
133 case 'C': /* CLIENT ERROR */
134 return MEMCACHED_CLIENT_ERROR;
135 default:
136 return MEMCACHED_UNKNOWN_READ_FAILURE;
137 }
138
139 return MEMCACHED_READ_FAILURE;
140 }
141
142 static memcached_return memcached_send(memcached_st *ptr,
143 char *key, size_t key_length,
144 char *value, size_t value_length,
145 time_t expiration,
146 uint16_t flags,
147 char *verb)
148 {
149 size_t send_length;
150 memcached_return rc;
151 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
152
153 rc= memcached_connect(ptr);
154
155 send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
156 "%s %.*s %u %u %u\r\n", verb,
157 key_length, key, flags, expiration, value_length);
158 if ((send(ptr->fd, buffer, send_length, 0) == -1))
159 {
160 fprintf(stderr, "failed set on %.*s TCP\n", key_length+1, key);
161
162 return MEMCACHED_WRITE_FAILURE;
163 }
164
165 send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
166 "%.*s\r\n",
167 value_length, value);
168 if ((send(ptr->fd, buffer, send_length, 0) == -1))
169 {
170 fprintf(stderr, "failed set on %.*s TCP\n", key_length+1, key);
171
172 return MEMCACHED_WRITE_FAILURE;
173 }
174
175 send_length= read(ptr->fd, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE);
176
177 if (send_length && buffer[0] == 'S') /* STORED */
178 return MEMCACHED_SUCCESS;
179 else if (send_length && buffer[0] == 'N') /* NOT_STORED */
180 return MEMCACHED_NOTSTORED;
181 else
182 return MEMCACHED_READ_FAILURE;
183 }
184
185 memcached_return memcached_set(memcached_st *ptr, char *key, size_t key_length,
186 char *value, size_t value_length,
187 time_t expiration,
188 uint16_t flags)
189 {
190 return memcached_send(ptr, key, key_length, value, value_length,
191 expiration, flags, "set");
192 }
193
194 memcached_return memcached_add(memcached_st *ptr, char *key, size_t key_length,
195 char *value, size_t value_length,
196 time_t expiration,
197 uint16_t flags)
198 {
199 return memcached_send(ptr, key, key_length, value, value_length,
200 expiration, flags, "add");
201 }
202
203 memcached_return memcached_replace(memcached_st *ptr, char *key, size_t key_length,
204 char *value, size_t value_length,
205 time_t expiration,
206 uint16_t flags)
207 {
208 return memcached_send(ptr, key, key_length, value, value_length,
209 expiration, flags, "replace");
210 }
211
212 memcached_return memcached_delete(memcached_st *ptr, char *key, size_t key_length,
213 time_t expiration)
214 {
215 size_t send_length;
216 memcached_return rc;
217 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
218
219 rc= memcached_connect(ptr);
220
221 if (expiration)
222 send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
223 "delete %.*s %u\r\n", key_length, key, expiration);
224 else
225 send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
226 "delete %.*s\r\n", key_length, key);
227 if ((write(ptr->fd, buffer, send_length) == -1))
228 {
229 fprintf(stderr, "failed set on %.*s TCP\n", key_length+1, key);
230
231 return MEMCACHED_WRITE_FAILURE;
232 }
233
234 return memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE);
235 }
236
237 memcached_return memcached_increment(memcached_st *ptr, char *key, size_t key_length,
238 unsigned int count)
239 {
240 return MEMCACHED_SUCCESS;
241 }
242
243 memcached_return memcached_decrement(memcached_st *ptr, char *key, size_t key_length,
244 unsigned int count)
245 {
246 return MEMCACHED_SUCCESS;
247 }
248
249 memcached_return memcached_stat(memcached_st *ptr, memcached_stat_st *stat)
250 {
251 size_t send_length;
252 memcached_return rc;
253 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
254
255 rc= memcached_connect(ptr);
256
257 send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
258 "stats \r\n");
259 if ((send(ptr->fd, buffer, send_length, 0) == -1))
260 {
261 fprintf(stderr, "failed on stats\n");
262
263 return MEMCACHED_WRITE_FAILURE;
264 }
265
266 while((send_length= read(ptr->fd, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE)) > 0)
267 {
268 if (send_length && buffer[0] == 'D') /* DELETED */
269 return MEMCACHED_SUCCESS;
270 else if (send_length && buffer[0] == 'N') /* NOT FOUND */
271 return MEMCACHED_NOTFOUND;
272 else if (send_length && buffer[0] == 'E') /* PROTOCOL ERROR */
273 return MEMCACHED_PROTOCOL_ERROR;
274 else if (send_length && buffer[0] == 'C') /* CLIENT ERROR */
275 return MEMCACHED_CLIENT_ERROR;
276 else if (send_length && buffer[0] == 'S') /* SERVER ERROR */
277 return MEMCACHED_SERVER_ERROR;
278 else if (send_length) /* UNKNOWN READ FAILURE */
279 {
280 fprintf(stderr, "UNKNOWN %.*s\n", send_length, buffer);
281 return MEMCACHED_UNKNOWN_READ_FAILURE;
282 }
283 else
284 return MEMCACHED_READ_FAILURE;
285 }
286 }
287
288 memcached_return memcached_flush(memcached_st *ptr, time_t expiration)
289 {
290 size_t send_length;
291 memcached_return rc;
292 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
293
294 rc= memcached_connect(ptr);
295
296 if (expiration)
297 send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
298 "flush_all %u\r\n", expiration);
299 else
300 send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
301 "flush_all\r\n");
302 if ((send(ptr->fd, buffer, send_length, 0) == -1))
303 {
304 fprintf(stderr, "failed flush_all TCP\n");
305
306 return MEMCACHED_WRITE_FAILURE;
307 }
308
309 return memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE);
310 }
311
312 char *memcached_version(memcached_st *ptr, memcached_return *error)
313 {
314 return MEMCACHED_SUCCESS;
315 }
316
317 memcached_return memcached_verbosity(memcached_st *ptr, unsigned int verbosity)
318 {
319 return MEMCACHED_SUCCESS;
320 }
321
322 memcached_return memcached_quit(memcached_st *ptr)
323 {
324 return MEMCACHED_SUCCESS;
325 }
326
327
328 char *memcached_get(memcached_st *ptr, char *key, size_t key_length,
329 size_t *value_length,
330 uint16_t *flags,
331 memcached_return *error)
332 {
333 size_t send_length;
334 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
335 char *string_ptr;
336
337 *error= memcached_connect(ptr);
338
339 send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, "get %.*s\r\n",
340 key_length, key);
341 if (*error != MEMCACHED_SUCCESS)
342 return NULL;
343
344 if ((send(ptr->fd, buffer, send_length, 0) == -1))
345 {
346 fprintf(stderr, "failed fetch on %.*s TCP\n", key_length+1, key);
347 *error= MEMCACHED_WRITE_FAILURE;
348 return NULL;
349 }
350
351 memset(buffer, 0, MEMCACHED_DEFAULT_COMMAND_SIZE);
352 *error= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE);
353
354 if (*error == MEMCACHED_SUCCESS)
355 {
356 char *end_ptr;
357
358 string_ptr= buffer;
359 string_ptr+= 6; /* "VALUE " */
360
361 /* We do nothing with the key, since we only asked for one key */
362 for (end_ptr= string_ptr; *end_ptr != ' '; end_ptr++);
363
364 /* Flags fetch */
365 string_ptr= end_ptr + 1;
366 for (end_ptr= string_ptr; *end_ptr != ' '; end_ptr++);
367 *flags= (uint16_t)strtol(string_ptr, &end_ptr, 10);
368
369 /* Length fetch */
370 string_ptr= end_ptr + 1;
371 for (end_ptr= string_ptr; *end_ptr != ' '; end_ptr++);
372 *value_length= strtoll(string_ptr, &end_ptr, 10);
373
374 /* Skip past the \r\n */
375 string_ptr= end_ptr +2;
376
377 if (*value_length)
378 {
379 size_t need_to_copy;
380 char *pos_ptr;
381 char *value;
382
383 value= (char *)malloc(*value_length * sizeof(char));
384
385 if (!value)
386 {
387 *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
388 return NULL;
389 }
390
391 need_to_copy= (*value_length < (size_t)(buffer-string_ptr))
392 ? *value_length
393 : (size_t)(buffer-string_ptr) ;
394
395 pos_ptr= memcpy(value, string_ptr, need_to_copy);
396
397 if ( need_to_copy > *value_length)
398 {
399 size_t read_length;
400 size_t need_to_read;
401
402 need_to_read= *value_length - need_to_copy;
403
404 read_length= read(ptr->fd, pos_ptr, need_to_read);
405 if (read_length != need_to_read)
406 {
407 free(value);
408 *error= MEMCACHED_PARTIAL_READ;
409
410 return NULL;
411 }
412 }
413
414 return value;
415 }
416 }
417
418 return NULL;
419 }
420
421 void memcached_deinit(memcached_st *ptr)
422 {
423 if (ptr->fd == -1)
424 close(ptr->fd);
425
426 if (ptr->is_allocated == MEMCACHED_ALLOCATED)
427 free(ptr);
428 else
429 memset(ptr, 0, sizeof(memcached_st));
430 }
431
432 char *memcached_strerror(memcached_st *ptr, memcached_return rc)
433 {
434 switch (rc)
435 {
436 case MEMCACHED_SUCCESS:
437 return "SUCCESS";
438 case MEMCACHED_FAILURE:
439 return "FAILURE";
440 case MEMCACHED_HOST_LOCKUP_FAILURE:
441 return "HOSTNAME LOOKUP FAILURE";
442 case MEMCACHED_CONNECTION_FAILURE:
443 return "CONNECTION FAILURE";
444 case MEMCACHED_CONNECTION_BIND_FAILURE:
445 return "CONNECTION BIND FAILURE";
446 case MEMCACHED_READ_FAILURE:
447 return "READ FAILURE";
448 case MEMCACHED_UNKNOWN_READ_FAILURE:
449 return "UNKNOWN READ FAILURE";
450 case MEMCACHED_PROTOCOL_ERROR:
451 return "PROTOCOL ERROR";
452 case MEMCACHED_CLIENT_ERROR:
453 return "CLIENT ERROR";
454 case MEMCACHED_SERVER_ERROR:
455 return "SERVER ERROR";
456 case MEMCACHED_WRITE_FAILURE:
457 return "WRITE FAILURE";
458 case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE:
459 return "CONNECTION SOCKET CREATE FAILURE";
460 case MEMCACHED_DATA_EXISTS:
461 return "CONNECTION DATA EXISTS";
462 case MEMCACHED_DATA_DOES_NOT_EXIST:
463 return "CONNECTION DATA DOES NOT EXIST";
464 case MEMCACHED_NOTSTORED:
465 return "NOT STORED";
466 case MEMCACHED_NOTFOUND:
467 return "NOT FOUND";
468 case MEMCACHED_MEMORY_ALLOCATION_FAILURE:
469 return "MEMORY ALLOCATION FAILURE";
470 case MEMCACHED_PARTIAL_READ:
471 return "PARTIAL READ";
472 };
473 }