Merge up for version.
[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 if (ptr->flags.use_udp)
50 return MEMCACHED_NOT_SUPPORTED;
51
52 memcached_return_t rc;
53
54 if (ptr->flags.binary_protocol)
55 rc= memcached_version_binary(ptr);
56 else
57 rc= memcached_version_textual(ptr);
58
59 return rc;
60 }
61
62 static inline memcached_return_t memcached_version_textual(memcached_st *ptr)
63 {
64 size_t send_length;
65 memcached_return_t rc;
66 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
67 char *response_ptr;
68 const char *command= "version\r\n";
69
70 send_length= sizeof("version\r\n") -1;
71
72 rc= MEMCACHED_SUCCESS;
73 for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
74 {
75 memcached_return_t rrc;
76 memcached_server_write_instance_st instance=
77 memcached_server_instance_fetch(ptr, x);
78
79 // Optimization, we only fetch version once.
80 if (instance->major_version != UINT8_MAX)
81 continue;
82
83 rrc= memcached_do(instance, command, send_length, true);
84 if (rrc != MEMCACHED_SUCCESS)
85 {
86 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
87 rc= MEMCACHED_SOME_ERRORS;
88 continue;
89 }
90
91 rrc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
92 if (rrc != MEMCACHED_SUCCESS)
93 {
94 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
95 rc= MEMCACHED_SOME_ERRORS;
96 continue;
97 }
98
99 /* Find the space, and then move one past it to copy version */
100 response_ptr= index(buffer, ' ');
101 response_ptr++;
102
103 instance->major_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
104 if (errno == ERANGE)
105 {
106 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
107 rc= MEMCACHED_SOME_ERRORS;
108 continue;
109 }
110
111 response_ptr= index(response_ptr, '.');
112 response_ptr++;
113
114 instance->minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
115 if (errno == ERANGE)
116 {
117 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
118 rc= MEMCACHED_SOME_ERRORS;
119 continue;
120 }
121
122 response_ptr= index(response_ptr, '.');
123 response_ptr++;
124 instance->micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
125 if (errno == ERANGE)
126 {
127 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
128 rc= MEMCACHED_SOME_ERRORS;
129 continue;
130 }
131 }
132
133 return rc;
134 }
135
136 static inline memcached_return_t memcached_version_binary(memcached_st *ptr)
137 {
138 memcached_return_t rc;
139 protocol_binary_request_version request= {};
140 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
141 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION;
142 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
143
144 rc= MEMCACHED_SUCCESS;
145 for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
146 {
147 memcached_return_t rrc;
148
149 memcached_server_write_instance_st instance=
150 memcached_server_instance_fetch(ptr, x);
151
152 if (instance->major_version != UINT8_MAX)
153 continue;
154
155 rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true);
156 if (rrc != MEMCACHED_SUCCESS)
157 {
158 memcached_io_reset(instance);
159 rc= MEMCACHED_SOME_ERRORS;
160 continue;
161 }
162 }
163
164 for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
165 {
166 memcached_server_write_instance_st instance=
167 memcached_server_instance_fetch(ptr, x);
168
169 if (instance->major_version != UINT8_MAX)
170 continue;
171
172 if (memcached_server_response_count(instance) > 0)
173 {
174 memcached_return_t rrc;
175 char buffer[32];
176 char *p;
177
178 rrc= memcached_response(instance, buffer, sizeof(buffer), NULL);
179 if (rrc != MEMCACHED_SUCCESS)
180 {
181 memcached_io_reset(instance);
182 rc= MEMCACHED_SOME_ERRORS;
183 continue;
184 }
185
186 instance->major_version= (uint8_t)strtol(buffer, &p, 10);
187 if (errno == ERANGE)
188 {
189 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
190 rc= MEMCACHED_SOME_ERRORS;
191 continue;
192 }
193
194 instance->minor_version= (uint8_t)strtol(p + 1, &p, 10);
195 if (errno == ERANGE)
196 {
197 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
198 rc= MEMCACHED_SOME_ERRORS;
199 continue;
200 }
201
202 instance->micro_version= (uint8_t)strtol(p + 1, NULL, 10);
203 if (errno == ERANGE)
204 {
205 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
206 rc= MEMCACHED_SOME_ERRORS;
207 continue;
208 }
209
210 }
211 }
212
213 return rc;
214 }