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 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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. struct timespec 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. clock_gettime (CLOCK_MONOTONIC, &ts);
  109. *(cb->lat) = (ts.tv_sec - cb->ts.tv_sec) * 1000. + /* Seconds */
  110. (ts.tv_nsec - cb->ts.tv_nsec) / 1000000.; /* Nanoseconds */
  111. close (conn->fd);
  112. rspamd_http_connection_unref (conn);
  113. g_free (cb);
  114. return 0;
  115. }
  116. static void
  117. rspamd_http_client_func (const gchar *path, rspamd_inet_addr_t *addr,
  118. gpointer kp, gpointer peer_kp, struct rspamd_keypair_cache *c,
  119. struct event_base *ev_base, double *latency)
  120. {
  121. struct rspamd_http_message *msg;
  122. struct rspamd_http_connection *conn;
  123. gchar urlbuf[PATH_MAX];
  124. struct client_cbdata *cb;
  125. gint fd;
  126. g_assert ((fd = rspamd_inet_address_connect (addr, SOCK_STREAM, TRUE)) != -1);
  127. conn = rspamd_http_connection_new (rspamd_client_body, rspamd_client_err,
  128. rspamd_client_finish, RSPAMD_HTTP_CLIENT_SIMPLE,
  129. RSPAMD_HTTP_CLIENT, c);
  130. rspamd_snprintf (urlbuf, sizeof (urlbuf), "http://127.0.0.1/%s", path);
  131. msg = rspamd_http_message_from_url (urlbuf);
  132. g_assert (conn != NULL && msg != NULL);
  133. if (kp != NULL) {
  134. g_assert (peer_kp != NULL);
  135. rspamd_http_connection_set_key (conn, kp);
  136. msg->peer_key = rspamd_http_connection_key_ref (peer_kp);
  137. }
  138. cb = g_malloc (sizeof (*cb));
  139. clock_gettime (CLOCK_MONOTONIC, &cb->ts);
  140. cb->lat = latency;
  141. rspamd_http_connection_write_message (conn, msg, NULL, NULL, cb,
  142. fd, NULL, ev_base);
  143. }
  144. static int
  145. cmpd (const void *p1, const void *p2)
  146. {
  147. const double *d1 = p1, *d2 = p2;
  148. return (*d1) - (*d2);
  149. }
  150. double
  151. rspamd_http_calculate_mean (double *lats, double *std)
  152. {
  153. gint i;
  154. gdouble mean = 0., dev = 0.;
  155. qsort (lats, ntests * pconns, sizeof (double), cmpd);
  156. for (i = 0; i < ntests * pconns; i ++) {
  157. mean += lats[i];
  158. }
  159. mean /= ntests * pconns;
  160. for (i = 0; i < ntests * pconns; i ++) {
  161. dev += (lats[i] - mean) * (lats[i] - mean);
  162. }
  163. dev /= ntests * pconns;
  164. *std = sqrt (dev);
  165. return mean;
  166. }
  167. void
  168. rspamd_http_test_func (void)
  169. {
  170. struct event_base *ev_base = event_init ();
  171. rspamd_mempool_t *pool = rspamd_mempool_new (rspamd_mempool_suggest_size ());
  172. gpointer serv_key, client_key, peer_key;
  173. struct rspamd_keypair_cache *c;
  174. rspamd_mempool_mutex_t *mtx;
  175. rspamd_inet_addr_t addr;
  176. struct timespec ts1, ts2;
  177. gchar filepath[PATH_MAX], buf[512];
  178. gint fd, i, j;
  179. pid_t sfd;
  180. GString *b32_key;
  181. double diff, total_diff = 0.0, latency[pconns * ntests], mean, std;
  182. rspamd_cryptobox_init ();
  183. rspamd_snprintf (filepath, sizeof (filepath), "/tmp/http-test-XXXXXX");
  184. g_assert ((fd = mkstemp (filepath)) != -1);
  185. for (i = 0; i < file_blocks; i ++) {
  186. memset (buf, 0, sizeof (buf));
  187. g_assert (write (fd, buf, sizeof (buf)) == sizeof (buf));
  188. }
  189. mtx = rspamd_mempool_get_mutex (pool);
  190. rspamd_parse_inet_address (&addr, "127.0.0.1");
  191. rspamd_inet_address_set_port (&addr, ottery_rand_range (30000) + 32768);
  192. serv_key = rspamd_http_connection_gen_key ();
  193. client_key = rspamd_http_connection_gen_key ();
  194. c = rspamd_keypair_cache_new (16);
  195. rspamd_mempool_lock_mutex (mtx);
  196. sfd = fork ();
  197. g_assert (sfd != -1);
  198. if (sfd == 0) {
  199. rspamd_http_server_func ("/tmp/", &addr, mtx, serv_key, c);
  200. exit (EXIT_SUCCESS);
  201. }
  202. rspamd_mempool_lock_mutex (mtx);
  203. /* Do client stuff */
  204. for (i = 0; i < ntests; i ++) {
  205. for (j = 0; j < pconns; j ++) {
  206. rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, &addr,
  207. NULL, NULL, c, ev_base, &latency[i * pconns + j]);
  208. }
  209. clock_gettime (CLOCK_MONOTONIC, &ts1);
  210. event_base_loop (ev_base, 0);
  211. clock_gettime (CLOCK_MONOTONIC, &ts2);
  212. diff = (ts2.tv_sec - ts1.tv_sec) * 1000. + /* Seconds */
  213. (ts2.tv_nsec - ts1.tv_nsec) / 1000000.; /* Nanoseconds */
  214. total_diff += diff;
  215. }
  216. msg_info ("Made %d connections of size %d in %.6f ms, %.6f cps",
  217. ntests * pconns,
  218. sizeof (buf) * file_blocks,
  219. total_diff, ntests * pconns / total_diff * 1000.);
  220. mean = rspamd_http_calculate_mean (latency, &std);
  221. msg_info ("Latency: %.6f ms mean, %.6f dev",
  222. mean, std);
  223. /* Now test encrypted */
  224. b32_key = rspamd_http_connection_print_key (serv_key,
  225. RSPAMD_KEYPAIR_PUBKEY|RSPAMD_KEYPAIR_BASE32);
  226. g_assert (b32_key != NULL);
  227. peer_key = rspamd_http_connection_make_peer_key (b32_key->str);
  228. g_assert (peer_key != NULL);
  229. total_diff = 0.0;
  230. for (i = 0; i < ntests; i ++) {
  231. for (j = 0; j < pconns; j ++) {
  232. rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, &addr,
  233. client_key, peer_key, c, ev_base, &latency[i * pconns + j]);
  234. }
  235. clock_gettime (CLOCK_MONOTONIC, &ts1);
  236. event_base_loop (ev_base, 0);
  237. clock_gettime (CLOCK_MONOTONIC, &ts2);
  238. diff = (ts2.tv_sec - ts1.tv_sec) * 1000. + /* Seconds */
  239. (ts2.tv_nsec - ts1.tv_nsec) / 1000000.; /* Nanoseconds */
  240. total_diff += diff;
  241. }
  242. msg_info ("Made %d encrypted connections of size %d in %.6f ms, %.6f cps",
  243. ntests * pconns,
  244. sizeof (buf) * file_blocks,
  245. total_diff, ntests * pconns / total_diff * 1000.);
  246. mean = rspamd_http_calculate_mean (latency, &std);
  247. msg_info ("Latency: %.6f ms mean, %.6f dev",
  248. mean, std);
  249. /* Restart server */
  250. kill (sfd, SIGTERM);
  251. wait (&i);
  252. sfd = fork ();
  253. g_assert (sfd != -1);
  254. if (sfd == 0) {
  255. rspamd_http_server_func ("/tmp/", &addr, mtx, serv_key, NULL);
  256. exit (EXIT_SUCCESS);
  257. }
  258. rspamd_mempool_lock_mutex (mtx);
  259. total_diff = 0.0;
  260. for (i = 0; i < ntests; i ++) {
  261. for (j = 0; j < pconns; j ++) {
  262. rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, &addr,
  263. client_key, peer_key, c, ev_base, &latency[i * pconns + j]);
  264. }
  265. clock_gettime (CLOCK_MONOTONIC, &ts1);
  266. event_base_loop (ev_base, 0);
  267. clock_gettime (CLOCK_MONOTONIC, &ts2);
  268. diff = (ts2.tv_sec - ts1.tv_sec) * 1000. + /* Seconds */
  269. (ts2.tv_nsec - ts1.tv_nsec) / 1000000.; /* Nanoseconds */
  270. total_diff += diff;
  271. }
  272. msg_info ("Made %d uncached encrypted connections of size %d in %.6f ms, %.6f cps",
  273. ntests * pconns,
  274. sizeof (buf) * file_blocks,
  275. total_diff, ntests * pconns / total_diff * 1000.);
  276. mean = rspamd_http_calculate_mean (latency, &std);
  277. msg_info ("Latency: %.6f ms mean, %.6f dev",
  278. mean, std);
  279. close (fd);
  280. unlink (filepath);
  281. kill (sfd, SIGTERM);
  282. }