Version will now have a default we can use to look for invalid versions.
[m6w6/libmemcached] / libmemcached / version.c
1 #include "common.h"
2
3 const char * memcached_lib_version(void)
4 {
5 return LIBMEMCACHED_VERSION_STRING;
6 }
7
8 static inline memcached_return_t memcached_version_binary(memcached_st *ptr);
9 static inline memcached_return_t memcached_version_textual(memcached_st *ptr);
10
11 memcached_return_t memcached_version(memcached_st *ptr)
12 {
13 if (ptr->flags.use_udp)
14 return MEMCACHED_NOT_SUPPORTED;
15
16 bool was_blocking= ptr->flags.no_block;
17 memcached_return_t rc;
18
19 ptr->flags.no_block= false;
20
21 if (ptr->flags.binary_protocol)
22 rc= memcached_version_binary(ptr);
23 else
24 rc= memcached_version_textual(ptr);
25
26 ptr->flags.no_block= was_blocking;
27
28 return rc;
29 }
30
31 static inline memcached_return_t memcached_version_textual(memcached_st *ptr)
32 {
33 size_t send_length;
34 memcached_return_t rc;
35 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
36 char *response_ptr;
37 const char *command= "version\r\n";
38
39 send_length= strlen(command);
40
41 rc= MEMCACHED_SUCCESS;
42 for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
43 {
44 memcached_return_t rrc;
45 memcached_server_write_instance_st instance=
46 memcached_server_instance_fetch(ptr, x);
47
48 // Optimization, we only fetch version once.
49 if (instance->major_version != UINT8_MAX)
50 continue;
51
52 rrc= memcached_do(instance, command, send_length, true);
53 if (rrc != MEMCACHED_SUCCESS)
54 {
55 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
56 rc= MEMCACHED_SOME_ERRORS;
57 continue;
58 }
59
60 rrc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
61 if (rrc != MEMCACHED_SUCCESS)
62 {
63 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
64 rc= MEMCACHED_SOME_ERRORS;
65 continue;
66 }
67
68 /* Find the space, and then move one past it to copy version */
69 response_ptr= index(buffer, ' ');
70 response_ptr++;
71
72 instance->major_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
73 if (errno == ERANGE)
74 {
75 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
76 rc= MEMCACHED_SOME_ERRORS;
77 continue;
78 }
79
80 response_ptr= index(response_ptr, '.');
81 response_ptr++;
82
83 instance->minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
84 if (errno == ERANGE)
85 {
86 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
87 rc= MEMCACHED_SOME_ERRORS;
88 continue;
89 }
90
91 response_ptr= index(response_ptr, '.');
92 response_ptr++;
93 instance->micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
94 if (errno == ERANGE)
95 {
96 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
97 rc= MEMCACHED_SOME_ERRORS;
98 continue;
99 }
100 }
101
102 return rc;
103 }
104
105 static inline memcached_return_t memcached_version_binary(memcached_st *ptr)
106 {
107 memcached_return_t rc;
108 protocol_binary_request_version request= { .bytes= {0}};
109 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
110 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION;
111 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
112
113 rc= MEMCACHED_SUCCESS;
114 for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
115 {
116 memcached_return_t rrc;
117
118 memcached_server_write_instance_st instance=
119 memcached_server_instance_fetch(ptr, x);
120
121 if (instance->major_version != UINT8_MAX)
122 continue;
123
124 rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true);
125 if (rrc != MEMCACHED_SUCCESS)
126 {
127 memcached_io_reset(instance);
128 rc= MEMCACHED_SOME_ERRORS;
129 continue;
130 }
131 }
132
133 for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
134 {
135 memcached_server_write_instance_st instance=
136 memcached_server_instance_fetch(ptr, x);
137
138 if (instance->major_version != UINT8_MAX)
139 continue;
140
141 if (memcached_server_response_count(instance) > 0)
142 {
143 memcached_return_t rrc;
144 char buffer[32];
145 char *p;
146
147 rrc= memcached_response(instance, buffer, sizeof(buffer), NULL);
148 if (rrc != MEMCACHED_SUCCESS)
149 {
150 memcached_io_reset(instance);
151 rc= MEMCACHED_SOME_ERRORS;
152 continue;
153 }
154
155 instance->major_version= (uint8_t)strtol(buffer, &p, 10);
156 if (errno == ERANGE)
157 {
158 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
159 rc= MEMCACHED_SOME_ERRORS;
160 continue;
161 }
162
163 instance->minor_version= (uint8_t)strtol(p + 1, &p, 10);
164 if (errno == ERANGE)
165 {
166 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
167 rc= MEMCACHED_SOME_ERRORS;
168 continue;
169 }
170
171 instance->micro_version= (uint8_t)strtol(p + 1, NULL, 10);
172 if (errno == ERANGE)
173 {
174 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
175 rc= MEMCACHED_SOME_ERRORS;
176 continue;
177 }
178
179 }
180 }
181
182 return rc;
183 }