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.

kvstorage_server.c 34KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247
  1. /* Copyright (c) 2010, 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 "kvstorage.h"
  25. #include "kvstorage_config.h"
  26. #include "kvstorage_server.h"
  27. #include "cfg_file.h"
  28. #include "cfg_xml.h"
  29. #include "main.h"
  30. #define ERROR_COMMON "ERROR" CRLF
  31. #define ERROR_UNKNOWN_COMMAND "CLIENT_ERROR unknown command" CRLF
  32. #define ERROR_NOT_STORED "NOT_STORED" CRLF
  33. #define ERROR_EXISTS "EXISTS" CRLF
  34. #define ERROR_NOT_FOUND "NOT_FOUND" CRLF
  35. #define ERROR_INVALID_KEYSTORAGE "CLIENT_ERROR storage does not exists" CRLF
  36. #define ERROR_REDIS_OK "+OK" CRLF
  37. static sig_atomic_t wanna_die = 0;
  38. static sig_atomic_t do_reopen_log = 0;
  39. static sig_atomic_t soft_wanna_die = 0;
  40. /* Logging functions */
  41. #define thr_err(...) do { \
  42. g_mutex_lock (thr->log_mtx); \
  43. rspamd_common_log_function(rspamd_main->logger, G_LOG_LEVEL_CRITICAL, __FUNCTION__, __VA_ARGS__); \
  44. g_mutex_unlock (thr->log_mtx); \
  45. } while (0)
  46. #define thr_warn(...) do { \
  47. g_mutex_lock (thr->log_mtx); \
  48. rspamd_common_log_function(rspamd_main->logger, G_LOG_LEVEL_WARNING, __FUNCTION__, __VA_ARGS__); \
  49. g_mutex_unlock (thr->log_mtx); \
  50. } while (0)
  51. #define thr_info(...) do { \
  52. g_mutex_lock (thr->log_mtx); \
  53. rspamd_common_log_function(rspamd_main->logger, G_LOG_LEVEL_INFO, __FUNCTION__, __VA_ARGS__); \
  54. g_mutex_unlock (thr->log_mtx); \
  55. } while (0)
  56. /* Init functions */
  57. gpointer init_keystorage (void);
  58. void start_keystorage (struct rspamd_worker *worker);
  59. worker_t keystorage_worker = {
  60. "keystorage", /* Name */
  61. init_keystorage, /* Init function */
  62. start_keystorage, /* Start function */
  63. TRUE, /* Has socket */
  64. FALSE, /* Non unique */
  65. TRUE, /* Non threaded */
  66. FALSE, /* Non killable */
  67. SOCK_STREAM /* TCP socket */
  68. };
  69. #ifndef HAVE_SA_SIGINFO
  70. static void
  71. sig_handler (gint signo)
  72. #else
  73. static void
  74. sig_handler (gint signo, siginfo_t *info, void *unused)
  75. #endif
  76. {
  77. switch (signo) {
  78. case SIGUSR1:
  79. do_reopen_log = 1;
  80. break;
  81. case SIGINT:
  82. case SIGTERM:
  83. wanna_die = 1;
  84. break;
  85. case SIGUSR2:
  86. soft_wanna_die = 1;
  87. break;
  88. }
  89. }
  90. gpointer
  91. init_keystorage (void)
  92. {
  93. struct kvstorage_worker_ctx *ctx;
  94. GQuark type;
  95. type = g_quark_try_string ("keystorage");
  96. ctx = g_malloc0 (sizeof (struct kvstorage_worker_ctx));
  97. ctx->pool = memory_pool_new (memory_pool_get_size ());
  98. /* Set default values */
  99. ctx->timeout_raw = 300000;
  100. register_worker_opt (type, "timeout", xml_handle_seconds, ctx,
  101. G_STRUCT_OFFSET (struct kvstorage_worker_ctx, timeout_raw));
  102. register_worker_opt (type, "redis", xml_handle_boolean, ctx,
  103. G_STRUCT_OFFSET (struct kvstorage_worker_ctx, is_redis));
  104. return ctx;
  105. }
  106. /* Make post-init configuration */
  107. static gboolean
  108. config_kvstorage_worker (struct rspamd_worker *worker)
  109. {
  110. struct kvstorage_worker_ctx *ctx = worker->ctx;
  111. /* Init timeval */
  112. msec_to_tv (ctx->timeout_raw, &ctx->io_timeout);
  113. return TRUE;
  114. }
  115. /*
  116. * Free kvstorage session
  117. */
  118. static void
  119. free_kvstorage_session (struct kvstorage_session *session)
  120. {
  121. rspamd_remove_dispatcher (session->dispather);
  122. memory_pool_delete (session->pool);
  123. close (session->sock);
  124. g_slice_free1 (sizeof (struct kvstorage_session), session);
  125. }
  126. /*
  127. * Parse kvstorage command
  128. */
  129. static gboolean
  130. parse_kvstorage_command (struct kvstorage_session *session, gchar *c, guint len)
  131. {
  132. if (len == 3) {
  133. /* Set or get command */
  134. if ((c[0] == 'g' || c[0] == 'G') &&
  135. (c[1] == 'e' || c[1] == 'E') &&
  136. (c[2] == 't' || c[2] == 'T')) {
  137. session->command = KVSTORAGE_CMD_GET;
  138. }
  139. else if ((c[0] == 's' || c[0] == 'S') &&
  140. (c[1] == 'e' || c[1] == 'E') &&
  141. (c[2] == 't' || c[2] == 'T')) {
  142. session->command = KVSTORAGE_CMD_SET;
  143. }
  144. else if ((c[0] == 'd' || c[0] == 'D') &&
  145. (c[1] == 'e' || c[1] == 'E') &&
  146. (c[2] == 'l' || c[2] == 'L')) {
  147. session->command = KVSTORAGE_CMD_DELETE;
  148. }
  149. else {
  150. /* Error */
  151. return FALSE;
  152. }
  153. }
  154. else if (len == 4) {
  155. if ((c[0] == 'i' || c[0] == 'I') &&
  156. (c[1] == 'n' || c[1] == 'N') &&
  157. (c[2] == 'c' || c[2] == 'C') &&
  158. (c[3] == 'r' || c[3] == 'R')) {
  159. session->command = KVSTORAGE_CMD_INCR;
  160. session->arg_data.value = 1;
  161. }
  162. else if ((c[0] == 'd' || c[0] == 'D') &&
  163. (c[1] == 'e' || c[1] == 'E') &&
  164. (c[2] == 'c' || c[2] == 'C') &&
  165. (c[3] == 'r' || c[3] == 'R')) {
  166. session->command = KVSTORAGE_CMD_DECR;
  167. session->arg_data.value = -1;
  168. }
  169. else if (g_ascii_strncasecmp (c, "quit", 4) == 0) {
  170. session->command = KVSTORAGE_CMD_QUIT;
  171. }
  172. else if (g_ascii_strncasecmp (c, "sync", 4) == 0 || g_ascii_strncasecmp (c, "save", 4) == 0) {
  173. session->command = KVSTORAGE_CMD_SYNC;
  174. }
  175. }
  176. else if (len == 6) {
  177. if ((c[0] == 'i' || c[0] == 'I') &&
  178. (c[1] == 'n' || c[1] == 'N') &&
  179. (c[2] == 'c' || c[2] == 'C') &&
  180. (c[3] == 'r' || c[3] == 'R') &&
  181. (c[4] == 'b' || c[4] == 'B') &&
  182. (c[5] == 'y' || c[5] == 'Y')) {
  183. session->command = KVSTORAGE_CMD_INCR;
  184. session->arg_data.value = 1;
  185. }
  186. else if ((c[0] == 'd' || c[0] == 'D') &&
  187. (c[1] == 'e' || c[1] == 'E') &&
  188. (c[2] == 'c' || c[2] == 'C') &&
  189. (c[3] == 'r' || c[3] == 'R') &&
  190. (c[4] == 'b' || c[4] == 'B') &&
  191. (c[5] == 'y' || c[5] == 'Y')) {
  192. session->command = KVSTORAGE_CMD_DECR;
  193. session->arg_data.value = -1;
  194. }
  195. else if ((c[0] == 'd' || c[0] == 'D') &&
  196. (c[1] == 'e' || c[1] == 'E') &&
  197. (c[2] == 'l' || c[2] == 'L') &&
  198. (c[3] == 'e' || c[3] == 'E') &&
  199. (c[4] == 't' || c[4] == 'T') &&
  200. (c[5] == 'e' || c[5] == 'E')) {
  201. session->command = KVSTORAGE_CMD_DELETE;
  202. }
  203. else if (g_ascii_strncasecmp (c, "select", 6) == 0) {
  204. session->command = KVSTORAGE_CMD_SELECT;
  205. }
  206. else {
  207. return FALSE;
  208. }
  209. }
  210. return TRUE;
  211. }
  212. /**
  213. * Parse kvstorage line
  214. */
  215. static gboolean
  216. parse_kvstorage_line (struct kvstorage_session *session, f_str_t *in)
  217. {
  218. gchar *p, *c, *end;
  219. gint state = 0, next_state = 0;
  220. gboolean is_redis;
  221. p = in->begin;
  222. end = in->begin + in->len;
  223. c = p;
  224. is_redis = session->thr->ctx->is_redis;
  225. /* State machine for parsing */
  226. while (p <= end) {
  227. switch (state) {
  228. case 0:
  229. /* At this state we try to read identifier of storage */
  230. if (g_ascii_isdigit (*p)) {
  231. p ++;
  232. }
  233. else {
  234. if (g_ascii_isspace (*p) && p != c) {
  235. /* We have some digits, so parse id */
  236. session->id = strtoul (c, NULL, 10);
  237. state = 99;
  238. next_state = 1;
  239. }
  240. else if (c == p) {
  241. if (*p != '*') {
  242. /* We have some character, so assume id as 0 and parse command */
  243. session->id = 0;
  244. state = 1;
  245. }
  246. else {
  247. /* In fact it is redis number of commands */
  248. c = ++p;
  249. state = 7;
  250. session->id = 0;
  251. }
  252. }
  253. else {
  254. /* We have something wrong here (like some digits and then come non-digits) */
  255. return FALSE;
  256. }
  257. }
  258. break;
  259. case 1:
  260. /* At this state we parse command */
  261. if (g_ascii_isalpha (*p) && p != end) {
  262. p ++;
  263. }
  264. else {
  265. if (parse_kvstorage_command (session, c, p - c)) {
  266. switch (session->command) {
  267. case KVSTORAGE_CMD_QUIT:
  268. case KVSTORAGE_CMD_SYNC:
  269. /* Single argument command */
  270. state = 100;
  271. break;
  272. case KVSTORAGE_CMD_SELECT:
  273. /* Select command, read id next */
  274. state = 99;
  275. next_state = 6;
  276. break;
  277. default:
  278. /* Normal command, read key */
  279. state = 99;
  280. next_state = 2;
  281. }
  282. }
  283. else {
  284. /* Some error */
  285. return FALSE;
  286. }
  287. }
  288. break;
  289. case 2:
  290. /* Read and store key */
  291. if (!g_ascii_isspace (*p) && end != p) {
  292. p ++;
  293. }
  294. else {
  295. if (p == c) {
  296. return FALSE;
  297. }
  298. else {
  299. session->key = memory_pool_alloc (session->pool, p - c + 1);
  300. rspamd_strlcpy (session->key, c, p - c + 1);
  301. session->keylen = p - c;
  302. /* Now we must select next state based on command */
  303. if (session->command == KVSTORAGE_CMD_SET ||
  304. session->command == KVSTORAGE_CMD_INCR ||
  305. session->command == KVSTORAGE_CMD_DECR) {
  306. /* Read flags */
  307. state = 99;
  308. if (is_redis) {
  309. next_state = 5;
  310. session->flags = 0;
  311. session->expire = 0;
  312. }
  313. else {
  314. if (session->command == KVSTORAGE_CMD_SET) {
  315. next_state = 3;
  316. }
  317. else {
  318. next_state = 5;
  319. }
  320. }
  321. }
  322. else {
  323. /* Nothing to read for other commands */
  324. state = 100;
  325. }
  326. }
  327. }
  328. break;
  329. case 3:
  330. /* Read flags */
  331. if (g_ascii_isdigit (*p)) {
  332. p ++;
  333. }
  334. else {
  335. if (g_ascii_isspace (*p)) {
  336. session->flags = strtoul (c, NULL, 10);
  337. state = 99;
  338. if (session->command == KVSTORAGE_CMD_SET) {
  339. next_state = 4;
  340. }
  341. else {
  342. /* INCR and DECR */
  343. next_state = 5;
  344. }
  345. }
  346. else {
  347. return FALSE;
  348. }
  349. }
  350. break;
  351. case 4:
  352. /* Read exptime */
  353. if (g_ascii_isdigit (*p)) {
  354. p ++;
  355. }
  356. else {
  357. if (g_ascii_isspace (*p)) {
  358. session->expire = strtoul (c, NULL, 10);
  359. state = 99;
  360. next_state = 5;
  361. }
  362. else {
  363. return FALSE;
  364. }
  365. }
  366. break;
  367. case 5:
  368. /* Read size or incr/decr values */
  369. if (g_ascii_isdigit (*p)) {
  370. p ++;
  371. }
  372. else {
  373. if (g_ascii_isspace (*p) || p >= end - 1) {
  374. if (session->command == KVSTORAGE_CMD_SET) {
  375. session->arg_data.length = strtoul (c, NULL, 10);
  376. }
  377. else {
  378. if (p != c) {
  379. session->arg_data.value = strtoul (c, NULL, 10);
  380. if (session->command == KVSTORAGE_CMD_DECR) {
  381. session->arg_data.value = -session->arg_data.value;
  382. }
  383. }
  384. else if (session->command == KVSTORAGE_CMD_INCR) {
  385. session->arg_data.value = 1;
  386. }
  387. else {
  388. session->arg_data.value = -1;
  389. }
  390. }
  391. state = 100;
  392. }
  393. else {
  394. return FALSE;
  395. }
  396. }
  397. break;
  398. case 6:
  399. /* Read index of storage */
  400. if (g_ascii_isdigit (*p)) {
  401. p ++;
  402. }
  403. else {
  404. if (g_ascii_isspace (*p) || end == p) {
  405. session->id = strtoul (c, NULL, 10);
  406. state = 100;
  407. }
  408. else {
  409. return FALSE;
  410. }
  411. }
  412. break;
  413. case 7:
  414. /* Read arguments count */
  415. if (g_ascii_isdigit (*p)) {
  416. p ++;
  417. }
  418. else {
  419. if (g_ascii_isspace (*p) || end == p) {
  420. session->argc = strtoul (c, NULL, 10);
  421. session->argnum = 0;
  422. state = 100;
  423. /* Switch to arglen state */
  424. session->state = KVSTORAGE_STATE_READ_ARGLEN;
  425. }
  426. else {
  427. return FALSE;
  428. }
  429. }
  430. break;
  431. case 99:
  432. /* Skip spaces state */
  433. if (g_ascii_isspace (*p)) {
  434. p ++;
  435. }
  436. else {
  437. c = p;
  438. state = next_state;
  439. }
  440. break;
  441. case 100:
  442. /* Successful state */
  443. return TRUE;
  444. break;
  445. }
  446. }
  447. return state == 100;
  448. }
  449. /* Process normal kvstorage command */
  450. static gboolean
  451. kvstorage_process_command (struct kvstorage_session *session, gboolean is_redis)
  452. {
  453. gint r;
  454. gchar outbuf[BUFSIZ], intbuf[sizeof ("9223372036854775807")];
  455. gboolean res;
  456. struct rspamd_kv_element *elt;
  457. guint eltlen;
  458. glong longval;
  459. if (session->command == KVSTORAGE_CMD_SET) {
  460. session->state = KVSTORAGE_STATE_READ_DATA;
  461. rspamd_set_dispatcher_policy (session->dispather, BUFFER_CHARACTER, session->arg_data.length);
  462. }
  463. else if (session->command == KVSTORAGE_CMD_GET) {
  464. elt = rspamd_kv_storage_lookup (session->cf->storage, session->key, session->keylen, session->now);
  465. if (elt == NULL) {
  466. RW_R_UNLOCK (&session->cf->storage->rwlock);
  467. if (!is_redis) {
  468. return rspamd_dispatcher_write (session->dispather, ERROR_NOT_FOUND,
  469. sizeof (ERROR_NOT_FOUND) - 1, FALSE, TRUE);
  470. }
  471. else {
  472. return rspamd_dispatcher_write (session->dispather, "$-1" CRLF,
  473. sizeof ("$-1" CRLF) - 1, FALSE, TRUE);
  474. }
  475. }
  476. else {
  477. if (elt->flags & KV_ELT_INTEGER) {
  478. eltlen = rspamd_snprintf (intbuf, sizeof (intbuf), "%l", ELT_LONG (elt));
  479. }
  480. else {
  481. eltlen = elt->size;
  482. }
  483. if (!is_redis) {
  484. r = rspamd_snprintf (outbuf, sizeof (outbuf), "VALUE %s %ud %ud" CRLF,
  485. ELT_KEY (elt), elt->flags, eltlen);
  486. }
  487. else {
  488. r = rspamd_snprintf (outbuf, sizeof (outbuf), "$%ud" CRLF,
  489. eltlen);
  490. }
  491. if (!rspamd_dispatcher_write (session->dispather, outbuf,
  492. r, TRUE, FALSE)) {
  493. RW_R_UNLOCK (&session->cf->storage->rwlock);
  494. return FALSE;
  495. }
  496. if (elt->flags & KV_ELT_INTEGER) {
  497. if (!rspamd_dispatcher_write (session->dispather, intbuf, eltlen, TRUE, TRUE)) {
  498. RW_R_UNLOCK (&session->cf->storage->rwlock);
  499. return FALSE;
  500. }
  501. }
  502. else {
  503. if (!rspamd_dispatcher_write (session->dispather, ELT_DATA(elt), eltlen, TRUE, TRUE)) {
  504. RW_R_UNLOCK (&session->cf->storage->rwlock);
  505. return FALSE;
  506. }
  507. }
  508. session->elt = elt;
  509. if (!is_redis) {
  510. res = rspamd_dispatcher_write (session->dispather, CRLF "END" CRLF,
  511. sizeof (CRLF "END" CRLF) - 1, FALSE, TRUE);
  512. }
  513. else {
  514. res = rspamd_dispatcher_write (session->dispather, CRLF,
  515. sizeof (CRLF) - 1, FALSE, TRUE);
  516. }
  517. if (!res) {
  518. RW_R_UNLOCK (&session->cf->storage->rwlock);
  519. }
  520. return res;
  521. }
  522. }
  523. else if (session->command == KVSTORAGE_CMD_DELETE) {
  524. elt = rspamd_kv_storage_delete (session->cf->storage, session->key, session->keylen);
  525. if (elt != NULL) {
  526. if ((elt->flags & KV_ELT_DIRTY) == 0) {
  527. /* Free memory if backend has deleted this element */
  528. g_slice_free1 (ELT_SIZE (elt), elt);
  529. }
  530. if (!is_redis) {
  531. return rspamd_dispatcher_write (session->dispather, "DELETED" CRLF,
  532. sizeof ("DELETED" CRLF) - 1, FALSE, TRUE);
  533. }
  534. else {
  535. return rspamd_dispatcher_write (session->dispather, ":1" CRLF,
  536. sizeof (":1" CRLF) - 1, FALSE, TRUE);
  537. }
  538. }
  539. else {
  540. if (!is_redis) {
  541. return rspamd_dispatcher_write (session->dispather, ERROR_NOT_FOUND,
  542. sizeof (ERROR_NOT_FOUND) - 1, FALSE, TRUE);
  543. }
  544. else {
  545. return rspamd_dispatcher_write (session->dispather, ":0" CRLF,
  546. sizeof (":0" CRLF) - 1, FALSE, TRUE);
  547. }
  548. }
  549. }
  550. else if (session->command == KVSTORAGE_CMD_INCR || session->command == KVSTORAGE_CMD_DECR) {
  551. longval = session->arg_data.value;
  552. if (!rspamd_kv_storage_increment (session->cf->storage, session->key, session->keylen, &longval)) {
  553. if (!is_redis) {
  554. return rspamd_dispatcher_write (session->dispather, ERROR_NOT_FOUND,
  555. sizeof (ERROR_NOT_FOUND) - 1, FALSE, TRUE);
  556. }
  557. else {
  558. return rspamd_dispatcher_write (session->dispather, "-ERR not found" CRLF,
  559. sizeof ("-ERR not found" CRLF) - 1, FALSE, TRUE);
  560. }
  561. }
  562. else {
  563. if (!is_redis) {
  564. r = rspamd_snprintf (outbuf, sizeof (outbuf), "%l" CRLF,
  565. longval);
  566. }
  567. else {
  568. r = rspamd_snprintf (outbuf, sizeof (outbuf), ":%l" CRLF,
  569. longval);
  570. }
  571. if (!rspamd_dispatcher_write (session->dispather, outbuf,
  572. r, FALSE, FALSE)) {
  573. return FALSE;
  574. }
  575. }
  576. }
  577. else if (session->command == KVSTORAGE_CMD_SYNC) {
  578. if (session->cf->storage->backend == NULL || session->cf->storage->backend->sync_func == NULL) {
  579. if (!is_redis) {
  580. return rspamd_dispatcher_write (session->dispather, ERROR_COMMON,
  581. sizeof (ERROR_COMMON) - 1, FALSE, TRUE);
  582. }
  583. else {
  584. return rspamd_dispatcher_write (session->dispather, "-ERR unsupported" CRLF,
  585. sizeof ("-ERR unsupported" CRLF) - 1, FALSE, TRUE);
  586. }
  587. }
  588. else {
  589. if (session->cf->storage->backend->sync_func (session->cf->storage->backend)) {
  590. if (!is_redis) {
  591. return rspamd_dispatcher_write (session->dispather, "SYNCED" CRLF,
  592. sizeof ("SYNCED" CRLF) - 1, FALSE, TRUE);
  593. }
  594. else {
  595. return rspamd_dispatcher_write (session->dispather, "+OK" CRLF,
  596. sizeof ("+OK" CRLF) - 1, FALSE, TRUE);
  597. }
  598. }
  599. else {
  600. if (!is_redis) {
  601. return rspamd_dispatcher_write (session->dispather, "NOT_SYNCED" CRLF,
  602. sizeof ("NOT_SYNCED" CRLF) - 1, FALSE, TRUE);
  603. }
  604. else {
  605. return rspamd_dispatcher_write (session->dispather, "-ERR not synced" CRLF,
  606. sizeof ("-ERR not synced" CRLF) - 1, FALSE, TRUE);
  607. }
  608. }
  609. }
  610. }
  611. else if (session->command == KVSTORAGE_CMD_SELECT) {
  612. if (!is_redis) {
  613. return rspamd_dispatcher_write (session->dispather, "SELECTED" CRLF,
  614. sizeof ("SELECTED" CRLF) - 1, FALSE, TRUE);
  615. }
  616. else {
  617. return rspamd_dispatcher_write (session->dispather, "+OK" CRLF,
  618. sizeof ("+OK" CRLF) - 1, FALSE, TRUE);
  619. }
  620. }
  621. else if (session->command == KVSTORAGE_CMD_QUIT) {
  622. /* Quit session */
  623. free_kvstorage_session (session);
  624. return FALSE;
  625. }
  626. return TRUE;
  627. }
  628. static gboolean
  629. kvstorage_read_arglen (f_str_t *in, guint *len)
  630. {
  631. gchar *p = in->begin, *end = in->begin + in->len, *c;
  632. gint state = 0;
  633. c = p;
  634. while (p < end) {
  635. switch (state) {
  636. case 0:
  637. if (*p != '$') {
  638. return FALSE;
  639. }
  640. else {
  641. p ++;
  642. c = p;
  643. state = 1;
  644. }
  645. break;
  646. case 1:
  647. if (g_ascii_isdigit (*p) && p != end - 1) {
  648. p ++;
  649. }
  650. else {
  651. if (p != end - 1) {
  652. return FALSE;
  653. }
  654. else {
  655. *len = strtoul (c, NULL, 10);
  656. return TRUE;
  657. }
  658. }
  659. break;
  660. }
  661. }
  662. return TRUE;
  663. }
  664. /*
  665. * Check number of arguments for a command
  666. */
  667. static gboolean
  668. kvstorage_check_argnum (struct kvstorage_session *session)
  669. {
  670. switch (session->command) {
  671. case KVSTORAGE_CMD_QUIT:
  672. case KVSTORAGE_CMD_SYNC:
  673. return session->argc == 1;
  674. case KVSTORAGE_CMD_SET:
  675. return session->argc == 3 || session->argc == 4;
  676. case KVSTORAGE_CMD_INCR:
  677. case KVSTORAGE_CMD_DECR:
  678. return session->argc == 2 || session->argc == 3;
  679. default:
  680. return session->argc == 2;
  681. }
  682. /* Unreachable */
  683. return FALSE;
  684. }
  685. /**
  686. * Dispatcher callbacks
  687. */
  688. /*
  689. * Callback that is called when there is data to read in buffer
  690. */
  691. static gboolean
  692. kvstorage_read_socket (f_str_t * in, void *arg)
  693. {
  694. struct kvstorage_session *session = (struct kvstorage_session *) arg;
  695. struct kvstorage_worker_thread *thr;
  696. gint r;
  697. guint arglen = 0;
  698. gchar outbuf[BUFSIZ];
  699. gboolean is_redis;
  700. if (in->len == 0) {
  701. /* Skip empty commands */
  702. return TRUE;
  703. }
  704. thr = session->thr;
  705. is_redis = thr->ctx->is_redis;
  706. switch (session->state) {
  707. case KVSTORAGE_STATE_READ_CMD:
  708. /* Update timestamp */
  709. session->now = time (NULL);
  710. if (! parse_kvstorage_line (session, in)) {
  711. thr_info ("%ud: unknown command: %V", thr->id, in);
  712. if (!is_redis) {
  713. return rspamd_dispatcher_write (session->dispather, ERROR_UNKNOWN_COMMAND,
  714. sizeof (ERROR_UNKNOWN_COMMAND) - 1, FALSE, TRUE);
  715. }
  716. else {
  717. r = rspamd_snprintf (outbuf, sizeof (outbuf), "-ERR unknown command '%V'" CRLF, in);
  718. return rspamd_dispatcher_write (session->dispather, outbuf,
  719. r, FALSE, TRUE);
  720. }
  721. }
  722. else {
  723. session->cf = get_kvstorage_config (session->id);
  724. if (session->cf == NULL) {
  725. thr_info ("%ud: bad keystorage: %ud", thr->id, session->id);
  726. if (!is_redis) {
  727. return rspamd_dispatcher_write (session->dispather, ERROR_INVALID_KEYSTORAGE,
  728. sizeof (ERROR_INVALID_KEYSTORAGE) - 1, FALSE, TRUE);
  729. }
  730. else {
  731. return rspamd_dispatcher_write (session->dispather, "-ERR unknown keystorage" CRLF,
  732. sizeof ("-ERR unknown keystorage" CRLF) - 1, FALSE, TRUE);
  733. }
  734. }
  735. if (session->state != KVSTORAGE_STATE_READ_ARGLEN) {
  736. return kvstorage_process_command (session, is_redis);
  737. }
  738. }
  739. break;
  740. case KVSTORAGE_STATE_READ_ARGLEN:
  741. if (! kvstorage_read_arglen (in, &arglen)) {
  742. session->state = KVSTORAGE_STATE_READ_CMD;
  743. r = rspamd_snprintf (outbuf, sizeof (outbuf), "-ERR unknown arglen '%V'" CRLF, in);
  744. return rspamd_dispatcher_write (session->dispather, outbuf,
  745. r, FALSE, TRUE);
  746. }
  747. else {
  748. session->state = KVSTORAGE_STATE_READ_ARG;
  749. rspamd_set_dispatcher_policy (session->dispather, BUFFER_CHARACTER, arglen);
  750. }
  751. break;
  752. case KVSTORAGE_STATE_READ_ARG:
  753. if (session->argnum == 0) {
  754. /* Read command */
  755. if (! parse_kvstorage_command (session, in->begin, in->len)) {
  756. session->state = KVSTORAGE_STATE_READ_CMD;
  757. r = rspamd_snprintf (outbuf, sizeof (outbuf), "-ERR unknown command '%V'" CRLF, in);
  758. return rspamd_dispatcher_write (session->dispather, outbuf,
  759. r, FALSE, TRUE);
  760. }
  761. else {
  762. if (! kvstorage_check_argnum (session)) {
  763. session->state = KVSTORAGE_STATE_READ_CMD;
  764. r = rspamd_snprintf (outbuf, sizeof (outbuf), "-ERR invalid argnum for command '%V': %ud" CRLF,
  765. in, session->argc);
  766. return rspamd_dispatcher_write (session->dispather, outbuf,
  767. r, FALSE, TRUE);
  768. }
  769. else {
  770. if (session->argnum == session->argc - 1) {
  771. session->state = KVSTORAGE_STATE_READ_CMD;
  772. rspamd_set_dispatcher_policy (session->dispather, BUFFER_LINE, -1);
  773. return kvstorage_process_command (session, TRUE);
  774. }
  775. else {
  776. session->argnum ++;
  777. session->state = KVSTORAGE_STATE_READ_ARGLEN;
  778. rspamd_set_dispatcher_policy (session->dispather, BUFFER_LINE, -1);
  779. }
  780. }
  781. }
  782. }
  783. else if (session->argnum == 1) {
  784. if (session->command != KVSTORAGE_CMD_SELECT) {
  785. /* This argument is a key for normal command */
  786. session->key = memory_pool_fstrdup (session->pool, in);
  787. session->keylen = in->len;
  788. if (session->argnum == session->argc - 1) {
  789. session->state = KVSTORAGE_STATE_READ_CMD;
  790. rspamd_set_dispatcher_policy (session->dispather, BUFFER_LINE, -1);
  791. return kvstorage_process_command (session, TRUE);
  792. }
  793. else {
  794. session->argnum ++;
  795. session->state = KVSTORAGE_STATE_READ_ARGLEN;
  796. rspamd_set_dispatcher_policy (session->dispather, BUFFER_LINE, -1);
  797. }
  798. }
  799. else {
  800. /* Special case for select command */
  801. session->state = KVSTORAGE_STATE_READ_CMD;
  802. rspamd_strlcpy (outbuf, in->begin, MIN (sizeof (outbuf), in->len));
  803. session->id = strtoul (outbuf, NULL, 10);
  804. rspamd_set_dispatcher_policy (session->dispather, BUFFER_LINE, -1);
  805. return kvstorage_process_command (session, TRUE);
  806. }
  807. }
  808. else if (session->argnum == 2) {
  809. /* We get datablock for set command */
  810. if (session->command == KVSTORAGE_CMD_SET && session->argc == 3) {
  811. session->state = KVSTORAGE_STATE_READ_CMD;
  812. rspamd_set_dispatcher_policy (session->dispather, BUFFER_LINE, -1);
  813. if (rspamd_kv_storage_insert (session->cf->storage, session->key, session->keylen,
  814. in->begin, in->len,
  815. session->flags, session->expire)) {
  816. return rspamd_dispatcher_write (session->dispather, "+OK" CRLF,
  817. sizeof ("+OK" CRLF) - 1, FALSE, TRUE);
  818. }
  819. else {
  820. return rspamd_dispatcher_write (session->dispather, "-ERR not stored" CRLF,
  821. sizeof ("-ERR not stored" CRLF) - 1, FALSE, TRUE);
  822. }
  823. }
  824. else if (session->command == KVSTORAGE_CMD_SET && session->argc == 4) {
  825. /* It is expire argument */
  826. session->state = KVSTORAGE_STATE_READ_CMD;
  827. rspamd_strtol (in->begin, in->len, (glong *)&session->expire);
  828. session->argnum ++;
  829. session->state = KVSTORAGE_STATE_READ_ARGLEN;
  830. rspamd_set_dispatcher_policy (session->dispather, BUFFER_LINE, -1);
  831. }
  832. else {
  833. session->state = KVSTORAGE_STATE_READ_CMD;
  834. rspamd_strtol (in->begin, in->len, &session->arg_data.value);
  835. if (session->command == KVSTORAGE_CMD_DECR) {
  836. session->arg_data.value = -session->arg_data.value;
  837. }
  838. rspamd_set_dispatcher_policy (session->dispather, BUFFER_LINE, -1);
  839. return kvstorage_process_command (session, TRUE);
  840. }
  841. }
  842. else if (session->argnum == 3) {
  843. /* We get datablock for set command */
  844. if (session->command == KVSTORAGE_CMD_SET && session->argc == 4) {
  845. session->state = KVSTORAGE_STATE_READ_CMD;
  846. rspamd_set_dispatcher_policy (session->dispather, BUFFER_LINE, -1);
  847. if (rspamd_kv_storage_insert (session->cf->storage, session->key, session->keylen,
  848. in->begin, in->len,
  849. session->flags, session->expire)) {
  850. return rspamd_dispatcher_write (session->dispather, "+OK" CRLF,
  851. sizeof ("+OK" CRLF) - 1, FALSE, TRUE);
  852. }
  853. else {
  854. return rspamd_dispatcher_write (session->dispather, "-ERR not stored" CRLF,
  855. sizeof ("-ERR not stored" CRLF) - 1, FALSE, TRUE);
  856. }
  857. }
  858. }
  859. break;
  860. case KVSTORAGE_STATE_READ_DATA:
  861. session->state = KVSTORAGE_STATE_READ_CMD;
  862. rspamd_set_dispatcher_policy (session->dispather, BUFFER_LINE, -1);
  863. if (rspamd_kv_storage_insert (session->cf->storage, session->key, session->keylen,
  864. in->begin, in->len,
  865. session->flags, session->expire)) {
  866. if (!is_redis) {
  867. return rspamd_dispatcher_write (session->dispather, "STORED" CRLF,
  868. sizeof ("STORED" CRLF) - 1, FALSE, TRUE);
  869. }
  870. else {
  871. return rspamd_dispatcher_write (session->dispather, "+OK" CRLF,
  872. sizeof ("+OK" CRLF) - 1, FALSE, TRUE);
  873. }
  874. }
  875. else {
  876. if (!is_redis) {
  877. return rspamd_dispatcher_write (session->dispather, ERROR_NOT_STORED,
  878. sizeof (ERROR_NOT_STORED) - 1, FALSE, TRUE);
  879. }
  880. else {
  881. return rspamd_dispatcher_write (session->dispather, "-ERR not stored" CRLF,
  882. sizeof ("-ERR not stored" CRLF) - 1, FALSE, TRUE);
  883. }
  884. }
  885. break;
  886. }
  887. return TRUE;
  888. }
  889. /*
  890. * Called if buffers were written
  891. */
  892. static gboolean
  893. kvstorage_write_socket (void *arg)
  894. {
  895. struct kvstorage_session *session = (struct kvstorage_session *) arg;
  896. if (session->elt) {
  897. if ((session->elt->flags & KV_ELT_NEED_INSERT) != 0) {
  898. /* Insert to cache and free element */
  899. session->elt->flags &= ~KV_ELT_NEED_INSERT;
  900. RW_R_UNLOCK (&session->cf->storage->rwlock);
  901. rspamd_kv_storage_insert_cache (session->cf->storage, ELT_KEY (session->elt),
  902. session->elt->keylen, ELT_DATA (session->elt),
  903. session->elt->size, session->elt->flags,
  904. session->elt->expire, NULL);
  905. g_free (session->elt);
  906. session->elt = NULL;
  907. return TRUE;
  908. }
  909. RW_R_UNLOCK (&session->cf->storage->rwlock);
  910. session->elt = NULL;
  911. }
  912. return TRUE;
  913. }
  914. /*
  915. * Called if something goes wrong
  916. */
  917. static void
  918. kvstorage_err_socket (GError * err, void *arg)
  919. {
  920. struct kvstorage_session *session = (struct kvstorage_session *) arg;
  921. struct kvstorage_worker_thread *thr;
  922. thr = session->thr;
  923. if (err->code != -1) {
  924. thr_info ("%ud: abnormally closing connection from: %s, error: %s",
  925. thr->id, inet_ntoa (session->client_addr), err->message);
  926. }
  927. if (session->elt) {
  928. RW_R_UNLOCK (&session->cf->storage->rwlock);
  929. session->elt = NULL;
  930. }
  931. g_error_free (err);
  932. free_kvstorage_session (session);
  933. }
  934. /**
  935. * Accept function
  936. */
  937. static void
  938. thr_accept_socket (gint fd, short what, void *arg)
  939. {
  940. struct kvstorage_worker_thread *thr = (struct kvstorage_worker_thread *)arg;
  941. union sa_union su;
  942. socklen_t addrlen = sizeof (su.ss);
  943. gint nfd;
  944. struct kvstorage_session *session;
  945. g_mutex_lock (thr->accept_mtx);
  946. if ((nfd = accept_from_socket (fd, (struct sockaddr *)&su.ss, &addrlen)) == -1) {
  947. thr_warn ("%ud: accept failed: %s", thr->id, strerror (errno));
  948. g_mutex_unlock (thr->accept_mtx);
  949. return;
  950. }
  951. /* Check for EAGAIN */
  952. if (nfd == 0) {
  953. g_mutex_unlock (thr->accept_mtx);
  954. return;
  955. }
  956. session = g_slice_alloc0 (sizeof (struct kvstorage_session));
  957. session->pool = memory_pool_new (memory_pool_get_size ());
  958. session->state = KVSTORAGE_STATE_READ_CMD;
  959. session->thr = thr;
  960. session->sock = nfd;
  961. session->dispather = rspamd_create_dispatcher (thr->ev_base, nfd, BUFFER_LINE,
  962. kvstorage_read_socket, kvstorage_write_socket,
  963. kvstorage_err_socket, thr->tv, session);
  964. g_mutex_unlock (thr->accept_mtx);
  965. session->elt = NULL;
  966. if (su.ss.ss_family == AF_UNIX) {
  967. session->client_addr.s_addr = INADDR_NONE;
  968. }
  969. else if (su.ss.ss_family == AF_INET) {
  970. memcpy (&session->client_addr, &su.s4.sin_addr,
  971. sizeof (struct in_addr));
  972. }
  973. }
  974. /**
  975. * Handle termination
  976. */
  977. static void
  978. thr_term_socket (gint fd, short what, void *arg)
  979. {
  980. struct kvstorage_worker_thread *thr = (struct kvstorage_worker_thread *)arg;
  981. struct timeval tv;
  982. if (read (fd, &tv, sizeof (struct timeval)) != sizeof (struct timeval)) {
  983. thr_err ("cannot read data from socket: %s", strerror (errno));
  984. tv.tv_sec = 0;
  985. tv.tv_usec = 0;
  986. }
  987. event_base_loopexit (thr->ev_base, &tv);
  988. event_del (&thr->bind_ev);
  989. }
  990. /**
  991. * Thread main worker function
  992. */
  993. static gpointer
  994. kvstorage_thread (gpointer ud)
  995. {
  996. struct kvstorage_worker_thread *thr = ud;
  997. /* Block signals as it is dispatcher deity */
  998. sigprocmask (SIG_BLOCK, thr->signals, NULL);
  999. /* Init thread specific events */
  1000. thr->ev_base = event_init ();
  1001. event_set (&thr->bind_ev, thr->worker->cf->listen_sock, EV_READ | EV_PERSIST, thr_accept_socket, (void *)thr);
  1002. event_base_set (thr->ev_base, &thr->bind_ev);
  1003. event_add (&thr->bind_ev, NULL);
  1004. event_set (&thr->term_ev, thr->term_sock[0], EV_READ | EV_PERSIST, thr_term_socket, (void *)thr);
  1005. event_base_set (thr->ev_base, &thr->term_ev);
  1006. event_add (&thr->term_ev, NULL);
  1007. event_base_loop (thr->ev_base, 0);
  1008. return NULL;
  1009. }
  1010. /**
  1011. * Create new thread, set it detached
  1012. */
  1013. static struct kvstorage_worker_thread *
  1014. create_kvstorage_thread (struct rspamd_worker *worker, struct kvstorage_worker_ctx *ctx, guint id, sigset_t *signals)
  1015. {
  1016. struct kvstorage_worker_thread *new;
  1017. GError *err = NULL;
  1018. new = memory_pool_alloc (ctx->pool, sizeof (struct kvstorage_worker_thread));
  1019. new->ctx = ctx;
  1020. new->worker = worker;
  1021. new->tv = &ctx->io_timeout;
  1022. new->log_mtx = ctx->log_mtx;
  1023. new->accept_mtx = ctx->accept_mtx;
  1024. new->id = id;
  1025. /* Create and setup terminating socket */
  1026. if (make_socketpair (new->term_sock) == -1) {
  1027. msg_err ("socket failed: %s", strerror (errno));
  1028. return NULL;
  1029. }
  1030. make_socket_nonblocking (new->term_sock[0]);
  1031. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
  1032. new->thr = g_thread_create (kvstorage_thread, new, FALSE, &err);
  1033. #else
  1034. gchar *name;
  1035. name = memory_pool_alloc (ctx->pool, sizeof ("kvstorage_thread") + sizeof ("4294967296") - 1);
  1036. rspamd_snprintf (name, sizeof ("kvstorage_thread") + sizeof ("4294967296") - 1, "kvstorage_thread%d", id);
  1037. new->thr = g_thread_new (name, kvstorage_thread, new);
  1038. #endif
  1039. new->ev_base = NULL;
  1040. new->signals = signals;
  1041. if (new->thr == NULL) {
  1042. msg_err ("cannot create thread: %s", err->message);
  1043. }
  1044. return new;
  1045. }
  1046. /*
  1047. * Start worker process
  1048. */
  1049. void
  1050. start_keystorage (struct rspamd_worker *worker)
  1051. {
  1052. struct sigaction signals;
  1053. struct kvstorage_worker_ctx *ctx = worker->ctx;
  1054. guint i;
  1055. struct kvstorage_worker_thread *thr;
  1056. struct timeval tv;
  1057. GList *cur;
  1058. gperf_profiler_init (worker->srv->cfg, "kvstorage");
  1059. if (!g_thread_supported ()) {
  1060. msg_err ("threads support is not supported on your system so kvstorage is not functionable");
  1061. exit (EXIT_SUCCESS);
  1062. }
  1063. /* Create socketpair */
  1064. if (make_socketpair (ctx->s_pair) == -1) {
  1065. msg_err ("cannot create socketpair, exiting");
  1066. exit (EXIT_SUCCESS);
  1067. }
  1068. worker->srv->pid = getpid ();
  1069. ctx->threads = NULL;
  1070. #if _EVENT_NUMERIC_VERSION > 0x02000000
  1071. if (evthread_use_pthreads () == -1) {
  1072. msg_err ("threads support is not supported in your libevent so kvstorage is not functionable");
  1073. exit (EXIT_SUCCESS);
  1074. }
  1075. #endif
  1076. /* Set kvstorage options */
  1077. if ( !config_kvstorage_worker (worker)) {
  1078. msg_err ("cannot configure kvstorage worker, exiting");
  1079. exit (EXIT_SUCCESS);
  1080. }
  1081. init_signals (&signals, sig_handler);
  1082. /* Set umask */
  1083. umask (S_IWGRP | S_IWOTH | S_IROTH | S_IRGRP);
  1084. /* Init mutexes */
  1085. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
  1086. ctx->log_mtx = g_mutex_new ();
  1087. ctx->accept_mtx = g_mutex_new ();
  1088. #else
  1089. ctx->log_mtx = memory_pool_alloc (ctx->pool, sizeof (GMutex));
  1090. ctx->accept_mtx = memory_pool_alloc (ctx->pool, sizeof (GMutex));
  1091. g_mutex_init (ctx->log_mtx);
  1092. g_mutex_init (ctx->accept_mtx);
  1093. #endif
  1094. /* Start workers threads */
  1095. for (i = 0; i < worker->cf->count; i ++) {
  1096. thr = create_kvstorage_thread (worker, ctx, i, &signals.sa_mask);
  1097. if (thr != NULL) {
  1098. ctx->threads = g_list_prepend (ctx->threads, thr);
  1099. }
  1100. }
  1101. sigprocmask (SIG_BLOCK, &signals.sa_mask, NULL);
  1102. /* Signal processing cycle */
  1103. for (;;) {
  1104. msg_debug ("calling sigsuspend");
  1105. sigemptyset (&signals.sa_mask);
  1106. sigsuspend (&signals.sa_mask);
  1107. if (wanna_die == 1) {
  1108. wanna_die = 0;
  1109. tv.tv_sec = 0;
  1110. tv.tv_usec = 0;
  1111. msg_info ("worker's immediately shutdown is requested");
  1112. cur = ctx->threads;
  1113. while (cur) {
  1114. thr = cur->data;
  1115. while (write (thr->term_sock[1], &tv, sizeof (struct timeval)) == -1) {
  1116. if (errno != EAGAIN) {
  1117. msg_err ("write to term socket failed: %s", strerror (errno));
  1118. abort ();
  1119. }
  1120. }
  1121. cur = g_list_next (cur);
  1122. }
  1123. break;
  1124. }
  1125. else if (soft_wanna_die == 1) {
  1126. soft_wanna_die = 0;
  1127. tv.tv_sec = SOFT_SHUTDOWN_TIME;
  1128. tv.tv_usec = 0;
  1129. msg_info ("worker's shutdown is pending in %d sec", SOFT_SHUTDOWN_TIME);
  1130. cur = ctx->threads;
  1131. while (cur) {
  1132. thr = cur->data;
  1133. while (write (thr->term_sock[1], &tv, sizeof (struct timeval)) == -1) {
  1134. if (errno != EAGAIN) {
  1135. msg_err ("write to term socket failed: %s", strerror (errno));
  1136. abort ();
  1137. }
  1138. }
  1139. cur = g_list_next (cur);
  1140. }
  1141. break;
  1142. }
  1143. else if (do_reopen_log == 1) {
  1144. do_reopen_log = 0;
  1145. reopen_log (rspamd_main->logger);
  1146. }
  1147. }
  1148. msg_info ("syncing storages");
  1149. /* Wait for threads in the recent glib */
  1150. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
  1151. cur = ctx->threads;
  1152. while (cur) {
  1153. thr = cur->data;
  1154. (void)g_thread_join (thr->thr);
  1155. cur = g_list_next (cur);
  1156. }
  1157. #endif
  1158. destroy_kvstorage_config ();
  1159. close_log (rspamd_main->logger);
  1160. exit (EXIT_SUCCESS);
  1161. }