You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rspamd_http_test.c 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /* Copyright (c) 2015, Vsevolod Stakhov
  2. * All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. * * Redistributions of source code must retain the above copyright
  7. * notice, this list of conditions and the following disclaimer.
  8. * * Redistributions in binary form must reproduce the above copyright
  9. * notice, this list of conditions and the following disclaimer in the
  10. * documentation and/or other materials provided with the distribution.
  11. *
  12. * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
  13. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  16. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #include "config.h"
  24. #include "main.h"
  25. #include "util.h"
  26. #include "http.h"
  27. #include "tests.h"
  28. #include "ottery.h"
  29. #include "cryptobox.h"
  30. static const int file_blocks = 8;
  31. static const int pconns = 10;
  32. static const int ntests = 3000;
  33. static void
  34. rspamd_server_error (struct rspamd_http_connection_entry *conn_ent,
  35. GError *err)
  36. {
  37. msg_err ("http error occurred: %s", err->message);
  38. g_assert (0);
  39. }
  40. static void
  41. rspamd_server_finish (struct rspamd_http_connection_entry *conn_ent)
  42. {
  43. /* Do nothing here */
  44. }
  45. static void
  46. rspamd_server_accept (gint fd, short what, void *arg)
  47. {
  48. struct rspamd_http_connection_router *rt = arg;
  49. rspamd_inet_addr_t addr;
  50. gint nfd;
  51. if ((nfd =
  52. rspamd_accept_from_socket (fd, &addr)) == -1) {
  53. msg_warn ("accept failed: %s", strerror (errno));
  54. return;
  55. }
  56. /* Check for EAGAIN */
  57. if (nfd == 0) {
  58. return;
  59. }
  60. rspamd_http_router_handle_socket (rt, nfd, NULL);
  61. }
  62. static void
  63. rspamd_http_server_func (const gchar *path, rspamd_inet_addr_t *addr,
  64. rspamd_mempool_mutex_t *mtx, gpointer kp, struct rspamd_keypair_cache *c)
  65. {
  66. struct rspamd_http_connection_router *rt;
  67. struct event_base *ev_base = event_init ();
  68. struct event accept_ev;
  69. gint fd;
  70. rt = rspamd_http_router_new (rspamd_server_error, rspamd_server_finish,
  71. NULL, ev_base, path, c);
  72. g_assert (rt != NULL);
  73. rspamd_http_router_set_key (rt, kp);
  74. g_assert ((fd = rspamd_inet_address_listen (addr, SOCK_STREAM, TRUE)) != -1);
  75. event_set (&accept_ev, fd, EV_READ | EV_PERSIST, rspamd_server_accept, rt);
  76. event_base_set (ev_base, &accept_ev);
  77. event_add (&accept_ev, NULL);
  78. rspamd_mempool_unlock_mutex (mtx);
  79. event_base_loop (ev_base, 0);
  80. }
  81. static gint
  82. rspamd_client_body (struct rspamd_http_connection *conn,
  83. struct rspamd_http_message *msg,
  84. const gchar *chunk, gsize len)
  85. {
  86. g_assert (chunk[0] == '\0');
  87. return 0;
  88. }
  89. struct client_cbdata {
  90. double *lat;
  91. gdouble ts;
  92. };
  93. static void
  94. rspamd_client_err (struct rspamd_http_connection *conn, GError *err)
  95. {
  96. msg_info ("abnormally closing connection from: error: %s",
  97. err->message);
  98. g_assert (0);
  99. close (conn->fd);
  100. rspamd_http_connection_unref (conn);
  101. }
  102. static gint
  103. rspamd_client_finish (struct rspamd_http_connection *conn,
  104. struct rspamd_http_message *msg)
  105. {
  106. struct client_cbdata *cb = conn->ud;
  107. struct timespec ts;
  108. *(cb->lat) = rspamd_get_ticks () * 1000.;
  109. close (conn->fd);
  110. rspamd_http_connection_unref (conn);
  111. g_free (cb);
  112. return 0;
  113. }
  114. static void
  115. rspamd_http_client_func (const gchar *path, rspamd_inet_addr_t *addr,
  116. gpointer kp, gpointer peer_kp, struct rspamd_keypair_cache *c,
  117. struct event_base *ev_base, double *latency)
  118. {
  119. struct rspamd_http_message *msg;
  120. struct rspamd_http_connection *conn;
  121. gchar urlbuf[PATH_MAX];
  122. struct client_cbdata *cb;
  123. gint fd;
  124. g_assert ((fd = rspamd_inet_address_connect (addr, SOCK_STREAM, TRUE)) != -1);
  125. conn = rspamd_http_connection_new (rspamd_client_body, rspamd_client_err,
  126. rspamd_client_finish, RSPAMD_HTTP_CLIENT_SIMPLE,
  127. RSPAMD_HTTP_CLIENT, c);
  128. rspamd_snprintf (urlbuf, sizeof (urlbuf), "http://127.0.0.1/%s", path);
  129. msg = rspamd_http_message_from_url (urlbuf);
  130. g_assert (conn != NULL && msg != NULL);
  131. if (kp != NULL) {
  132. g_assert (peer_kp != NULL);
  133. rspamd_http_connection_set_key (conn, kp);
  134. msg->peer_key = rspamd_http_connection_key_ref (peer_kp);
  135. }
  136. cb = g_malloc (sizeof (*cb));
  137. cb->ts = rspamd_get_ticks ();
  138. cb->lat = latency;
  139. rspamd_http_connection_write_message (conn, msg, NULL, NULL, cb,
  140. fd, NULL, ev_base);
  141. }
  142. static int
  143. cmpd (const void *p1, const void *p2)
  144. {
  145. const double *d1 = p1, *d2 = p2;
  146. return (*d1) - (*d2);
  147. }
  148. double
  149. rspamd_http_calculate_mean (double *lats, double *std)
  150. {
  151. gint i;
  152. gdouble mean = 0., dev = 0.;
  153. qsort (lats, ntests * pconns, sizeof (double), cmpd);
  154. for (i = 0; i < ntests * pconns; i ++) {
  155. mean += lats[i];
  156. }
  157. mean /= ntests * pconns;
  158. for (i = 0; i < ntests * pconns; i ++) {
  159. dev += (lats[i] - mean) * (lats[i] - mean);
  160. }
  161. dev /= ntests * pconns;
  162. *std = sqrt (dev);
  163. return mean;
  164. }
  165. void
  166. rspamd_http_test_func (void)
  167. {
  168. struct event_base *ev_base = event_init ();
  169. rspamd_mempool_t *pool = rspamd_mempool_new (rspamd_mempool_suggest_size ());
  170. gpointer serv_key, client_key, peer_key;
  171. struct rspamd_keypair_cache *c;
  172. rspamd_mempool_mutex_t *mtx;
  173. rspamd_inet_addr_t addr;
  174. gdouble ts1, ts2;
  175. gchar filepath[PATH_MAX], buf[512];
  176. gint fd, i, j;
  177. pid_t sfd;
  178. GString *b32_key;
  179. double diff, total_diff = 0.0, latency[pconns * ntests], mean, std;
  180. rspamd_cryptobox_init ();
  181. rspamd_snprintf (filepath, sizeof (filepath), "/tmp/http-test-XXXXXX");
  182. g_assert ((fd = mkstemp (filepath)) != -1);
  183. for (i = 0; i < file_blocks; i ++) {
  184. memset (buf, 0, sizeof (buf));
  185. g_assert (write (fd, buf, sizeof (buf)) == sizeof (buf));
  186. }
  187. mtx = rspamd_mempool_get_mutex (pool);
  188. rspamd_parse_inet_address (&addr, "127.0.0.1");
  189. rspamd_inet_address_set_port (&addr, ottery_rand_range (30000) + 32768);
  190. serv_key = rspamd_http_connection_gen_key ();
  191. client_key = rspamd_http_connection_gen_key ();
  192. c = rspamd_keypair_cache_new (16);
  193. rspamd_mempool_lock_mutex (mtx);
  194. sfd = fork ();
  195. g_assert (sfd != -1);
  196. if (sfd == 0) {
  197. rspamd_http_server_func ("/tmp/", &addr, mtx, serv_key, c);
  198. exit (EXIT_SUCCESS);
  199. }
  200. rspamd_mempool_lock_mutex (mtx);
  201. /* Do client stuff */
  202. for (i = 0; i < ntests; i ++) {
  203. for (j = 0; j < pconns; j ++) {
  204. rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, &addr,
  205. NULL, NULL, c, ev_base, &latency[i * pconns + j]);
  206. }
  207. ts1 = rspamd_get_ticks ();
  208. event_base_loop (ev_base, 0);
  209. ts2 = rspamd_get_ticks ();
  210. diff = (ts2 - ts1) * 1000.0;
  211. total_diff += diff;
  212. }
  213. msg_info ("Made %d connections of size %d in %.6f ms, %.6f cps",
  214. ntests * pconns,
  215. sizeof (buf) * file_blocks,
  216. total_diff, ntests * pconns / total_diff * 1000.);
  217. mean = rspamd_http_calculate_mean (latency, &std);
  218. msg_info ("Latency: %.6f ms mean, %.6f dev",
  219. mean, std);
  220. /* Now test encrypted */
  221. b32_key = rspamd_http_connection_print_key (serv_key,
  222. RSPAMD_KEYPAIR_PUBKEY|RSPAMD_KEYPAIR_BASE32);
  223. g_assert (b32_key != NULL);
  224. peer_key = rspamd_http_connection_make_peer_key (b32_key->str);
  225. g_assert (peer_key != NULL);
  226. total_diff = 0.0;
  227. for (i = 0; i < ntests; i ++) {
  228. for (j = 0; j < pconns; j ++) {
  229. rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, &addr,
  230. client_key, peer_key, c, ev_base, &latency[i * pconns + j]);
  231. }
  232. ts1 = rspamd_get_ticks ();
  233. event_base_loop (ev_base, 0);
  234. ts2 = rspamd_get_ticks ();
  235. diff = (ts2 - ts1) * 1000.0;
  236. total_diff += diff;
  237. }
  238. msg_info ("Made %d encrypted connections of size %d in %.6f ms, %.6f cps",
  239. ntests * pconns,
  240. sizeof (buf) * file_blocks,
  241. total_diff, ntests * pconns / total_diff * 1000.);
  242. mean = rspamd_http_calculate_mean (latency, &std);
  243. msg_info ("Latency: %.6f ms mean, %.6f dev",
  244. mean, std);
  245. /* Restart server */
  246. kill (sfd, SIGTERM);
  247. wait (&i);
  248. sfd = fork ();
  249. g_assert (sfd != -1);
  250. if (sfd == 0) {
  251. rspamd_http_server_func ("/tmp/", &addr, mtx, serv_key, NULL);
  252. exit (EXIT_SUCCESS);
  253. }
  254. rspamd_mempool_lock_mutex (mtx);
  255. total_diff = 0.0;
  256. for (i = 0; i < ntests; i ++) {
  257. for (j = 0; j < pconns; j ++) {
  258. rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, &addr,
  259. client_key, peer_key, c, ev_base, &latency[i * pconns + j]);
  260. }
  261. ts1 = rspamd_get_ticks ();
  262. event_base_loop (ev_base, 0);
  263. ts2 = rspamd_get_ticks ();
  264. diff = (ts2 - ts1) * 1000.0;
  265. total_diff += diff;
  266. }
  267. msg_info ("Made %d uncached encrypted connections of size %d in %.6f ms, %.6f cps",
  268. ntests * pconns,
  269. sizeof (buf) * file_blocks,
  270. total_diff, ntests * pconns / total_diff * 1000.);
  271. mean = rspamd_http_calculate_mean (latency, &std);
  272. msg_info ("Latency: %.6f ms mean, %.6f dev",
  273. mean, std);
  274. close (fd);
  275. unlink (filepath);
  276. kill (sfd, SIGTERM);
  277. }