Updating for 1.0.2 release
[awesomized/libmemcached] / libmemcached / version.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Libmemcached library
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * Copyright (C) 2010 Brian Aker All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37 #include <libmemcached/common.h>
38
39 const char * memcached_lib_version(void)
40 {
41 return LIBMEMCACHED_VERSION_STRING;
42 }
43
44 static inline memcached_return_t memcached_version_binary(memcached_st *ptr);
45 static inline memcached_return_t memcached_version_textual(memcached_st *ptr);
46
47 memcached_return_t memcached_version(memcached_st *ptr)
48 {
49 memcached_return_t rc;
50 if (memcached_failed(rc= initialize_query(ptr)))
51 {
52 return rc;
53 }
54
55 if (ptr->flags.use_udp)
56 {
57 return MEMCACHED_NOT_SUPPORTED;
58 }
59
60 if (ptr->flags.binary_protocol)
61 {
62 rc= memcached_version_binary(ptr);
63 }
64 else
65 {
66 rc= memcached_version_textual(ptr);
67 }
68
69 return rc;
70 }
71
72 static inline memcached_return_t memcached_version_textual(memcached_st *ptr)
73 {
74 memcached_return_t rc= MEMCACHED_SUCCESS;
75 for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
76 {
77 memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x);
78
79 // Optimization, we only fetch version once.
80 if (instance->major_version != UINT8_MAX)
81 {
82 continue;
83 }
84
85 memcached_return_t rrc= memcached_do(instance, memcached_literal_param("version\r\n"), true);
86 if (memcached_failed(rrc))
87 {
88 (void)memcached_set_error(*instance, rrc, MEMCACHED_AT);
89 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
90 rc= MEMCACHED_SOME_ERRORS;
91 continue;
92 }
93
94 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
95 rrc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
96 if (memcached_failed(rrc))
97 {
98 memcached_set_error(*instance, rrc, MEMCACHED_AT);
99 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
100 rc= MEMCACHED_SOME_ERRORS;
101 continue;
102 }
103
104 /* Find the space, and then move one past it to copy version */
105 char *response_ptr= index(buffer, ' ');
106 response_ptr++;
107
108 long int version= strtol(response_ptr, (char **)NULL, 10);
109 if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX or version == 0)
110 {
111 memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse major version"));
112 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
113 rc= MEMCACHED_SOME_ERRORS;
114 continue;
115 }
116 instance->major_version= uint8_t(version);
117
118 response_ptr= index(response_ptr, '.');
119 response_ptr++;
120
121 version= strtol(response_ptr, (char **)NULL, 10);
122 if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX)
123 {
124 memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse minor version"));
125 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
126 rc= MEMCACHED_SOME_ERRORS;
127 continue;
128 }
129 instance->minor_version= uint8_t(version);
130
131 response_ptr= index(response_ptr, '.');
132 response_ptr++;
133
134 version= strtol(response_ptr, (char **)NULL, 10);
135 if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX)
136 {
137 memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version"));
138 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
139 rc= MEMCACHED_SOME_ERRORS;
140 continue;
141 }
142 instance->micro_version= uint8_t(version);
143 }
144
145 return rc;
146 }
147
148 static inline memcached_return_t memcached_version_binary(memcached_st *ptr)
149 {
150 protocol_binary_request_version request= {};
151 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
152 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION;
153 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
154
155 memcached_return_t rc= MEMCACHED_SUCCESS;
156 for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
157 {
158 memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x);
159
160 if (instance->major_version != UINT8_MAX)
161 {
162 continue;
163 }
164
165 memcached_return_t rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true);
166 if (memcached_failed(rrc))
167 {
168 memcached_io_reset(instance);
169 rc= MEMCACHED_SOME_ERRORS;
170 continue;
171 }
172 }
173
174 for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
175 {
176 memcached_server_write_instance_st instance=
177 memcached_server_instance_fetch(ptr, x);
178
179 if (instance->major_version != UINT8_MAX)
180 {
181 continue;
182 }
183
184 if (memcached_server_response_count(instance) > 0)
185 {
186 char buffer[32];
187 char *p;
188
189 memcached_return_t rrc= memcached_response(instance, buffer, sizeof(buffer), NULL);
190 if (memcached_failed(rrc))
191 {
192 memcached_io_reset(instance);
193 rc= MEMCACHED_SOME_ERRORS;
194 continue;
195 }
196
197 long int version= strtol(buffer, &p, 10);
198 if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX or version == 0)
199 {
200 memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse major version"));
201 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
202 rc= MEMCACHED_SOME_ERRORS;
203 continue;
204 }
205 instance->major_version= uint8_t(version);
206
207 version= strtol(p +1, &p, 10);
208 if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX)
209 {
210 memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version"));
211 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
212 rc= MEMCACHED_SOME_ERRORS;
213 continue;
214 }
215 instance->minor_version= uint8_t(version);
216
217 version= strtol(p + 1, NULL, 10);
218 if (errno == ERANGE)
219 {
220 memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version"));
221 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
222 rc= MEMCACHED_SOME_ERRORS;
223 continue;
224 }
225 instance->micro_version= uint8_t(version);
226 }
227 }
228
229 return rc;
230 }