55713d45ced450d831bb71d971c98b6371156b02
[m6w6/libmemcached] / libtest / server.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * libtest
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22
23 #include <config.h>
24 #include <libtest/common.h>
25
26 #include <cassert>
27 #include <cerrno>
28 #include <cstdlib>
29 #include <iostream>
30
31 #include <algorithm>
32 #include <functional>
33 #include <locale>
34
35 // trim from end
36 static inline std::string &rtrim(std::string &s)
37 {
38 s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
39 return s;
40 }
41
42 #include <libtest/server.h>
43 #include <libtest/stream.h>
44 #include <libtest/killpid.h>
45
46 namespace libtest {
47
48 std::ostream& operator<<(std::ostream& output, const Server &arg)
49 {
50 if (arg.is_socket())
51 {
52 output << arg.hostname();
53 }
54 else
55 {
56 output << arg.hostname() << ":" << arg.port();
57 }
58
59 if (arg.has_pid())
60 {
61 output << " Pid:" << arg.pid();
62 }
63
64 if (arg.has_socket())
65 {
66 output << " Socket:" << arg.socket();
67 }
68
69 if (arg.running().empty() == false)
70 {
71 output << " Exec:" << arg.running();
72 }
73
74 return output; // for multiple << operators
75 }
76
77 #define MAGIC_MEMORY 123570
78
79 Server::Server(const std::string& host_arg, const in_port_t port_arg,
80 const std::string& executable, const bool _is_libtool,
81 bool is_socket_arg) :
82 _magic(MAGIC_MEMORY),
83 _is_socket(is_socket_arg),
84 _pid(-1),
85 _port(port_arg),
86 _hostname(host_arg),
87 _app(executable, _is_libtool)
88 {
89 }
90
91 Server::~Server()
92 {
93 if (has_pid() and not kill(_pid))
94 {
95 Error << "Unable to kill:" << *this;
96 }
97
98 Application::error_t ret;
99 if (Application::SUCCESS != (ret= _app.wait()))
100 {
101 Error << "Application::wait() " << _running << " " << ret << ": " << _app.stderr_result();
102 }
103 }
104
105 bool Server::check()
106 {
107 _app.slurp();
108 return _app.check();
109 }
110
111 bool Server::validate()
112 {
113 return _magic == MAGIC_MEMORY;
114 }
115
116 // If the server exists, kill it
117 bool Server::cycle()
118 {
119 uint32_t limit= 3;
120
121 // Try to ping, and kill the server #limit number of times
122 pid_t current_pid;
123 while (--limit and
124 is_pid_valid(current_pid= get_pid()))
125 {
126 if (kill(current_pid))
127 {
128 Log << "Killed existing server," << *this << " with pid:" << current_pid;
129 dream(0, 50000);
130 continue;
131 }
132 }
133
134 // For whatever reason we could not kill it, and we reached limit
135 if (limit == 0)
136 {
137 Error << "Reached limit, could not kill server pid:" << current_pid;
138 return false;
139 }
140
141 return true;
142 }
143
144 bool Server::wait_for_pidfile() const
145 {
146 Wait wait(pid_file(), 4);
147
148 return wait.successful();
149 }
150
151 bool Server::start()
152 {
153 // If we find that we already have a pid then kill it.
154 if (has_pid() and kill(_pid) == false)
155 {
156 Error << "Could not kill() existing server during start() pid:" << _pid;
157 return false;
158 }
159
160 if (has_pid() == false)
161 {
162 fatal_message("has_pid() failed, programer error");
163 }
164
165 // This needs more work.
166 #if 0
167 if (gdb_is_caller())
168 {
169 _app.use_gdb();
170 }
171 #endif
172
173 if (args(_app) == false)
174 {
175 Error << "Could not build command()";
176 return false;
177 }
178
179 Application::error_t ret;
180 if (Application::SUCCESS != (ret= _app.run()))
181 {
182 Error << "Application::run() " << ret;
183 return false;
184 }
185 _running= _app.print();
186
187 if (valgrind_is_caller())
188 {
189 dream(5, 50000);
190 }
191
192 if (pid_file().empty() == false)
193 {
194 Wait wait(pid_file(), 8);
195
196 if (wait.successful() == false)
197 {
198 libtest::fatal(LIBYATL_DEFAULT_PARAM,
199 "Unable to open pidfile for: %s",
200 _running.c_str());
201 }
202 }
203
204 uint32_t this_wait;
205 bool pinged= false;
206 {
207 uint32_t timeout= 20; // This number should be high enough for valgrind startup (which is slow)
208 uint32_t waited;
209 uint32_t retry;
210
211 for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
212 {
213 if ((pinged= ping()) == true)
214 {
215 break;
216 }
217 else if (waited >= timeout)
218 {
219 break;
220 }
221
222 this_wait= retry * retry / 3 + 1;
223 libtest::dream(this_wait, 0);
224 }
225 }
226
227 if (pinged == false)
228 {
229 // If we happen to have a pid file, lets try to kill it
230 if (pid_file().empty() == false)
231 {
232 if (kill_file(pid_file()) == false)
233 {
234 fatal_message("Failed to kill off server after startup occurred, when pinging failed");
235 }
236 Error << "Failed to ping(), waited:" << this_wait
237 << " server started, having pid_file. exec:" << _running
238 << " error:" << _app.stderr_result();
239 }
240 else
241 {
242 Error << "Failed to ping() server started. exec:" << _running;
243 }
244 _running.clear();
245 return false;
246 }
247
248 // A failing get_pid() at this point is considered an error
249 _pid= get_pid(true);
250
251 return has_pid();
252 }
253
254 void Server::reset_pid()
255 {
256 _running.clear();
257 _pid_file.clear();
258 _pid= -1;
259 }
260
261 pid_t Server::pid()
262 {
263 return _pid;
264 }
265
266 void Server::add_option(const std::string& arg)
267 {
268 _options.push_back(std::make_pair(arg, std::string()));
269 }
270
271 void Server::add_option(const std::string& name, const std::string& value)
272 {
273 _options.push_back(std::make_pair(name, value));
274 }
275
276 bool Server::set_socket_file()
277 {
278 char file_buffer[FILENAME_MAX];
279 file_buffer[0]= 0;
280
281 if (broken_pid_file())
282 {
283 snprintf(file_buffer, sizeof(file_buffer), "/tmp/%s.socketXXXXXX", name());
284 }
285 else
286 {
287 snprintf(file_buffer, sizeof(file_buffer), "var/run/%s.socketXXXXXX", name());
288 }
289
290 int fd;
291 if ((fd= mkstemp(file_buffer)) == -1)
292 {
293 perror(file_buffer);
294 return false;
295 }
296 close(fd);
297 unlink(file_buffer);
298
299 _socket= file_buffer;
300
301 return true;
302 }
303
304 bool Server::set_pid_file()
305 {
306 char file_buffer[FILENAME_MAX];
307 file_buffer[0]= 0;
308
309 if (broken_pid_file())
310 {
311 snprintf(file_buffer, sizeof(file_buffer), "/tmp/%s.pidXXXXXX", name());
312 }
313 else
314 {
315 snprintf(file_buffer, sizeof(file_buffer), "var/run/%s.pidXXXXXX", name());
316 }
317
318 int fd;
319 if ((fd= mkstemp(file_buffer)) == -1)
320 {
321 perror(file_buffer);
322 return false;
323 }
324 close(fd);
325 unlink(file_buffer);
326
327 _pid_file= file_buffer;
328
329 return true;
330 }
331
332 bool Server::set_log_file()
333 {
334 char file_buffer[FILENAME_MAX];
335 file_buffer[0]= 0;
336
337 snprintf(file_buffer, sizeof(file_buffer), "var/log/%s.logXXXXXX", name());
338 int fd;
339 if ((fd= mkstemp(file_buffer)) == -1)
340 {
341 libtest::fatal(LIBYATL_DEFAULT_PARAM, "mkstemp() failed on %s with %s", file_buffer, strerror(errno));
342 }
343 close(fd);
344
345 _log_file= file_buffer;
346
347 return true;
348 }
349
350 bool Server::args(Application& app)
351 {
352
353 // Set a log file if it was requested (and we can)
354 if (has_log_file_option())
355 {
356 set_log_file();
357 log_file_option(app, _log_file);
358 }
359
360 if (getenv("LIBTEST_SYSLOG") and has_syslog())
361 {
362 app.add_option("--syslog");
363 }
364
365 // Update pid_file
366 {
367 if (_pid_file.empty() and set_pid_file() == false)
368 {
369 return false;
370 }
371
372 pid_file_option(app, pid_file());
373 }
374
375 if (has_socket_file_option())
376 {
377 if (set_socket_file() == false)
378 {
379 return false;
380 }
381
382 socket_file_option(app, _socket);
383 }
384
385 if (has_port_option())
386 {
387 port_option(app, _port);
388 }
389
390 for (Options::const_iterator iter= _options.begin(); iter != _options.end(); iter++)
391 {
392 if ((*iter).second.empty() == false)
393 {
394 app.add_option((*iter).first, (*iter).second);
395 }
396 else
397 {
398 app.add_option((*iter).first);
399 }
400 }
401
402 return true;
403 }
404
405 bool Server::kill(pid_t pid_arg)
406 {
407 if (check_pid(pid_arg) and kill_pid(pid_arg)) // If we kill it, reset
408 {
409 if (broken_pid_file() and pid_file().empty() == false)
410 {
411 unlink(pid_file().c_str());
412 }
413
414 if (broken_socket_cleanup() and has_socket() and not socket().empty())
415 {
416 unlink(socket().c_str());
417 }
418
419 reset_pid();
420
421 return true;
422 }
423
424 return false;
425 }
426
427 } // namespace libtest