4
0

common_test_agent.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * Copyright (c) 2010 Red Hat, Inc.
  3. *
  4. * All rights reserved.
  5. *
  6. * Author: Angus Salkeld (asalkeld@redhat.com)
  7. *
  8. * This software licensed under BSD license, the text of which follows:
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. * - Neither the name of the MontaVista Software, Inc. nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  32. * THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include <errno.h>
  35. #include <unistd.h>
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <assert.h>
  39. #include <string.h>
  40. #include <sys/types.h>
  41. #include <sys/socket.h>
  42. #include <netinet/in.h>
  43. #include <arpa/inet.h>
  44. #include <netdb.h>
  45. #include <poll.h>
  46. #include <unistd.h>
  47. #include <fcntl.h>
  48. #include "common_test_agent.h"
  49. static char big_and_buf_rx[HOW_BIG_AND_BUF];
  50. ta_do_command_fn do_command;
  51. static qb_loop_t *poll_handle;
  52. static pre_exit_fn pre_exit = NULL;
  53. qb_loop_t *ta_poll_handle_get(void)
  54. {
  55. return poll_handle;
  56. }
  57. static void shut_me_down(void)
  58. {
  59. if (pre_exit) {
  60. pre_exit();
  61. }
  62. qb_loop_stop(poll_handle);
  63. }
  64. static void ta_handle_command (int sock, char* msg)
  65. {
  66. int num_args;
  67. char *saveptr = NULL;
  68. char *str = strdup (msg);
  69. char *str_len;
  70. char *str_arg;
  71. char *args[5];
  72. int i = 0;
  73. int a = 0;
  74. char* func = NULL;
  75. qb_log(LOG_DEBUG,"(MSG:%s)", msg);
  76. str_len = strtok_r (str, ":", &saveptr);
  77. assert (str_len);
  78. num_args = atoi (str_len) * 2;
  79. for (i = 0; i < num_args / 2; i++) {
  80. str_len = strtok_r (NULL, ":", &saveptr);
  81. str_arg = strtok_r (NULL, ":", &saveptr);
  82. if (func == NULL) {
  83. /* first "arg" is the function */
  84. qb_log (LOG_TRACE, "(LEN:%s, FUNC:%s)", str_len, str_arg);
  85. func = str_arg;
  86. a = 0;
  87. } else {
  88. args[a] = str_arg;
  89. a++;
  90. qb_log (LOG_TRACE, "(LEN:%s, ARG:%s)", str_len, str_arg);
  91. }
  92. }
  93. do_command (sock, func, args, a+1);
  94. free (str);
  95. }
  96. static int server_process_data_fn (
  97. int fd,
  98. int revents,
  99. void *data)
  100. {
  101. char *saveptr;
  102. char *msg;
  103. char *cmd;
  104. int32_t nbytes;
  105. if (revents & POLLHUP || revents & POLLERR) {
  106. qb_log (LOG_INFO, "command sockect got POLLHUP exiting...");
  107. shut_me_down();
  108. return -1;
  109. }
  110. if ((nbytes = recv (fd, big_and_buf_rx, sizeof (big_and_buf_rx), 0)) <= 0) {
  111. /* got error or connection closed by client */
  112. if (nbytes == 0) {
  113. /* connection closed */
  114. qb_log (LOG_WARNING, "socket %d hung up: exiting...", fd);
  115. } else {
  116. qb_perror(LOG_ERR, "recv() failed");
  117. }
  118. shut_me_down();
  119. return -1;
  120. } else {
  121. big_and_buf_rx[nbytes] = '\0';
  122. msg = strtok_r (big_and_buf_rx, ";", &saveptr);
  123. assert (msg);
  124. while (msg) {
  125. cmd = strdup (msg);
  126. ta_handle_command (fd, cmd);
  127. free (cmd);
  128. msg = strtok_r (NULL, ";", &saveptr);
  129. }
  130. }
  131. return 0;
  132. }
  133. static int server_accept_fn (
  134. int fd, int revents, void *data)
  135. {
  136. socklen_t addrlen;
  137. struct sockaddr_in in_addr;
  138. int new_fd;
  139. int res;
  140. if (revents & POLLHUP || revents & POLLERR) {
  141. qb_log (LOG_INFO, "command sockect got POLLHUP exiting...");
  142. shut_me_down();
  143. return -1;
  144. }
  145. addrlen = sizeof (struct sockaddr_in);
  146. retry_accept:
  147. new_fd = accept (fd, (struct sockaddr *)&in_addr, &addrlen);
  148. if (new_fd == -1 && errno == EINTR) {
  149. goto retry_accept;
  150. }
  151. if (new_fd == -1) {
  152. qb_log (LOG_ERR,
  153. "Could not accept connection: %s", strerror (errno));
  154. return (0); /* This is an error, but -1 would indicate disconnect from poll loop */
  155. }
  156. res = fcntl (new_fd, F_SETFL, O_NONBLOCK);
  157. if (res == -1) {
  158. qb_log (LOG_ERR,
  159. "Could not set non-blocking operation on connection: %s",
  160. strerror (errno));
  161. close (new_fd);
  162. return (0); /* This is an error, but -1 would indicate disconnect from poll loop */
  163. }
  164. qb_loop_poll_add (poll_handle,
  165. QB_LOOP_MED,
  166. new_fd,
  167. POLLIN|POLLNVAL,
  168. NULL,
  169. server_process_data_fn);
  170. return 0;
  171. }
  172. static int create_server_sockect (int server_port)
  173. {
  174. int listener;
  175. int yes = 1;
  176. int rv;
  177. struct addrinfo hints, *ai, *p;
  178. char server_port_str[16];
  179. char addr_str[INET_ADDRSTRLEN];
  180. void *ptr = NULL;
  181. /* get a socket and bind it
  182. */
  183. sprintf(server_port_str, "%d", server_port);
  184. memset (&hints, 0, sizeof hints);
  185. hints.ai_family = AF_UNSPEC;
  186. hints.ai_socktype = SOCK_STREAM;
  187. hints.ai_flags = AI_PASSIVE;
  188. if ((rv = getaddrinfo (NULL, server_port_str, &hints, &ai)) != 0) {
  189. qb_log (LOG_ERR, "%s", gai_strerror (rv));
  190. exit (1);
  191. }
  192. for (p = ai; p != NULL; p = p->ai_next) {
  193. listener = socket (p->ai_family, p->ai_socktype, p->ai_protocol);
  194. if (listener < 0) {
  195. continue;
  196. }
  197. /* lose the pesky "address already in use" error message
  198. */
  199. if (setsockopt (listener, SOL_SOCKET, SO_REUSEADDR,
  200. &yes, sizeof(int)) < 0) {
  201. qb_log (LOG_ERR, "setsockopt() failed: %s", strerror (errno));
  202. }
  203. switch (p->ai_family)
  204. {
  205. case AF_INET:
  206. ptr = &((struct sockaddr_in *) p->ai_addr)->sin_addr;
  207. break;
  208. case AF_INET6:
  209. ptr = &((struct sockaddr_in6 *) p->ai_addr)->sin6_addr;
  210. break;
  211. default:
  212. qb_log (LOG_ERR, "address family wrong");
  213. exit (4);
  214. }
  215. if (inet_ntop(p->ai_family, ptr, addr_str, INET_ADDRSTRLEN) == NULL) {
  216. qb_log (LOG_ERR, "inet_ntop() failed: %s", strerror (errno));
  217. }
  218. if (bind (listener, p->ai_addr, p->ai_addrlen) < 0) {
  219. qb_log (LOG_ERR, "bind(%s) failed: %s", addr_str, strerror (errno));
  220. close (listener);
  221. continue;
  222. }
  223. break;
  224. }
  225. if (p == NULL) {
  226. qb_log (LOG_ERR, "failed to bind");
  227. exit (2);
  228. }
  229. freeaddrinfo (ai);
  230. if (listen (listener, 10) == -1) {
  231. qb_log (LOG_ERR, "listen() failed: %s", strerror(errno));
  232. exit (3);
  233. }
  234. return listener;
  235. }
  236. static int32_t sig_exit_handler (int num, void *data)
  237. {
  238. qb_log (LOG_INFO, "got signal %d, exiting", num);
  239. shut_me_down();
  240. return 0;
  241. }
  242. int
  243. test_agent_run(const char * prog_name, int server_port,
  244. ta_do_command_fn func, pre_exit_fn exit_fn)
  245. {
  246. int listener;
  247. qb_log_init(prog_name, LOG_DAEMON, LOG_DEBUG);
  248. qb_log_format_set(QB_LOG_SYSLOG, "%n() [%p] %b");
  249. qb_log (LOG_INFO, "STARTING");
  250. do_command = func;
  251. pre_exit = exit_fn;
  252. poll_handle = qb_loop_create ();
  253. if (exit_fn) {
  254. qb_loop_signal_add(poll_handle, QB_LOOP_HIGH,
  255. SIGINT, NULL, sig_exit_handler, NULL);
  256. qb_loop_signal_add(poll_handle, QB_LOOP_HIGH,
  257. SIGQUIT, NULL, sig_exit_handler, NULL);
  258. qb_loop_signal_add(poll_handle, QB_LOOP_HIGH,
  259. SIGTERM, NULL, sig_exit_handler, NULL);
  260. }
  261. listener = create_server_sockect (server_port);
  262. qb_loop_poll_add (poll_handle,
  263. QB_LOOP_MED,
  264. listener,
  265. POLLIN|POLLNVAL,
  266. NULL, server_accept_fn);
  267. qb_loop_run (poll_handle);
  268. qb_log (LOG_INFO, "EXITING");
  269. qb_log_fini();
  270. return 0;
  271. }