memcached.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  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. #include <config.h>
  22. #include <libtest/common.h>
  23. #include <libmemcached-1.0/memcached.h>
  24. #include <libmemcachedutil-1.0/util.h>
  25. using namespace libtest;
  26. #include <cassert>
  27. #include <cerrno>
  28. #include <cstdio>
  29. #include <cstdlib>
  30. #include <cstring>
  31. #include <iostream>
  32. #include <signal.h>
  33. #include <sys/types.h>
  34. #include <sys/wait.h>
  35. #include <unistd.h>
  36. #include <libtest/server.h>
  37. #include <libtest/wait.h>
  38. #include <libtest/memcached.h>
  39. #ifndef __INTEL_COMPILER
  40. #pragma GCC diagnostic ignored "-Wold-style-cast"
  41. #endif
  42. using namespace libtest;
  43. class Memcached : public libtest::Server
  44. {
  45. std::string _username;
  46. std::string _password;
  47. public:
  48. Memcached(const std::string& host_arg, const in_port_t port_arg, const bool is_socket_arg, const std::string& username_arg, const std::string& password_arg) :
  49. libtest::Server(host_arg, port_arg, is_socket_arg, MEMCACHED_BINARY, false),
  50. _username(username_arg),
  51. _password(password_arg)
  52. { }
  53. Memcached(const std::string& host_arg, const in_port_t port_arg, const bool is_socket_arg) :
  54. libtest::Server(host_arg, port_arg, is_socket_arg)
  55. {
  56. set_pid_file();
  57. }
  58. virtual const char *sasl() const
  59. {
  60. return NULL;
  61. }
  62. const std::string& password() const
  63. {
  64. return _password;
  65. }
  66. const std::string& username() const
  67. {
  68. return _username;
  69. }
  70. pid_t get_pid(bool error_is_ok)
  71. {
  72. // Memcached is slow to start, so we need to do this
  73. if (pid_file().empty() == false)
  74. {
  75. if (error_is_ok and
  76. wait_for_pidfile() == false)
  77. {
  78. Error << "Pidfile was not found:" << pid_file();
  79. return -1;
  80. }
  81. }
  82. pid_t local_pid;
  83. memcached_return_t rc= MEMCACHED_SUCCESS;
  84. if (has_socket())
  85. {
  86. if (socket().empty())
  87. {
  88. return -1;
  89. }
  90. local_pid= libmemcached_util_getpid(socket().c_str(), port(), &rc);
  91. }
  92. else
  93. {
  94. local_pid= libmemcached_util_getpid(hostname().c_str(), port(), &rc);
  95. }
  96. if (error_is_ok and ((memcached_failed(rc) or not is_pid_valid(local_pid))))
  97. {
  98. Error << "libmemcached_util_getpid(" << memcached_strerror(NULL, rc) << ") pid: " << local_pid << " for:" << *this;
  99. }
  100. return local_pid;
  101. }
  102. bool ping()
  103. {
  104. // Memcached is slow to start, so we need to do this
  105. if (pid_file().empty() == false)
  106. {
  107. if (wait_for_pidfile() == false)
  108. {
  109. Error << "Pidfile was not found:" << pid_file();
  110. return -1;
  111. }
  112. }
  113. memcached_return_t rc;
  114. bool ret;
  115. if (has_socket())
  116. {
  117. ret= libmemcached_util_ping(socket().c_str(), 0, &rc);
  118. }
  119. else
  120. {
  121. ret= libmemcached_util_ping(hostname().c_str(), port(), &rc);
  122. }
  123. if (memcached_failed(rc) or not ret)
  124. {
  125. Error << "libmemcached_util_ping(" << hostname() << ", " << port() << ") error: " << memcached_strerror(NULL, rc);
  126. }
  127. return ret;
  128. }
  129. const char *name()
  130. {
  131. return "memcached";
  132. };
  133. const char *executable()
  134. {
  135. return MEMCACHED_BINARY;
  136. }
  137. virtual void pid_file_option(Application& app, const std::string& arg)
  138. {
  139. if (arg.empty() == false)
  140. {
  141. app.add_option("-P", arg);
  142. }
  143. }
  144. const char *socket_file_option() const
  145. {
  146. return "-s ";
  147. }
  148. const char *daemon_file_option()
  149. {
  150. return "-d";
  151. }
  152. virtual void port_option(Application& app, in_port_t arg)
  153. {
  154. char buffer[30];
  155. snprintf(buffer, sizeof(buffer), "%d", int(arg));
  156. app.add_option("-p", buffer);
  157. }
  158. bool has_port_option() const
  159. {
  160. return true;
  161. }
  162. bool has_socket_file_option() const
  163. {
  164. return has_socket();
  165. }
  166. void socket_file_option(Application& app, const std::string& socket_arg)
  167. {
  168. if (socket_arg.empty() == false)
  169. {
  170. app.add_option("-s", socket_arg);
  171. }
  172. }
  173. bool is_libtool()
  174. {
  175. return false;
  176. }
  177. bool broken_socket_cleanup()
  178. {
  179. return true;
  180. }
  181. // Memcached's pidfile is broken
  182. bool broken_pid_file()
  183. {
  184. return true;
  185. }
  186. bool build(size_t argc, const char *argv[]);
  187. };
  188. class MemcachedLight : public libtest::Server
  189. {
  190. public:
  191. MemcachedLight(const std::string& host_arg, const in_port_t port_arg) :
  192. libtest::Server(host_arg, port_arg, MEMCACHED_LIGHT_BINARY, true)
  193. {
  194. set_pid_file();
  195. }
  196. pid_t get_pid(bool error_is_ok)
  197. {
  198. // Memcached is slow to start, so we need to do this
  199. if (pid_file().empty() == false)
  200. {
  201. if (error_is_ok and wait_for_pidfile() == false)
  202. {
  203. Error << "Pidfile was not found:" << pid_file();
  204. return -1;
  205. }
  206. }
  207. bool success= false;
  208. std::stringstream error_message;
  209. pid_t local_pid= get_pid_from_file(pid_file(), error_message);
  210. if (local_pid > 0)
  211. {
  212. if (::kill(local_pid, 0) > 0)
  213. {
  214. success= true;
  215. }
  216. }
  217. if (error_is_ok and ((success or not is_pid_valid(local_pid))))
  218. {
  219. Error << "kill(" << " pid: " << local_pid << " errno:" << strerror(errno) << " for:" << *this;
  220. }
  221. return local_pid;
  222. }
  223. bool ping()
  224. {
  225. // Memcached is slow to start, so we need to do this
  226. if (not pid_file().empty())
  227. {
  228. if (not wait_for_pidfile())
  229. {
  230. Error << "Pidfile was not found:" << pid_file();
  231. return false;
  232. }
  233. }
  234. std::stringstream error_message;
  235. pid_t local_pid= get_pid_from_file(pid_file(), error_message);
  236. if (local_pid > 0)
  237. {
  238. if (::kill(local_pid, 0) == 0)
  239. {
  240. return true;
  241. }
  242. }
  243. return false;
  244. }
  245. const char *name()
  246. {
  247. return "memcached_light";
  248. };
  249. const char *executable()
  250. {
  251. return MEMCACHED_LIGHT_BINARY;
  252. }
  253. const char *daemon_file_option()
  254. {
  255. return "--daemon";
  256. }
  257. virtual void port_option(Application& app, in_port_t arg)
  258. {
  259. char buffer[1024];
  260. snprintf(buffer, sizeof(buffer), "--port=%d", int(arg));
  261. app.add_option(buffer);
  262. }
  263. bool has_port_option() const
  264. {
  265. return true;
  266. }
  267. bool is_libtool()
  268. {
  269. return true;
  270. }
  271. void log_file_option(Application& app, const std::string& arg)
  272. {
  273. if (arg.empty() == false)
  274. {
  275. std::string buffer("--log-file=");
  276. buffer+= arg;
  277. app.add_option("--verbose");
  278. app.add_option(buffer);
  279. }
  280. }
  281. bool has_log_file_option() const
  282. {
  283. return true;
  284. }
  285. bool build(size_t argc, const char *argv[]);
  286. };
  287. class MemcachedSaSL : public Memcached
  288. {
  289. public:
  290. MemcachedSaSL(const std::string& host_arg,
  291. const in_port_t port_arg,
  292. const bool is_socket_arg,
  293. const std::string& username_arg,
  294. const std::string &password_arg) :
  295. Memcached(host_arg, port_arg, is_socket_arg, username_arg, password_arg)
  296. { }
  297. const char *name()
  298. {
  299. return "memcached-sasl";
  300. };
  301. const char *sasl() const
  302. {
  303. return " -S -B binary ";
  304. }
  305. const char *executable()
  306. {
  307. return MEMCACHED_SASL_BINARY;
  308. }
  309. pid_t get_pid(bool error_is_ok)
  310. {
  311. // Memcached is slow to start, so we need to do this
  312. if (pid_file().empty() == false)
  313. {
  314. if (error_is_ok and
  315. wait_for_pidfile() == false)
  316. {
  317. Error << "Pidfile was not found:" << pid_file();
  318. return -1;
  319. }
  320. }
  321. pid_t local_pid;
  322. memcached_return_t rc;
  323. if (has_socket())
  324. {
  325. local_pid= libmemcached_util_getpid2(socket().c_str(), 0, username().c_str(), password().c_str(), &rc);
  326. }
  327. else
  328. {
  329. local_pid= libmemcached_util_getpid2(hostname().c_str(), port(), username().c_str(), password().c_str(), &rc);
  330. }
  331. if (error_is_ok and ((memcached_failed(rc) or not is_pid_valid(local_pid))))
  332. {
  333. Error << "libmemcached_util_getpid2(" << memcached_strerror(NULL, rc) << ") username: " << username() << " password: " << password() << " pid: " << local_pid << " for:" << *this;
  334. }
  335. return local_pid;
  336. }
  337. bool ping()
  338. {
  339. // Memcached is slow to start, so we need to do this
  340. if (pid_file().empty() == false)
  341. {
  342. if (wait_for_pidfile() == false)
  343. {
  344. Error << "Pidfile was not found:" << pid_file();
  345. return -1;
  346. }
  347. }
  348. memcached_return_t rc;
  349. bool ret;
  350. if (has_socket())
  351. {
  352. ret= libmemcached_util_ping2(socket().c_str(), 0, username().c_str(), password().c_str(), &rc);
  353. }
  354. else
  355. {
  356. ret= libmemcached_util_ping2(hostname().c_str(), port(), username().c_str(), password().c_str(), &rc);
  357. }
  358. if (memcached_failed(rc) or ret == false)
  359. {
  360. Error << "libmemcached_util_ping2(" << hostname() << ", " << port() << ", " << username() << ", " << password() << ") error: " << memcached_strerror(NULL, rc);
  361. }
  362. return ret;
  363. }
  364. };
  365. #include <sstream>
  366. bool Memcached::build(size_t argc, const char *argv[])
  367. {
  368. std::stringstream arg_buffer;
  369. if (getuid() == 0 or geteuid() == 0)
  370. {
  371. add_option("-u", "root");
  372. }
  373. add_option("-l", "localhost");
  374. add_option("-m", "128");
  375. add_option("-M");
  376. if (sasl())
  377. {
  378. add_option(sasl());
  379. }
  380. for (int x= 0 ; x < argc ; x++)
  381. {
  382. add_option(argv[x]);
  383. }
  384. return true;
  385. }
  386. bool MemcachedLight::build(size_t argc, const char *argv[])
  387. {
  388. for (size_t x= 0 ; x < argc ; x++)
  389. {
  390. add_option(argv[x]);
  391. }
  392. return true;
  393. }
  394. namespace libtest {
  395. libtest::Server *build_memcached(const std::string& hostname, const in_port_t try_port)
  396. {
  397. return new Memcached(hostname, try_port, false);
  398. }
  399. libtest::Server *build_memcached_socket(const std::string& socket_file, const in_port_t try_port)
  400. {
  401. return new Memcached(socket_file, try_port, true);
  402. }
  403. libtest::Server *build_memcached_light(const std::string& hostname, const in_port_t try_port)
  404. {
  405. return new MemcachedLight(hostname, try_port);
  406. }
  407. libtest::Server *build_memcached_sasl(const std::string& hostname, const in_port_t try_port, const std::string& username, const std::string &password)
  408. {
  409. if (username.empty())
  410. {
  411. return new MemcachedSaSL(hostname, try_port, false, "memcached", "memcached");
  412. }
  413. return new MemcachedSaSL(hostname, try_port, false, username, password);
  414. }
  415. libtest::Server *build_memcached_sasl_socket(const std::string& socket_file, const in_port_t try_port, const std::string& username, const std::string &password)
  416. {
  417. if (username.empty())
  418. {
  419. return new MemcachedSaSL(socket_file, try_port, true, "memcached", "memcached");
  420. }
  421. return new MemcachedSaSL(socket_file, try_port, true, username, password);
  422. }
  423. }