1 | /* Copyright (C) 2013-2015 Codership Oy <info@codership.com> |
2 | |
3 | This program is free software; you can redistribute it and/or modify |
4 | it under the terms of the GNU General Public License as published by |
5 | the Free Software Foundation; version 2 of the License. |
6 | |
7 | This program is distributed in the hope that it will be useful, |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | GNU General Public License for more details. |
11 | |
12 | You should have received a copy of the GNU General Public License along |
13 | with this program; if not, write to the Free Software Foundation, Inc., |
14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ |
15 | |
16 | #ifndef WSREP_UTILS_H |
17 | #define WSREP_UTILS_H |
18 | |
19 | #include "wsrep_priv.h" |
20 | #include "wsrep_mysqld.h" |
21 | |
22 | unsigned int wsrep_check_ip (const char* const addr, bool *is_ipv6); |
23 | size_t wsrep_guess_ip (char* buf, size_t buf_len); |
24 | |
25 | /* returns the length of the host part of the address string */ |
26 | size_t wsrep_host_len(const char* addr, size_t addr_len); |
27 | |
28 | namespace wsp { |
29 | |
30 | class Address { |
31 | public: |
32 | Address() |
33 | : m_address_len(0), m_family(UNSPEC), m_port(0), m_valid(false) |
34 | { |
35 | memset(m_address, 0, sizeof(m_address)); |
36 | } |
37 | Address(const char *addr_in) |
38 | : m_address_len(0), m_family(UNSPEC), m_port(0), m_valid(false) |
39 | { |
40 | memset(m_address, 0, sizeof(m_address)); |
41 | parse_addr(addr_in); |
42 | } |
43 | bool is_valid() { return m_valid; } |
44 | bool is_ipv6() { return (m_family == INET6); } |
45 | |
46 | const char* get_address() { return m_address; } |
47 | size_t get_address_len() { return m_address_len; } |
48 | int get_port() { return m_port; } |
49 | |
50 | private: |
51 | enum family { |
52 | UNSPEC= 0, |
53 | INET, /* IPv4 */ |
54 | INET6, /* IPv6 */ |
55 | }; |
56 | |
57 | char m_address[256]; |
58 | size_t m_address_len; |
59 | family m_family; |
60 | int m_port; |
61 | bool m_valid; |
62 | |
63 | void parse_addr(const char *addr_in) { |
64 | const char *start; |
65 | const char *end; |
66 | const char *port; |
67 | const char* open_bracket= strchr(const_cast<char *>(addr_in), '['); |
68 | const char* close_bracket= strchr(const_cast<char *>(addr_in), ']'); |
69 | const char* colon= strchr(const_cast<char *>(addr_in), ':'); |
70 | const char* dot= strchr(const_cast<char *>(addr_in), '.'); |
71 | |
72 | int cc= colon_count(addr_in); |
73 | |
74 | if (open_bracket != NULL || |
75 | dot == NULL || |
76 | (colon != NULL && (dot == NULL || colon < dot))) |
77 | { |
78 | // This could be an IPv6 address or a hostname |
79 | if (open_bracket != NULL) { |
80 | /* Sanity check: Address with '[' must include ']' */ |
81 | if (close_bracket == NULL && |
82 | open_bracket < close_bracket) /* Error: malformed address */ |
83 | { |
84 | m_valid= false; |
85 | return; |
86 | } |
87 | |
88 | start= open_bracket + 1; |
89 | end= close_bracket; |
90 | |
91 | /* Check for port */ |
92 | port= strchr(close_bracket, ':'); |
93 | if ((port != NULL) && parse_port(port + 1)) |
94 | { |
95 | return; /* Error: invalid port */ |
96 | } |
97 | m_family= INET6; |
98 | } |
99 | else |
100 | { |
101 | switch (cc) { |
102 | case 0: |
103 | /* Hostname with no port */ |
104 | start= addr_in; |
105 | end= addr_in + strlen(addr_in); |
106 | break; |
107 | case 1: |
108 | /* Hostname with port (host:port) */ |
109 | start= addr_in; |
110 | end= colon; |
111 | parse_port(colon + 1); |
112 | break; |
113 | default: |
114 | /* IPv6 address */ |
115 | start= addr_in; |
116 | end= addr_in + strlen(addr_in); |
117 | m_family= INET6; |
118 | break; |
119 | } |
120 | } |
121 | } else { /* IPv4 address or hostname */ |
122 | start= addr_in; |
123 | if (colon != NULL) { /* Port */ |
124 | end= colon; |
125 | if (parse_port(colon + 1)) |
126 | return; /* Error: invalid port */ |
127 | } else { |
128 | end= addr_in + strlen(addr_in); |
129 | } |
130 | } |
131 | |
132 | size_t len= end - start; |
133 | |
134 | /* Safety */ |
135 | if (len >= sizeof(m_address)) |
136 | { |
137 | // The supplied address is too large to fit into the internal buffer. |
138 | m_valid= false; |
139 | return; |
140 | } |
141 | |
142 | memcpy(m_address, start, len); |
143 | m_address[len]= '\0'; |
144 | m_address_len= ++ len; |
145 | m_valid= true; |
146 | return; |
147 | } |
148 | |
149 | int colon_count(const char *addr) { |
150 | int count= 0, i= 0; |
151 | |
152 | while(addr[i] != '\0') |
153 | { |
154 | if (addr[i] == ':') ++count; |
155 | ++ i; |
156 | } |
157 | return count; |
158 | } |
159 | |
160 | bool parse_port(const char *port) { |
161 | errno= 0; /* Reset the errno */ |
162 | m_port= strtol(port, NULL, 10); |
163 | if (errno == EINVAL || errno == ERANGE) |
164 | { |
165 | m_port= 0; /* Error: invalid port */ |
166 | m_valid= false; |
167 | return true; |
168 | } |
169 | return false; |
170 | } |
171 | }; |
172 | |
173 | class Config_state |
174 | { |
175 | public: |
176 | Config_state() : view_(), status_(WSREP_MEMBER_UNDEFINED) |
177 | {} |
178 | |
179 | void set(wsrep_member_status_t status, const wsrep_view_info_t* view) |
180 | { |
181 | wsrep_notify_status(status, view); |
182 | |
183 | lock(); |
184 | |
185 | status_= status; |
186 | view_= *view; |
187 | member_info_.clear(); |
188 | |
189 | wsrep_member_info_t memb; |
190 | for(int i= 0; i < view->memb_num; i ++) |
191 | { |
192 | memb= view->members[i]; |
193 | member_info_.append_val(memb); |
194 | } |
195 | |
196 | unlock(); |
197 | } |
198 | |
199 | void set(wsrep_member_status_t status) |
200 | { |
201 | wsrep_notify_status(status, 0); |
202 | lock(); |
203 | status_= status; |
204 | unlock(); |
205 | } |
206 | |
207 | wsrep_view_info_t get_view_info() const |
208 | { |
209 | return view_; |
210 | } |
211 | |
212 | wsrep_member_status_t get_status() const |
213 | { |
214 | return status_; |
215 | } |
216 | |
217 | Dynamic_array<wsrep_member_info_t> * get_member_info() |
218 | { |
219 | return &member_info_; |
220 | } |
221 | |
222 | int lock() |
223 | { |
224 | return mysql_mutex_lock(&LOCK_wsrep_config_state); |
225 | } |
226 | |
227 | int unlock() |
228 | { |
229 | return mysql_mutex_unlock(&LOCK_wsrep_config_state); |
230 | } |
231 | |
232 | private: |
233 | wsrep_view_info_t view_; |
234 | wsrep_member_status_t status_; |
235 | Dynamic_array<wsrep_member_info_t> member_info_; |
236 | }; |
237 | |
238 | } /* namespace wsp */ |
239 | |
240 | extern wsp::Config_state *wsrep_config_state; |
241 | |
242 | namespace wsp { |
243 | /* a class to manage env vars array */ |
244 | class env |
245 | { |
246 | private: |
247 | size_t len_; |
248 | char** env_; |
249 | int errno_; |
250 | bool ctor_common(char** e); |
251 | void dtor(); |
252 | env& operator =(env); |
253 | public: |
254 | explicit env(char** env); |
255 | explicit env(const env&); |
256 | ~env(); |
257 | int append(const char* var); /* add a new env. var */ |
258 | int error() const { return errno_; } |
259 | char** operator()() { return env_; } |
260 | }; |
261 | |
262 | /* A small class to run external programs. */ |
263 | class process |
264 | { |
265 | private: |
266 | const char* const str_; |
267 | FILE* io_; |
268 | int err_; |
269 | pid_t pid_; |
270 | |
271 | public: |
272 | /*! @arg type is a pointer to a null-terminated string which must contain |
273 | either the letter 'r' for reading or the letter 'w' for writing. |
274 | @arg env optional null-terminated vector of environment variables |
275 | */ |
276 | process (const char* cmd, const char* type, char** env); |
277 | ~process (); |
278 | |
279 | FILE* pipe () { return io_; } |
280 | int error() { return err_; } |
281 | int wait (); |
282 | const char* cmd() { return str_; } |
283 | }; |
284 | |
285 | class thd |
286 | { |
287 | class thd_init |
288 | { |
289 | public: |
290 | thd_init() { my_thread_init(); } |
291 | ~thd_init() { my_thread_end(); } |
292 | } |
293 | init; |
294 | |
295 | thd (const thd&); |
296 | thd& operator= (const thd&); |
297 | |
298 | public: |
299 | |
300 | thd(my_bool wsrep_on); |
301 | ~thd(); |
302 | THD* const ptr; |
303 | }; |
304 | |
305 | class string |
306 | { |
307 | public: |
308 | string() : string_(0) {} |
309 | explicit string(size_t s) : string_(static_cast<char*>(malloc(s))) {} |
310 | char* operator()() { return string_; } |
311 | void set(char* str) { if (string_) free (string_); string_ = str; } |
312 | ~string() { set (0); } |
313 | private: |
314 | char* string_; |
315 | }; |
316 | |
317 | #ifdef REMOVED |
318 | class lock |
319 | { |
320 | pthread_mutex_t* const mtx_; |
321 | |
322 | public: |
323 | |
324 | lock (pthread_mutex_t* mtx) : mtx_(mtx) |
325 | { |
326 | int err = pthread_mutex_lock (mtx_); |
327 | |
328 | if (err) |
329 | { |
330 | WSREP_ERROR("Mutex lock failed: %s" , strerror(err)); |
331 | abort(); |
332 | } |
333 | } |
334 | |
335 | virtual ~lock () |
336 | { |
337 | int err = pthread_mutex_unlock (mtx_); |
338 | |
339 | if (err) |
340 | { |
341 | WSREP_ERROR("Mutex unlock failed: %s" , strerror(err)); |
342 | abort(); |
343 | } |
344 | } |
345 | |
346 | inline void wait (pthread_cond_t* cond) |
347 | { |
348 | pthread_cond_wait (cond, mtx_); |
349 | } |
350 | |
351 | private: |
352 | |
353 | lock (const lock&); |
354 | lock& operator=(const lock&); |
355 | |
356 | }; |
357 | |
358 | class monitor |
359 | { |
360 | int mutable refcnt; |
361 | pthread_mutex_t mutable mtx; |
362 | pthread_cond_t mutable cond; |
363 | |
364 | public: |
365 | |
366 | monitor() : refcnt(0) |
367 | { |
368 | pthread_mutex_init (&mtx, NULL); |
369 | pthread_cond_init (&cond, NULL); |
370 | } |
371 | |
372 | ~monitor() |
373 | { |
374 | pthread_mutex_destroy (&mtx); |
375 | pthread_cond_destroy (&cond); |
376 | } |
377 | |
378 | void enter() const |
379 | { |
380 | lock l(&mtx); |
381 | |
382 | while (refcnt) |
383 | { |
384 | l.wait(&cond); |
385 | } |
386 | refcnt++; |
387 | } |
388 | |
389 | void leave() const |
390 | { |
391 | lock l(&mtx); |
392 | |
393 | refcnt--; |
394 | if (refcnt == 0) |
395 | { |
396 | pthread_cond_signal (&cond); |
397 | } |
398 | } |
399 | |
400 | private: |
401 | |
402 | monitor (const monitor&); |
403 | monitor& operator= (const monitor&); |
404 | }; |
405 | |
406 | class critical |
407 | { |
408 | const monitor& mon; |
409 | |
410 | public: |
411 | |
412 | critical(const monitor& m) : mon(m) { mon.enter(); } |
413 | |
414 | ~critical() { mon.leave(); } |
415 | |
416 | private: |
417 | |
418 | critical (const critical&); |
419 | critical& operator= (const critical&); |
420 | }; |
421 | #endif |
422 | |
423 | } // namespace wsrep |
424 | |
425 | #endif /* WSREP_UTILS_H */ |
426 | |