Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

lua_cdb.c 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "lua_common.h"
  17. #include "cdb.h"
  18. #define CDB_REFRESH_TIME 60
  19. LUA_FUNCTION_DEF (cdb, create);
  20. LUA_FUNCTION_DEF (cdb, lookup);
  21. LUA_FUNCTION_DEF (cdb, get_name);
  22. LUA_FUNCTION_DEF (cdb, destroy);
  23. LUA_FUNCTION_DEF (cdb, build);
  24. LUA_FUNCTION_DEF (cdb_builder, add);
  25. LUA_FUNCTION_DEF (cdb_builder, finalize);
  26. LUA_FUNCTION_DEF (cdb_builder, dtor);
  27. static const struct luaL_reg cdblib_m[] = {
  28. LUA_INTERFACE_DEF (cdb, lookup),
  29. {"find", lua_cdb_lookup},
  30. LUA_INTERFACE_DEF (cdb, get_name),
  31. {"__tostring", rspamd_lua_class_tostring},
  32. {"__gc", lua_cdb_destroy},
  33. {NULL, NULL}
  34. };
  35. static const struct luaL_reg cdbbuilderlib_m[] = {
  36. LUA_INTERFACE_DEF (cdb_builder, add),
  37. LUA_INTERFACE_DEF (cdb_builder, finalize),
  38. {"__tostring", rspamd_lua_class_tostring},
  39. {"__gc", lua_cdb_builder_dtor},
  40. {NULL, NULL}
  41. };
  42. static const struct luaL_reg cdblib_f[] = {
  43. LUA_INTERFACE_DEF (cdb, create),
  44. {"open", lua_cdb_create},
  45. {"build", lua_cdb_build},
  46. {NULL, NULL}
  47. };
  48. static struct cdb *
  49. lua_check_cdb (lua_State * L, int pos)
  50. {
  51. void *ud = rspamd_lua_check_udata (L, pos, "rspamd{cdb}");
  52. luaL_argcheck (L, ud != NULL, pos, "'cdb' expected");
  53. return ud ? *((struct cdb **)ud) : NULL;
  54. }
  55. static struct cdb_make *
  56. lua_check_cdb_builder (lua_State * L, int pos)
  57. {
  58. void *ud = rspamd_lua_check_udata (L, pos, "rspamd{cdb_builder}");
  59. luaL_argcheck (L, ud != NULL, pos, "'cdb_builder' expected");
  60. return ud ? ((struct cdb_make *)ud) : NULL;
  61. }
  62. static gint
  63. lua_cdb_create (lua_State *L)
  64. {
  65. struct cdb *cdb, **pcdb;
  66. const gchar *filename;
  67. gint fd;
  68. struct ev_loop *ev_base = NULL;
  69. if (lua_type(L, 2) == LUA_TUSERDATA) {
  70. ev_base = lua_check_ev_base(L, 2);
  71. }
  72. filename = luaL_checkstring (L, 1);
  73. /* If file begins with cdb://, just skip it */
  74. if (g_ascii_strncasecmp (filename, "cdb://", sizeof ("cdb://") - 1) == 0) {
  75. filename += sizeof ("cdb://") - 1;
  76. }
  77. if ((fd = open (filename, O_RDONLY)) == -1) {
  78. msg_warn ("cannot open cdb: %s, %s", filename, strerror (errno));
  79. lua_pushnil (L);
  80. }
  81. else {
  82. cdb = g_malloc0 (sizeof (struct cdb));
  83. cdb->filename = g_strdup (filename);
  84. if (cdb_init (cdb, fd) == -1) {
  85. g_free (cdb->filename);
  86. g_free (cdb);
  87. msg_warn ("cannot open cdb: %s, %s", filename, strerror (errno));
  88. lua_pushnil (L);
  89. }
  90. else {
  91. #ifdef HAVE_READAHEAD
  92. struct stat st;
  93. /*
  94. * Do not readahead more than 100mb,
  95. * which is enough for the vast majority of the use cases
  96. */
  97. static const size_t max_readahead = 100 * 0x100000;
  98. if (fstat(cdb_fileno(cdb), &st) != 1) {
  99. /* Must always be true because cdb_init calls it as well */
  100. if (readahead(cdb_fileno(cdb), 0, MIN(max_readahead, st.st_size)) == -1) {
  101. msg_warn ("cannot readahead cdb: %s, %s", filename, strerror (errno));
  102. }
  103. }
  104. #endif
  105. if (ev_base) {
  106. cdb_add_timer(cdb, ev_base, CDB_REFRESH_TIME);
  107. }
  108. pcdb = lua_newuserdata (L, sizeof (struct cdb *));
  109. rspamd_lua_setclass (L, "rspamd{cdb}", -1);
  110. *pcdb = cdb;
  111. }
  112. }
  113. return 1;
  114. }
  115. static gint
  116. lua_cdb_get_name (lua_State *L)
  117. {
  118. struct cdb *cdb = lua_check_cdb (L, 1);
  119. if (!cdb) {
  120. lua_error (L);
  121. return 1;
  122. }
  123. lua_pushstring (L, cdb->filename);
  124. return 1;
  125. }
  126. static gint
  127. lua_cdb_lookup (lua_State *L)
  128. {
  129. struct cdb *cdb = lua_check_cdb (L, 1);
  130. gsize klen;
  131. const gchar *what = luaL_checklstring(L, 2, &klen);
  132. if (!cdb || what == NULL) {
  133. return lua_error (L);
  134. }
  135. if (cdb_find (cdb, what, klen) > 0) {
  136. /* Extract and push value to lua as string */
  137. lua_pushlstring (L, cdb_getdata (cdb), cdb_datalen (cdb));
  138. }
  139. else {
  140. lua_pushnil (L);
  141. }
  142. return 1;
  143. }
  144. static gint
  145. lua_cdb_destroy (lua_State *L)
  146. {
  147. struct cdb *cdb = lua_check_cdb (L, 1);
  148. if (cdb) {
  149. cdb_free (cdb);
  150. if (cdb->cdb_fd != -1) {
  151. (void) close(cdb->cdb_fd);
  152. }
  153. g_free (cdb->filename);
  154. g_free (cdb);
  155. }
  156. return 0;
  157. }
  158. static gint
  159. lua_cdb_build (lua_State *L)
  160. {
  161. const char *filename = luaL_checkstring (L, 1);
  162. int fd, mode = 00755;
  163. if (filename == NULL) {
  164. return luaL_error (L, "invalid arguments, filename expected");
  165. }
  166. /* If file begins with cdb://, just skip it */
  167. if (g_ascii_strncasecmp (filename, "cdb://", sizeof ("cdb://") - 1) == 0) {
  168. filename += sizeof ("cdb://") - 1;
  169. }
  170. if (lua_isnumber (L, 2)) {
  171. mode = lua_tointeger (L, 2);
  172. }
  173. fd = rspamd_file_xopen (filename, O_RDWR | O_CREAT | O_TRUNC, mode, 0);
  174. if (fd == -1) {
  175. lua_pushnil (L);
  176. lua_pushfstring (L, "cannot open cdb: %s, %s", filename, strerror (errno));
  177. return 2;
  178. }
  179. struct cdb_make *cdbm = lua_newuserdata (L, sizeof(struct cdb_make));
  180. g_assert (cdb_make_start(cdbm, fd) == 0);
  181. rspamd_lua_setclass (L, "rspamd{cdb_builder}", -1);
  182. return 1;
  183. }
  184. static gint
  185. lua_cdb_builder_add (lua_State *L)
  186. {
  187. struct cdb_make *cdbm = lua_check_cdb_builder(L, 1);
  188. gsize data_sz, key_sz;
  189. const char *key = lua_tolstring (L, 2, &key_sz);
  190. const char *data = lua_tolstring (L, 3, &data_sz);
  191. if (cdbm == NULL || key == NULL || data == NULL || cdbm->cdb_fd == -1) {
  192. return luaL_error(L, "invalid arguments");
  193. }
  194. if (cdb_make_add (cdbm, key, key_sz, data, data_sz) == -1) {
  195. lua_pushvalue(L, 1);
  196. lua_pushfstring(L, "cannot push value to cdb: %s", strerror(errno));
  197. return 2;
  198. }
  199. /* Allow chaining */
  200. lua_pushvalue(L, 1);
  201. return 1;
  202. }
  203. static gint
  204. lua_cdb_builder_finalize (lua_State *L)
  205. {
  206. struct cdb_make *cdbm = lua_check_cdb_builder(L, 1);
  207. if (cdbm == NULL || cdbm->cdb_fd == -1) {
  208. return luaL_error(L, "invalid arguments");
  209. }
  210. if (cdb_make_finish (cdbm) == -1) {
  211. lua_pushvalue(L, 1);
  212. lua_pushfstring(L, "cannot finish value to cdb: %s", strerror(errno));
  213. return 2;
  214. }
  215. close (cdbm->cdb_fd);
  216. cdbm->cdb_fd = -1; /* To distinguish finalized object */
  217. /* Allow chaining */
  218. lua_pushvalue (L, 1);
  219. return 1;
  220. }
  221. static gint
  222. lua_cdb_builder_dtor (lua_State *L)
  223. {
  224. struct cdb_make *cdbm = lua_check_cdb_builder(L, 1);
  225. if (cdbm == NULL) {
  226. return luaL_error(L, "invalid arguments");
  227. }
  228. if (cdbm->cdb_fd != -1) {
  229. cdb_make_finish (cdbm);
  230. close (cdbm->cdb_fd);
  231. cdbm->cdb_fd = -1; /* Finalized object */
  232. }
  233. return 0;
  234. }
  235. static gint
  236. lua_load_cdb (lua_State *L)
  237. {
  238. lua_newtable (L);
  239. luaL_register (L, NULL, cdblib_f);
  240. return 1;
  241. }
  242. void
  243. luaopen_cdb (lua_State * L)
  244. {
  245. rspamd_lua_new_class (L, "rspamd{cdb}", cdblib_m);
  246. lua_pop (L, 1);
  247. rspamd_lua_new_class (L, "rspamd{cdb_builder}", cdbbuilderlib_m);
  248. lua_pop (L, 1);
  249. rspamd_lua_add_preload (L, "rspamd_cdb", lua_load_cdb);
  250. }