test: poll_timeout; see php-memcached-dev/php-memcached#531
[awesomized/libmemcached] / src / libmemcached / version.cc
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached-awesome - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020-2021 Michael Wallner https://awesome.co/ |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "libmemcached/common.h"
17
18 const char *memcached_lib_version(void) {
19 return LIBMEMCACHED_VERSION_STRING;
20 }
21
22 static inline memcached_return_t memcached_version_textual(Memcached *memc) {
23 libmemcached_io_vector_st vector[] = {
24 {memcached_literal_param("version\r\n")},
25 };
26
27 uint32_t success = 0;
28 bool errors_happened = false;
29 for (uint32_t x = 0; x < memcached_server_count(memc); x++) {
30 memcached_instance_st *instance = memcached_instance_fetch(memc, x);
31
32 // Optimization, we only fetch version once.
33 if (instance->major_version != UINT8_MAX) {
34 continue;
35 }
36
37 memcached_return_t rrc;
38 if (memcached_failed(rrc = memcached_vdo(instance, vector, 1, true))) {
39 errors_happened = true;
40 (void) memcached_set_error(*instance, rrc, MEMCACHED_AT);
41 continue;
42 }
43 success++;
44 }
45
46 if (success) {
47 // Collect the returned items
48 memcached_instance_st *instance;
49 memcached_return_t readable_error;
50 while ((instance = memcached_io_get_readable_server(memc, readable_error))) {
51 memcached_return_t rrc = memcached_response(instance, NULL);
52 if (memcached_failed(rrc)) {
53 errors_happened = true;
54 }
55 }
56 }
57
58 return errors_happened ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
59 }
60
61 static inline memcached_return_t memcached_version_binary(Memcached *memc) {
62 protocol_binary_request_version request = {};
63
64 request.message.header.request.opcode = PROTOCOL_BINARY_CMD_VERSION;
65 request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
66
67 libmemcached_io_vector_st vector[] = {{request.bytes, sizeof(request.bytes)}};
68
69 uint32_t success = 0;
70 bool errors_happened = false;
71 for (uint32_t x = 0; x < memcached_server_count(memc); x++) {
72 memcached_instance_st *instance = memcached_instance_fetch(memc, x);
73
74 initialize_binary_request(instance, request.message.header);
75
76 if (instance->major_version != UINT8_MAX) {
77 continue;
78 }
79
80 memcached_return_t rrc = memcached_vdo(instance, vector, 1, true);
81 if (memcached_failed(rrc)) {
82 errors_happened = true;
83 continue;
84 }
85
86 success++;
87 }
88
89 if (success) {
90 // Collect the returned items
91 memcached_instance_st *instance;
92 memcached_return_t readable_error;
93 while ((instance = memcached_io_get_readable_server(memc, readable_error))) {
94 char buffer[32];
95 memcached_return_t rrc = memcached_response(instance, buffer, sizeof(buffer), NULL);
96 if (memcached_failed(rrc)) {
97 errors_happened = true;
98 }
99 }
100 }
101
102 return errors_happened ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
103 }
104
105 static inline void version_ascii_instance(memcached_instance_st *instance) {
106 if (instance->major_version != UINT8_MAX) {
107 libmemcached_io_vector_st vector[] = {
108 {memcached_literal_param("version\r\n")},
109 };
110
111 (void) memcached_vdo(instance, vector, 1, false);
112 }
113 }
114
115 static inline void version_binary_instance(memcached_instance_st *instance) {
116 if (instance->major_version != UINT8_MAX) {
117 protocol_binary_request_version request = {};
118
119 request.message.header.request.opcode = PROTOCOL_BINARY_CMD_VERSION;
120 request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
121
122 libmemcached_io_vector_st vector[] = {{request.bytes, sizeof(request.bytes)}};
123
124 initialize_binary_request(instance, request.message.header);
125
126 (void) memcached_vdo(instance, vector, 1, false);
127 }
128 }
129
130 void memcached_version_instance(memcached_instance_st *instance) {
131 if (instance) {
132 if (memcached_has_root(instance)) {
133 if (memcached_is_fetching_version(instance->root)) {
134 if (memcached_is_udp(instance->root) == false) {
135 if (memcached_is_binary(instance->root)) {
136 version_binary_instance(instance);
137 return;
138 }
139
140 version_ascii_instance(instance);
141 }
142 }
143 }
144 }
145 }
146
147 int8_t memcached_version_instance_cmp(memcached_instance_st *instance, uint8_t maj, uint8_t min,
148 uint8_t mic) {
149 if (!instance || memcached_server_major_version(instance) == UINT8_MAX) {
150 return INT8_MIN;
151 } else {
152 uint32_t sv, cv;
153
154 sv = memcached_server_micro_version(instance) | memcached_server_minor_version(instance) << 8
155 | memcached_server_major_version(instance) << 16;
156 cv = mic | min << 8 | maj << 16;
157 if (sv < cv) {
158 return -1;
159 }
160 return sv != cv;
161 }
162 }
163
164 memcached_return_t memcached_version(memcached_st *shell) {
165 Memcached *memc = memcached2Memcached(shell);
166 if (memc) {
167 memcached_return_t rc;
168 if (memcached_failed(rc = initialize_query(memc, true))) {
169 return rc;
170 }
171
172 if (memcached_is_udp(memc)) {
173 return MEMCACHED_NOT_SUPPORTED;
174 }
175
176 if (memcached_is_binary(memc)) {
177 return memcached_version_binary(memc);
178 }
179
180 return memcached_version_textual(memc);
181 }
182
183 return MEMCACHED_INVALID_ARGUMENTS;
184 }