Fixed bug where zero length key was provided.
[awesomized/libmemcached] / lib / memcached_storage.c
1 /*
2 Memcached library
3
4 memcached_set()
5 memcached_replace()
6 memcached_add()
7
8 */
9
10 #include "common.h"
11 #include "memcached_io.h"
12
13 typedef enum {
14 SET_OP,
15 REPLACE_OP,
16 ADD_OP,
17 } memcached_storage_action;
18
19 /* Inline this */
20 #define storage_op_string(A) A == SET_OP ? "set" : ( A == REPLACE_OP ? "replace" : "add")
21
22 static memcached_return memcached_send(memcached_st *ptr,
23 char *key, size_t key_length,
24 char *value, size_t value_length,
25 time_t expiration,
26 uint16_t flags,
27 memcached_storage_action verb)
28 {
29 char to_write;
30 size_t write_length;
31 ssize_t sent_length;
32 memcached_return rc;
33 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
34 unsigned int server_key;
35
36 WATCHPOINT_ASSERT(value);
37 WATCHPOINT_ASSERT(value_length);
38
39 if (key_length == 0)
40 return MEMCACHED_NO_KEY_PROVIDED;
41
42 /* Leaving this WATCHPOINT_ASSERT in since only a library fubar could blow this */
43 #ifdef NOT_DONE
44 if (!(ptr->flags & MEM_NO_BLOCK) && ptr->write_buffer_offset != 0)
45 WATCHPOINT_ASSERT(0);
46 #endif
47
48 if (ptr->hosts == NULL || ptr->number_of_hosts == 0)
49 return MEMCACHED_NO_SERVERS;
50
51 server_key= memcached_generate_hash(ptr, key, key_length);
52
53 rc= memcached_connect(ptr, server_key);
54 if (rc != MEMCACHED_SUCCESS)
55 return rc;
56
57
58 write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
59 "%s %.*s %x %llu %zu\r\n", storage_op_string(verb),
60 (int)key_length, key, flags,
61 (unsigned long long)expiration, value_length);
62 if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
63 {
64 rc= MEMCACHED_WRITE_FAILURE;
65 goto error;
66 }
67
68 /*
69 We have to flush after sending the command. Memcached is not smart enough
70 to just keep reading from the socket :(
71 */
72 if ((sent_length= memcached_io_write(ptr, server_key, buffer, write_length, 0)) == -1)
73 {
74 rc= MEMCACHED_WRITE_FAILURE;
75 goto error;
76 }
77
78 if ((sent_length= memcached_io_write(ptr, server_key, value, value_length, 0)) == -1)
79 {
80 rc= MEMCACHED_WRITE_FAILURE;
81 goto error;
82 }
83
84 if ((ptr->flags & MEM_NO_BLOCK) && verb == SET_OP)
85 to_write= 0;
86 else
87 to_write= 1;
88
89 if ((sent_length= memcached_io_write(ptr, server_key, "\r\n", 2, to_write)) == -1)
90 {
91 memcached_quit_server(ptr, server_key);
92 rc= MEMCACHED_WRITE_FAILURE;
93 goto error;
94 }
95
96 if ((ptr->flags & MEM_NO_BLOCK) && verb == SET_OP)
97 {
98 rc= MEMCACHED_SUCCESS;
99 memcached_server_response_increment(ptr, server_key);
100 }
101 else
102 {
103 rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
104 }
105
106 if (rc == MEMCACHED_STORED)
107 return MEMCACHED_SUCCESS;
108 else
109 return rc;
110
111 error:
112 memcached_io_reset(ptr, server_key);
113
114 return rc;
115 }
116
117 memcached_return memcached_set(memcached_st *ptr, char *key, size_t key_length,
118 char *value, size_t value_length,
119 time_t expiration,
120 uint16_t flags)
121 {
122 memcached_return rc;
123 LIBMEMCACHED_MEMCACHED_SET_START();
124 rc= memcached_send(ptr, key, key_length, value, value_length,
125 expiration, flags, SET_OP);
126 LIBMEMCACHED_MEMCACHED_SET_END();
127 return rc;
128 }
129
130 memcached_return memcached_add(memcached_st *ptr, char *key, size_t key_length,
131 char *value, size_t value_length,
132 time_t expiration,
133 uint16_t flags)
134 {
135 memcached_return rc;
136 LIBMEMCACHED_MEMCACHED_ADD_START();
137 rc= memcached_send(ptr, key, key_length, value, value_length,
138 expiration, flags, ADD_OP);
139 LIBMEMCACHED_MEMCACHED_ADD_END();
140 return rc;
141 }
142
143 memcached_return memcached_replace(memcached_st *ptr, char *key, size_t key_length,
144 char *value, size_t value_length,
145 time_t expiration,
146 uint16_t flags)
147 {
148 memcached_return rc;
149 LIBMEMCACHED_MEMCACHED_REPLACE_START();
150 rc= memcached_send(ptr, key, key_length, value, value_length,
151 expiration, flags, REPLACE_OP);
152 LIBMEMCACHED_MEMCACHED_REPLACE_END();
153 return rc;
154 }