test_mq.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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 (GNUNET_TIME_UNIT_MILLISECONDS, 1)
  29. static unsigned int received_cnt;
  30. GNUNET_NETWORK_STRUCT_BEGIN
  31. struct MyMessage
  32. {
  33. struct GNUNET_MessageHeader header;
  34. uint32_t x GNUNET_PACKED;
  35. };
  36. GNUNET_NETWORK_STRUCT_END
  37. static int global_ret;
  38. static struct GNUNET_SCHEDULER_Task *tt;
  39. static struct GNUNET_SCHEDULER_Task *dt;
  40. static struct GNUNET_MQ_Handle *cmq;
  41. static void
  42. do_shutdown (void *cls)
  43. {
  44. (void) cls;
  45. if (NULL != tt)
  46. {
  47. GNUNET_SCHEDULER_cancel (tt);
  48. tt = NULL;
  49. }
  50. if (NULL != cmq)
  51. {
  52. GNUNET_MQ_destroy (cmq);
  53. cmq = NULL;
  54. }
  55. }
  56. static void
  57. do_timeout (void *cls)
  58. {
  59. (void) cls;
  60. tt = NULL;
  61. GNUNET_SCHEDULER_shutdown ();
  62. global_ret = 1;
  63. }
  64. /**
  65. * Generic error handler, called with the appropriate
  66. * error code and the same closure specified at the creation of
  67. * the message queue.
  68. * Not every message queue implementation supports an error handler.
  69. *
  70. * @param cls closure
  71. * @param error error code
  72. */
  73. static void
  74. error_cb (void *cls,
  75. enum GNUNET_MQ_Error error)
  76. {
  77. GNUNET_break (0);
  78. global_ret = 3;
  79. GNUNET_SCHEDULER_shutdown ();
  80. }
  81. static void
  82. client_continue (void *cls)
  83. {
  84. struct GNUNET_SERVICE_Client *c = cls;
  85. dt = NULL;
  86. GNUNET_SERVICE_client_continue (c);
  87. }
  88. static void
  89. handle_dummy (void *cls,
  90. const struct MyMessage *msg)
  91. {
  92. struct GNUNET_SERVICE_Client *c = cls;
  93. GNUNET_assert (NULL == dt);
  94. /* artificially make receiver slower than sender */
  95. dt = GNUNET_SCHEDULER_add_delayed (RECEIVER_THROTTLE,
  96. &client_continue,
  97. c);
  98. if (received_cnt != ntohl (msg->x))
  99. {
  100. GNUNET_break (0);
  101. global_ret = 4;
  102. GNUNET_SCHEDULER_shutdown ();
  103. }
  104. received_cnt++;
  105. }
  106. static void
  107. handle_dummy2 (void *cls,
  108. const struct MyMessage *msg)
  109. {
  110. struct GNUNET_SERVICE_Client *c = cls;
  111. GNUNET_SERVICE_client_continue (c);
  112. if (NUM_TRANSMISSIONS != received_cnt)
  113. {
  114. GNUNET_break (0);
  115. global_ret = 5;
  116. }
  117. GNUNET_SCHEDULER_shutdown ();
  118. }
  119. /**
  120. * Function called whenever MQ has sent a message.
  121. */
  122. static void
  123. notify_sent_cb (void *cls)
  124. {
  125. static unsigned int seen;
  126. unsigned int *cnt = cls;
  127. if (seen != *cnt)
  128. {
  129. GNUNET_break (0);
  130. global_ret = 6;
  131. GNUNET_SCHEDULER_shutdown ();
  132. }
  133. seen++;
  134. GNUNET_free (cnt);
  135. }
  136. /**
  137. * Start running the actual test.
  138. *
  139. * @param cls closure passed to #GNUNET_SERVICE_MAIN
  140. * @param cfg configuration to use for this service
  141. * @param sh handle to the newly create service
  142. */
  143. static void
  144. run (void *cls,
  145. const struct GNUNET_CONFIGURATION_Handle *cfg,
  146. struct GNUNET_SERVICE_Handle *sh)
  147. {
  148. struct GNUNET_MQ_MessageHandler ch[] = {
  149. GNUNET_MQ_handler_end ()
  150. };
  151. struct GNUNET_MQ_Envelope *env;
  152. struct MyMessage *m;
  153. (void) cls;
  154. (void) sh;
  155. cmq = GNUNET_CLIENT_connect (cfg,
  156. "test_client",
  157. ch,
  158. &error_cb,
  159. NULL);
  160. GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
  161. NULL);
  162. tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
  163. &do_timeout,
  164. NULL);
  165. for (unsigned int i=0;i<NUM_TRANSMISSIONS;i++)
  166. {
  167. unsigned int *cnt;
  168. cnt = GNUNET_new (unsigned int);
  169. *cnt = i;
  170. env = GNUNET_MQ_msg (m,
  171. GNUNET_MESSAGE_TYPE_DUMMY);
  172. GNUNET_MQ_notify_sent (env,
  173. &notify_sent_cb,
  174. cnt);
  175. m->x = htonl (i);
  176. GNUNET_MQ_send (cmq,
  177. env);
  178. }
  179. env = GNUNET_MQ_msg (m,
  180. GNUNET_MESSAGE_TYPE_DUMMY2);
  181. GNUNET_MQ_send (cmq,
  182. env);
  183. }
  184. /**
  185. * Callback to be called when a client connects to the service.
  186. *
  187. * @param cls closure for the service
  188. * @param c the new client that connected to the service
  189. * @param mq the message queue used to send messages to the client
  190. * @return the client-specific (`internal') closure
  191. */
  192. static void *
  193. connect_cb (void *cls,
  194. struct GNUNET_SERVICE_Client *c,
  195. struct GNUNET_MQ_Handle *mq)
  196. {
  197. (void) cls;
  198. (void) mq;
  199. return c;
  200. }
  201. /**
  202. * Callback to be called when a client disconnected from the service
  203. *
  204. * @param cls closure for the service
  205. * @param c the client that disconnected
  206. * @param internal_cls the client-specific (`internal') closure
  207. */
  208. static void
  209. disconnect_cb (void *cls,
  210. struct GNUNET_SERVICE_Client *c,
  211. void *internal_cls)
  212. {
  213. (void) cls;
  214. (void) c;
  215. (void) internal_cls;
  216. }
  217. static void
  218. test1 ()
  219. {
  220. struct GNUNET_MQ_Envelope *mqm;
  221. struct MyMessage *mm;
  222. mm = NULL;
  223. mqm = NULL;
  224. mqm = GNUNET_MQ_msg (mm,
  225. GNUNET_MESSAGE_TYPE_DUMMY);
  226. GNUNET_assert (NULL != mqm);
  227. GNUNET_assert (NULL != mm);
  228. GNUNET_assert (GNUNET_MESSAGE_TYPE_DUMMY == ntohs (mm->header.type));
  229. GNUNET_assert (sizeof (struct MyMessage) == ntohs (mm->header.size));
  230. GNUNET_MQ_discard (mqm);
  231. }
  232. static void
  233. test2 ()
  234. {
  235. struct GNUNET_MQ_Envelope *mqm;
  236. struct GNUNET_MessageHeader *mh;
  237. mqm = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_DUMMY);
  238. /* how could the above be checked? */
  239. GNUNET_MQ_discard (mqm);
  240. mqm = GNUNET_MQ_msg_header_extra (mh,
  241. 20,
  242. GNUNET_MESSAGE_TYPE_DUMMY);
  243. GNUNET_assert (GNUNET_MESSAGE_TYPE_DUMMY == ntohs (mh->type));
  244. GNUNET_assert (sizeof (struct GNUNET_MessageHeader) + 20 == ntohs (mh->size));
  245. GNUNET_MQ_discard (mqm);
  246. }
  247. int
  248. main (int argc, char **argv)
  249. {
  250. char * test_argv[] = {
  251. (char *) "test_client",
  252. "-c",
  253. "test_client_data.conf",
  254. NULL
  255. };
  256. struct GNUNET_MQ_MessageHandler mh[] = {
  257. GNUNET_MQ_hd_fixed_size (dummy,
  258. GNUNET_MESSAGE_TYPE_DUMMY,
  259. struct MyMessage,
  260. NULL),
  261. GNUNET_MQ_hd_fixed_size (dummy2,
  262. GNUNET_MESSAGE_TYPE_DUMMY2,
  263. struct MyMessage,
  264. NULL),
  265. GNUNET_MQ_handler_end ()
  266. };
  267. (void) argc;
  268. (void) argv;
  269. GNUNET_log_setup ("test-mq",
  270. "INFO",
  271. NULL);
  272. test1 ();
  273. test2 ();
  274. if (0 !=
  275. GNUNET_SERVICE_run_ (3,
  276. test_argv,
  277. "test_client",
  278. GNUNET_SERVICE_OPTION_NONE,
  279. &run,
  280. &connect_cb,
  281. &disconnect_cb,
  282. NULL,
  283. mh))
  284. return 1;
  285. return global_ret;
  286. }