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