Merge lp:~tangent-org/libmemcached/1.0-build Build: jenkins-Libmemcached-1.0-95
[awesomized/libmemcached] / libtest / server.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Data Differential YATL (i.e. libtest) library
4 *
5 * Copyright (C) 2012 Data Differential, http://datadifferential.com/
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * * The names of its contributors may not be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 */
36
37 #include "mem_config.h"
38 #include <libtest/common.h>
39
40 #include <cassert>
41 #include <cerrno>
42 #include <climits>
43 #include <cstdlib>
44 #include <iostream>
45
46 #include <algorithm>
47 #include <functional>
48 #include <locale>
49 #include <unistd.h>
50
51 // trim from end
52 static inline std::string &rtrim(std::string &s)
53 {
54 s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
55 return s;
56 }
57
58 #include <libtest/server.h>
59 #include <libtest/stream.h>
60 #include <libtest/killpid.h>
61
62 namespace libtest {
63
64 std::ostream& operator<<(std::ostream& output, const Server &arg)
65 {
66 if (arg.is_socket())
67 {
68 output << arg.hostname();
69 }
70 else
71 {
72 output << arg.hostname() << ":" << arg.port();
73 }
74
75 if (arg.has_pid())
76 {
77 output << " Pid:" << arg.pid();
78 }
79
80 if (arg.has_socket())
81 {
82 output << " Socket:" << arg.socket();
83 }
84
85 if (arg.running().empty() == false)
86 {
87 output << " Exec:" << arg.running();
88 }
89
90 return output; // for multiple << operators
91 }
92
93 #ifdef __GLIBC__
94 namespace {
95
96 class Buffer
97 {
98 public:
99 Buffer(char *b) : b_(b) {}
100 ~Buffer() { free(b_); }
101 char* buf() { return b_; }
102 private:
103 char *b_;
104 };
105
106 }
107 #endif // __GLIBC__
108
109 #define MAGIC_MEMORY 123570
110
111 Server::Server(const std::string& host_arg, const in_port_t port_arg,
112 const std::string& executable, const bool _is_libtool,
113 bool is_socket_arg) :
114 _magic(MAGIC_MEMORY),
115 _is_socket(is_socket_arg),
116 _port(port_arg),
117 _hostname(host_arg),
118 _app(executable, _is_libtool),
119 out_of_ban_killed_(false)
120 {
121 }
122
123 Server::~Server()
124 {
125 kill();
126 }
127
128 bool Server::check()
129 {
130 _app.slurp();
131 _app.check();
132 return true;
133 }
134
135 bool Server::validate()
136 {
137 return _magic == MAGIC_MEMORY;
138 }
139
140 // If the server exists, kill it
141 bool Server::cycle()
142 {
143 uint32_t limit= 3;
144
145 // Try to ping, and kill the server #limit number of times
146 while (--limit and
147 is_pid_valid(_app.pid()))
148 {
149 if (kill())
150 {
151 Log << "Killed existing server," << *this;
152 dream(0, 50000);
153 continue;
154 }
155 }
156
157 // For whatever reason we could not kill it, and we reached limit
158 if (limit == 0)
159 {
160 Error << "Reached limit, could not kill server";
161 return false;
162 }
163
164 return true;
165 }
166
167 bool Server::wait_for_pidfile() const
168 {
169 Wait wait(pid_file(), 4);
170
171 return wait.successful();
172 }
173
174 bool Server::has_pid() const
175 {
176 return (_app.pid() > 1);
177 }
178
179
180 bool Server::start()
181 {
182 // If we find that we already have a pid then kill it.
183 if (has_pid() == true)
184 {
185 #if 0
186 fatal_message("has_pid() failed, programer error");
187 #endif
188 }
189
190 // This needs more work.
191 #if 0
192 if (gdb_is_caller())
193 {
194 _app.use_gdb();
195 }
196 #endif
197
198 if (port() == LIBTEST_FAIL_PORT)
199 {
200 throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
201 hostname(), port(), "Called failure");
202 }
203
204 if (getenv("YATL_PTRCHECK_SERVER"))
205 {
206 _app.use_ptrcheck();
207 }
208 else if (getenv("YATL_VALGRIND_SERVER"))
209 {
210 _app.use_valgrind();
211 }
212
213 out_of_ban_killed(false);
214 if (args(_app) == false)
215 {
216 throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
217 hostname(), port(), "Could not build command()");
218 }
219
220 libtest::release_port(_port);
221
222 Application::error_t ret;
223 if (Application::SUCCESS != (ret= _app.run()))
224 {
225 throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
226 hostname(), port(), "Application::run() %s", libtest::Application::toString(ret));
227 return false;
228 }
229 _running= _app.print();
230
231 if (valgrind_is_caller())
232 {
233 dream(5, 50000);
234 }
235
236 size_t repeat= 5;
237 _app.slurp();
238 while (--repeat)
239 {
240 if (pid_file().empty() == false)
241 {
242 Wait wait(pid_file(), 8);
243
244 if (wait.successful() == false)
245 {
246 if (_app.check())
247 {
248 _app.slurp();
249 continue;
250 }
251
252 #ifdef __GLIBC__
253 Buffer buf( get_current_dir_name());
254 char *getcwd_buf= buf.buf();
255 #else
256 char buf[PATH_MAX];
257 char *getcwd_buf= getcwd(buf, sizeof(buf));
258 #endif // __GLIBC__
259 throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
260 hostname(), port(),
261 "Unable to open pidfile in %s for: %s stderr:%s",
262 getcwd_buf ? getcwd_buf : "",
263 _running.c_str(),
264 _app.stderr_c_str());
265 }
266 }
267 }
268
269 bool pinged= false;
270 uint32_t this_wait= 0;
271 {
272 uint32_t timeout= 40; // This number should be high enough for valgrind startup (which is slow)
273 uint32_t waited;
274 uint32_t retry;
275
276 for (waited= 0, retry= 7; ; retry++, waited+= this_wait)
277 {
278 if (_app.check() == false)
279 {
280 break;
281 }
282
283 if ((pinged= ping()) == true)
284 {
285 break;
286 }
287 else if (waited >= timeout)
288 {
289 break;
290 }
291
292 Error << "ping(" << _app.pid() << ") wait: " << this_wait << " " << hostname() << ":" << port() << " " << error();
293
294 this_wait= retry * retry / 3 + 1;
295 libtest::dream(this_wait, 0);
296 }
297 }
298
299 if (pinged == false)
300 {
301 // If we happen to have a pid file, lets try to kill it
302 if ((pid_file().empty() == false) and (access(pid_file().c_str(), R_OK) == 0))
303 {
304 _app.slurp();
305 if (kill_file(pid_file()) == false)
306 {
307 throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
308 hostname(), port(),
309 "Failed to kill off server, waited: %u after startup occurred, when pinging failed: %.*s stderr:%.*s",
310 this_wait,
311 int(_running.size()), _running.c_str(),
312 int(_app.stderr_result_length()), _app.stderr_c_str());
313 }
314 else
315 {
316 throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
317 hostname(), port(),
318 "Failed native ping(), pid: %d was alive: %s waited: %u server started, having pid_file. exec: %.*s stderr:%.*s",
319 int(_app.pid()),
320 _app.check() ? "true" : "false",
321 this_wait,
322 int(_running.size()), _running.c_str(),
323 int(_app.stderr_result_length()), _app.stderr_c_str());
324 }
325 }
326 else
327 {
328 throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
329 hostname(), port(),
330 "Failed native ping(), pid: %d is alive: %s waited: %u server started. exec: %.*s stderr:%.*s",
331 int(_app.pid()),
332 _app.check() ? "true" : "false",
333 this_wait,
334 int(_running.size()), _running.c_str(),
335 int(_app.stderr_result_length()), _app.stderr_c_str());
336 }
337 _running.clear();
338
339 return false;
340 }
341
342 return has_pid();
343 }
344
345 void Server::reset_pid()
346 {
347 _running.clear();
348 _pid_file.clear();
349 }
350
351 pid_t Server::pid() const
352 {
353 return _app.pid();
354 }
355
356 void Server::add_option(const std::string& arg)
357 {
358 _options.push_back(std::make_pair(arg, std::string()));
359 }
360
361 void Server::add_option(const std::string& name_, const std::string& value_)
362 {
363 _options.push_back(std::make_pair(name_, value_));
364 }
365
366 bool Server::set_socket_file()
367 {
368 char file_buffer[FILENAME_MAX];
369 file_buffer[0]= 0;
370
371 if (broken_pid_file())
372 {
373 snprintf(file_buffer, sizeof(file_buffer), "/tmp/%s.socketXXXXXX", name());
374 }
375 else
376 {
377 snprintf(file_buffer, sizeof(file_buffer), "var/run/%s.socketXXXXXX", name());
378 }
379
380 int fd;
381 if ((fd= mkstemp(file_buffer)) == -1)
382 {
383 perror(file_buffer);
384 return false;
385 }
386 close(fd);
387 unlink(file_buffer);
388
389 _socket= file_buffer;
390
391 return true;
392 }
393
394 bool Server::set_pid_file()
395 {
396 char file_buffer[FILENAME_MAX];
397 file_buffer[0]= 0;
398
399 if (broken_pid_file())
400 {
401 snprintf(file_buffer, sizeof(file_buffer), "/tmp/%s.pidXXXXXX", name());
402 }
403 else
404 {
405 snprintf(file_buffer, sizeof(file_buffer), "var/run/%s.pidXXXXXX", name());
406 }
407
408 int fd;
409 if ((fd= mkstemp(file_buffer)) == -1)
410 {
411 throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "mkstemp() failed on %s with %s", file_buffer, strerror(errno));
412 }
413 close(fd);
414 unlink(file_buffer);
415
416 _pid_file= file_buffer;
417
418 return true;
419 }
420
421 bool Server::set_log_file()
422 {
423 char file_buffer[FILENAME_MAX];
424 file_buffer[0]= 0;
425
426 snprintf(file_buffer, sizeof(file_buffer), "var/log/%s.logXXXXXX", name());
427 int fd;
428 if ((fd= mkstemp(file_buffer)) == -1)
429 {
430 throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "mkstemp() failed on %s with %s", file_buffer, strerror(errno));
431 }
432 close(fd);
433
434 _log_file= file_buffer;
435
436 return true;
437 }
438
439 bool Server::args(Application& app)
440 {
441
442 // Set a log file if it was requested (and we can)
443 if (has_log_file_option())
444 {
445 set_log_file();
446 log_file_option(app, _log_file);
447 }
448
449 if (getenv("LIBTEST_SYSLOG") and has_syslog())
450 {
451 app.add_option("--syslog");
452 }
453
454 // Update pid_file
455 {
456 if (_pid_file.empty() and set_pid_file() == false)
457 {
458 return false;
459 }
460
461 pid_file_option(app, pid_file());
462 }
463
464 if (has_socket_file_option())
465 {
466 if (set_socket_file() == false)
467 {
468 return false;
469 }
470
471 socket_file_option(app, _socket);
472 }
473
474 if (has_port_option())
475 {
476 port_option(app, _port);
477 }
478
479 for (Options::const_iterator iter= _options.begin(); iter != _options.end(); ++iter)
480 {
481 if ((*iter).second.empty() == false)
482 {
483 app.add_option((*iter).first, (*iter).second);
484 }
485 else
486 {
487 app.add_option((*iter).first);
488 }
489 }
490
491 return true;
492 }
493
494 bool Server::kill()
495 {
496 if (check_pid(_app.pid())) // If we kill it, reset
497 {
498 _app.murder();
499 if (broken_pid_file() and pid_file().empty() == false)
500 {
501 unlink(pid_file().c_str());
502 }
503
504 if (broken_socket_cleanup() and has_socket() and not socket().empty())
505 {
506 unlink(socket().c_str());
507 }
508
509 reset_pid();
510
511 return true;
512 }
513
514 return false;
515 }
516
517 } // namespace libtest