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
22unsigned int wsrep_check_ip (const char* const addr, bool *is_ipv6);
23size_t wsrep_guess_ip (char* buf, size_t buf_len);
24
25/* returns the length of the host part of the address string */
26size_t wsrep_host_len(const char* addr, size_t addr_len);
27
28namespace wsp {
29
30class Address {
31public:
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
50private:
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
173class Config_state
174{
175public:
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
232private:
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
240extern wsp::Config_state *wsrep_config_state;
241
242namespace wsp {
243/* a class to manage env vars array */
244class env
245{
246private:
247 size_t len_;
248 char** env_;
249 int errno_;
250 bool ctor_common(char** e);
251 void dtor();
252 env& operator =(env);
253public:
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. */
263class process
264{
265private:
266 const char* const str_;
267 FILE* io_;
268 int err_;
269 pid_t pid_;
270
271public:
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
285class 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
298public:
299
300 thd(my_bool wsrep_on);
301 ~thd();
302 THD* const ptr;
303};
304
305class string
306{
307public:
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); }
313private:
314 char* string_;
315};
316
317#ifdef REMOVED
318class lock
319{
320 pthread_mutex_t* const mtx_;
321
322public:
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
351private:
352
353 lock (const lock&);
354 lock& operator=(const lock&);
355
356};
357
358class monitor
359{
360 int mutable refcnt;
361 pthread_mutex_t mutable mtx;
362 pthread_cond_t mutable cond;
363
364public:
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
400private:
401
402 monitor (const monitor&);
403 monitor& operator= (const monitor&);
404};
405
406class critical
407{
408 const monitor& mon;
409
410public:
411
412 critical(const monitor& m) : mon(m) { mon.enter(); }
413
414 ~critical() { mon.leave(); }
415
416private:
417
418 critical (const critical&);
419 critical& operator= (const critical&);
420};
421#endif
422
423} // namespace wsrep
424
425#endif /* WSREP_UTILS_H */
426