test_mq.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012, 2018 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file util/test_mq.c
  18. * @brief tests for mq
  19. * @author Florian Dold
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #define NUM_TRANSMISSIONS 500
  25. /**
  26. * How long does the receiver take per message?
  27. */
  28. #define RECEIVER_THROTTLE GNUNET_TIME_relative_multiply ( \
  29. GNUNET_TIME_UNIT_MILLISECONDS, 1)
  30. static unsigned int received_cnt;
  31. GNUNET_NETWORK_STRUCT_BEGIN
  32. struct MyMessage
  33. {
  34. struct GNUNET_MessageHeader header;
  35. uint32_t x GNUNET_PACKED;
  36. };
  37. GNUNET_NETWORK_STRUCT_END
  38. static int global_ret;
  39. static struct GNUNET_SCHEDULER_Task *tt;
  40. static struct GNUNET_SCHEDULER_Task *dt;
  41. static struct GNUNET_MQ_Handle *cmq;
  42. static void
  43. do_shutdown (void *cls)
  44. {
  45. (void) cls;
  46. if (NULL != tt)
  47. {
  48. GNUNET_SCHEDULER_cancel (tt);
  49. tt = NULL;
  50. }
  51. if (NULL != cmq)
  52. {
  53. GNUNET_MQ_destroy (cmq);
  54. cmq = NULL;
  55. }
  56. }
  57. static void
  58. do_timeout (void *cls)
  59. {
  60. (void) cls;
  61. tt = NULL;
  62. GNUNET_SCHEDULER_shutdown ();
  63. global_ret = 1;
  64. }
  65. /**
  66. * Generic error handler, called with the appropriate
  67. * error code and the same closure specified at the creation of
  68. * the message queue.
  69. * Not every message queue implementation supports an error handler.
  70. *
  71. * @param cls closure
  72. * @param error error code
  73. */
  74. static void
  75. error_cb (void *cls,
  76. enum GNUNET_MQ_Error error)
  77. {
  78. GNUNET_break (0);
  79. global_ret = 3;
  80. GNUNET_SCHEDULER_shutdown ();
  81. }
  82. static void
  83. client_continue (void *cls)
  84. {
  85. struct GNUNET_SERVICE_Client *c = cls;
  86. dt = NULL;
  87. GNUNET_SERVICE_client_continue (c);
  88. }
  89. static void
  90. handle_dummy (void *cls,
  91. const struct MyMessage *msg)
  92. {
  93. struct GNUNET_SERVICE_Client *c = cls;
  94. GNUNET_assert (NULL == dt);
  95. /* artificially make receiver slower than sender */
  96. dt = GNUNET_SCHEDULER_add_delayed (RECEIVER_THROTTLE,
  97. &client_continue,
  98. c);
  99. if (received_cnt != ntohl (msg->x))
  100. {
  101. GNUNET_break (0);
  102. global_ret = 4;
  103. GNUNET_SCHEDULER_shutdown ();
  104. }
  105. received_cnt++;
  106. }
  107. static void
  108. handle_dummy2 (void *cls,
  109. const struct MyMessage *msg)
  110. {
  111. struct GNUNET_SERVICE_Client *c = cls;
  112. GNUNET_SERVICE_client_continue (c);
  113. if (NUM_TRANSMISSIONS != received_cnt)
  114. {
  115. GNUNET_break (0);
  116. global_ret = 5;
  117. }
  118. GNUNET_SCHEDULER_shutdown ();
  119. }
  120. /**
  121. * Function called whenever MQ has sent a message.
  122. */
  123. static void
  124. notify_sent_cb (void *cls)
  125. {
  126. static unsigned int seen;
  127. unsigned int *cnt = cls;
  128. if (seen != *cnt)
  129. {
  130. GNUNET_break (0);
  131. global_ret = 6;
  132. GNUNET_SCHEDULER_shutdown ();
  133. }
  134. seen++;
  135. GNUNET_free (cnt);
  136. }
  137. /**
  138. * Start running the actual test.
  139. *
  140. * @param cls closure passed to #GNUNET_SERVICE_MAIN
  141. * @param cfg configuration to use for this service
  142. * @param sh handle to the newly create service
  143. */
  144. static void
  145. run (void *cls,
  146. const struct GNUNET_CONFIGURATION_Handle *cfg,
  147. struct GNUNET_SERVICE_Handle *sh)
  148. {
  149. struct GNUNET_MQ_MessageHandler ch[] = {
  150. GNUNET_MQ_handler_end ()
  151. };
  152. struct GNUNET_MQ_Envelope *env;
  153. struct MyMessage *m;
  154. (void) cls;
  155. (void) sh;
  156. cmq = GNUNET_CLIENT_connect (cfg,
  157. "test_client",
  158. ch,
  159. &error_cb,
  160. NULL);
  161. GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
  162. NULL);
  163. tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
  164. &do_timeout,
  165. NULL);
  166. for (unsigned int i = 0; i < NUM_TRANSMISSIONS; i++)
  167. {
  168. unsigned int *cnt;
  169. cnt = GNUNET_new (unsigned int);
  170. *cnt = i;
  171. env = GNUNET_MQ_msg (m,
  172. GNUNET_MESSAGE_TYPE_DUMMY);
  173. GNUNET_MQ_notify_sent (env,
  174. &notify_sent_cb,
  175. cnt);
  176. m->x = htonl (i);
  177. GNUNET_MQ_send (cmq,
  178. env);
  179. }
  180. env = GNUNET_MQ_msg (m,
  181. GNUNET_MESSAGE_TYPE_DUMMY2);
  182. GNUNET_MQ_send (cmq,
  183. env);
  184. }
  185. /**
  186. * Callback to be called when a client connects to the service.
  187. *
  188. * @param cls closure for the service
  189. * @param c the new client that connected to the service
  190. * @param mq the message queue used to send messages to the client
  191. * @return the client-specific (`internal') closure
  192. */
  193. static void *
  194. connect_cb (void *cls,
  195. struct GNUNET_SERVICE_Client *c,
  196. struct GNUNET_MQ_Handle *mq)
  197. {
  198. (void) cls;
  199. (void) mq;
  200. return c;
  201. }
  202. /**
  203. * Callback to be called when a client disconnected from the service
  204. *
  205. * @param cls closure for the service
  206. * @param c the client that disconnected
  207. * @param internal_cls the client-specific (`internal') closure
  208. */
  209. static void
  210. disconnect_cb (void *cls,
  211. struct GNUNET_SERVICE_Client *c,
  212. void *internal_cls)
  213. {
  214. (void) cls;
  215. (void) c;
  216. (void) internal_cls;
  217. }
  218. static void
  219. test1 ()
  220. {
  221. struct GNUNET_MQ_Envelope *mqm;
  222. struct MyMessage *mm;
  223. mm = NULL;
  224. mqm = NULL;
  225. mqm = GNUNET_MQ_msg (mm,
  226. GNUNET_MESSAGE_TYPE_DUMMY);
  227. GNUNET_assert (NULL != mqm);
  228. GNUNET_assert (NULL != mm);
  229. GNUNET_assert (GNUNET_MESSAGE_TYPE_DUMMY == ntohs (mm->header.type));
  230. GNUNET_assert (sizeof(struct MyMessage) == ntohs (mm->header.size));
  231. GNUNET_MQ_discard (mqm);
  232. }
  233. static void
  234. test2 ()
  235. {
  236. struct GNUNET_MQ_Envelope *mqm;
  237. struct GNUNET_MessageHeader *mh;
  238. mqm = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_DUMMY);
  239. /* how could the above be checked? */
  240. GNUNET_MQ_discard (mqm);
  241. mqm = GNUNET_MQ_msg_header_extra (mh,
  242. 20,
  243. GNUNET_MESSAGE_TYPE_DUMMY);
  244. GNUNET_assert (GNUNET_MESSAGE_TYPE_DUMMY == ntohs (mh->type));
  245. GNUNET_assert (sizeof(struct GNUNET_MessageHeader) + 20 == ntohs (mh->size));
  246. GNUNET_MQ_discard (mqm);
  247. }
  248. int
  249. main (int argc, char **argv)
  250. {
  251. char *test_argv[] = {
  252. (char *) "test_client",
  253. "-c",
  254. "test_client_data.conf",
  255. NULL
  256. };
  257. struct GNUNET_MQ_MessageHandler mh[] = {
  258. GNUNET_MQ_hd_fixed_size (dummy,
  259. GNUNET_MESSAGE_TYPE_DUMMY,
  260. struct MyMessage,
  261. NULL),
  262. GNUNET_MQ_hd_fixed_size (dummy2,
  263. GNUNET_MESSAGE_TYPE_DUMMY2,
  264. struct MyMessage,
  265. NULL),
  266. GNUNET_MQ_handler_end ()
  267. };
  268. (void) argc;
  269. (void) argv;
  270. GNUNET_log_setup ("test-mq",
  271. "INFO",
  272. NULL);
  273. test1 ();
  274. test2 ();
  275. if (0 !=
  276. GNUNET_SERVICE_run_ (3,
  277. test_argv,
  278. "test_client",
  279. GNUNET_SERVICE_OPTION_NONE,
  280. &run,
  281. &connect_cb,
  282. &disconnect_cb,
  283. NULL,
  284. mh))
  285. return 1;
  286. return global_ret;
  287. }