-
Notifications
You must be signed in to change notification settings - Fork 1k
/
Copy pathproxysql_utils.h
254 lines (225 loc) · 8.86 KB
/
proxysql_utils.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#ifndef __PROXYSQL_UTILS_H
#define __PROXYSQL_UTILS_H
#include <cstdarg>
#include <functional>
#include <type_traits>
#include <memory>
#include <string>
#include <vector>
#include <sys/time.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/resource.h>
#include "sqlite3db.h"
#ifndef ProxySQL_Checksum_Value_LENGTH
#define ProxySQL_Checksum_Value_LENGTH 20
#endif
#ifndef ETIME
// ETIME is not defined on FreeBSD
// ETIME is used internaly to report API timer expired
// replace with ETIMEDOUT as closest alternative
#define ETIME ETIMEDOUT
#endif
template<class...> struct conjunction : std::true_type { };
template<class B1> struct conjunction<B1> : B1 { };
template<class B1, class... Bn>
struct conjunction<B1, Bn...>
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
/**
* @brief Stores the result of formatting the first parameter with the provided
* arguments, into the std::string reference provided in the second parameter.
*
* @param str The string to be formatted.
* @param result A std::string reference in which store the formatted result.
* @param args The additional arguments to be formatted into the string.
* @return int In case of success 0 is returned, otherwise, the formatting error provided
* by 'snprintf' is provided.
*/
template<
typename... Args,
#ifdef CXX17
typename std::enable_if<std::conjunction<std::is_trivial<Args>...>::value,int>::type = 0
#else
typename std::enable_if<conjunction<std::is_trivial<Args>...>::value,int>::type = 0
#endif // CXX17
>
int string_format(const std::string& str, std::string& result, Args... args) {
int size = snprintf(nullptr, 0, str.c_str(), args...);
if (size <= 0) {
return size;
} else {
size += 1;
std::unique_ptr<char[]> buf(new char[size]);
size = snprintf(buf.get(), size, str.c_str(), args...);
result = std::string(buf.get(), buf.get() + size);
}
return size;
}
/**
* @brief Output struct of 'cstr_format' functions family.
*/
struct cfmt_t {
// @brief If negative, the error returned from 'snprintf' while formatting. Otherwise the number of bytes
// copied into the resulting formatted string.
int size;
// @brief In case of success the resulting formatted string, empty otherwise.
std::string str;
};
/**
* @brief Formats the provided string literal with the extra variadic arguments.
* @details This is an improved version on 'string_format' function. When used against an string literal,
* allows the compiler to issue the proper warnings in case the format parameters are ill-formed.
* @param fmt The string literal to be formatted with variadic arguments.
* @param ... The variadic arguments to use for formatting.
* @return An 'cfmt_t' holding the number of bytes copied to the resulting string and the formatted string
* itself. In case of error the 'size' field will hold 'snprintf' returned error and 'str' will be empty.
*/
__attribute__((__format__ (__printf__, 1, 2)))
cfmt_t cstr_format(const char* fmt, ...);
/**
* @brief Formats the provided string literal with the extra variadic arguments, and place the formatted
* string either in the returned 'cfmt_t::string' or in the supplied buffer.
* @details This is an improved version on 'string_format' function. When used against an string literal,
* allows the compiler to issue the proper warnings in case the format parameters are ill-formed.
* @param out_buf The output buffer in which to place the resulting formatted string in case it fits.
* @param fmt The string literal to be formatted with variadic arguments.
* @param ... The variadic arguments to use for formatting.
* @return On success, an 'cfmt_t' holding the number of bytes copied to the resulting string, in case this
* result fits in the provided buffer, this buffer is directly written and the returned 'cfmt_t::str' will
* be empty. In case of error the 'size' field will hold 'snprintf' returned error and 'str' will be empty.
*/
template <int N> __attribute__((__format__ (__printf__, 2, 3)))
cfmt_t cstr_format(char (&out_buf)[N], const char* fmt, ...) {
va_list args;
va_start(args, fmt);
int size = vsnprintf(nullptr, 0, fmt, args);
va_end(args);
if (size <= 0) {
return { size, {} };
} else {
size += 1;
if (size <= N) {
va_start(args, fmt);
size = vsnprintf(out_buf, size, fmt, args);
va_end(args);
return { size, {} };
} else {
std::unique_ptr<char[]> buf(new char[size]);
va_start(args, fmt);
size = vsnprintf(buf.get(), size, fmt, args);
va_end(args);
if (size <= 0) {
return { size, {} };
} else {
return { size, std::string(buf.get(), buf.get() + size) };
}
}
}
}
/**
* @brief Simple struct that holds the 'timeout options' for 'wexecvp'.
*/
struct to_opts_t {
/**
* @brief Timeout for the script execution to be completed, in case of being
* exceeded, the script will be terminated.
*/
unsigned int timeout_us;
/**
* @brief Timeout used for 'poll()' non blocking calls.
*/
suseconds_t poll_to_us;
/**
* @brief The duration of the sleeps between the checks being performed
* on the child process waiting it to exit after being signaled to terminate,
* before issuing 'SIGKILL'.
*/
unsigned int waitpid_delay_us;
/**
* @brief The timeout to be waited on the child process after being signaled
* with 'SIGTERM' before being forcely terminated by 'SIGKILL'.
*/
unsigned int sigkill_to_us;
};
/**
* @brief Helper function to launch an executable in a child process through 'fork()' and
* 'execvp()' and retrieve their 'stderr' and 'stdout' to the caller toguether with
* the result of it's execution.
*
* @param file The file to be executed.
* @param argv The arguments to be supplied to the file being executed.
* @param opts Struct holding timeout options to consider for the launched process.
* @param s_stdout Output string to hold the output 'stdout' of the child process.
* @param s_stderr Output string to hold the output 'stderr' of the child process.
*
* @return 0 In case of success or one of the following error codes:
* - '-1' in case any 'pipe()' creation failed.
* - '-2' in case 'fork()' call failed.
* - '-3' in case 'fcntl()' call failed.
* - '-4' in case 'poll()' call failed.
* - '-5' in case 'read()' from pipes failed with a non-expected error.
* - 'ETIME' in case the executable has exceeded the timeout supplied in 'opts.timeout_us'.
* In all this cases 'errno' is set to the error reported by the failing 'system call'.
*/
int wexecvp(
const std::string& file,
const std::vector<const char*>& argv,
const to_opts_t& opts,
std::string& s_stdout,
std::string& s_stderr
);
/**
* @brief Returns the current timestamp in microseconds.
* @return The current timestamp in microseconds.
*/
uint64_t get_timestamp_us();
/**
* @brief Helper function to replace all the occurrences in a string of a matching substring in favor
* of another string.
*
* @param str The string which copy is going to be searched for matches to be replaced.
* @param match The substring to be matched inside the string.
* @param repl The string for which matches are going to be replaced.
*
* @return A string in which all the matches of 'match' within 'str' has been replaced by 'repl'.
*/
std::string replace_str(const std::string& str, const std::string& match, const std::string& repl);
/**
* @brief Split a string into a vector of strings with the provided 'char' delimiter.
* @param s String to be split.
* @param delimiter Delimiter to be used.
* @return Vector with the string splits. Empty if none is found.
*/
std::vector<std::string> split_str(const std::string& s, char delimiter);
std::string generate_multi_rows_query(int rows, int params);
/**
* @brief Generates a random string of the length of the provider 'strSize' parameter.
* @param strSize The size of the string to be generated.
* @return A random string.
*/
std::string rand_str(std::size_t strSize);
/**
* @brief Helper function used to replace spaces and zeros by '0' char in the supplied checksum buffer.
* @param checksum Input buffer containing the checksum.
*/
inline void replace_checksum_zeros(char* checksum) {
for (int i=2; i<18; i++) {
if (checksum[i]==' ' || checksum[i]==0) {
checksum[i]='0';
}
}
}
/**
* @brief Generates a ProxySQL checksum as a string from the supplied integer hash.
* @param hash The integer hash to be formated as a string.
* @return String representation of the supplied hash.
*/
std::string get_checksum_from_hash(uint64_t hash);
void close_all_non_term_fd(std::vector<int> excludeFDs);
/**
* @brief Returns the expected error for query 'SELECT $$'.
* @param version The 'server_version' for which the error should match.
* @return A pair of the shape '{err_code,err_msg}'.
*/
std::pair<int,const char*> get_dollar_quote_error(const char* version);
#endif