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