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.

lua_tcp.c 56KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428
  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 "lua_thread_pool.h"
  18. #include "libserver/ssl_util.h"
  19. #include "utlist.h"
  20. #include "unix-std.h"
  21. #include <math.h>
  22. static const gchar *M = "rspamd lua tcp";
  23. /***
  24. * @module rspamd_tcp
  25. * Rspamd TCP module represents generic TCP asynchronous client available from LUA code.
  26. * This module hides all complexity: DNS resolving, sessions management, zero-copy
  27. * text transfers and so on under the hood. It can work in partial or complete modes:
  28. *
  29. * - partial mode is used when you need to call a continuation routine each time data is available for read
  30. * - complete mode calls for continuation merely when all data is read from socket (e.g. when a server sends reply and closes a connection)
  31. * @example
  32. local logger = require "rspamd_logger"
  33. local tcp = require "rspamd_tcp"
  34. rspamd_config.SYM = function(task)
  35. local function cb(err, data)
  36. logger.infox('err: %1, data: %2', err, tostring(data))
  37. end
  38. tcp.request({
  39. task = task,
  40. host = "google.com",
  41. port = 80,
  42. data = {"GET / HTTP/1.0\r\n", "Host: google.com\r\n", "\r\n"},
  43. callback = cb})
  44. end
  45. -- New TCP syntax test
  46. rspamd_config:register_symbol({
  47. name = 'TCP_TEST',
  48. type = "normal",
  49. callback = function(task)
  50. local logger = require "rspamd_logger"
  51. local function rcpt_done_cb(err, data, conn)
  52. logger.errx(task, 'RCPT: got reply: %s, error: %s', data, err)
  53. conn:close()
  54. end
  55. local function rcpt_cb(err, conn)
  56. logger.errx(task, 'written rcpt, error: %s', err)
  57. conn:add_read(rcpt_done_cb, '\r\n')
  58. end
  59. local function from_done_cb(err, data, conn)
  60. logger.errx(task, 'FROM: got reply: %s, error: %s', data, err)
  61. conn:add_write(rcpt_cb, 'RCPT TO: <test@yandex.ru>\r\n')
  62. end
  63. local function from_cb(err, conn)
  64. logger.errx(task, 'written from, error: %s', err)
  65. conn:add_read(from_done_cb, '\r\n')
  66. end
  67. local function hello_done_cb(err, data, conn)
  68. logger.errx(task, 'HELO: got reply: %s, error: %s', data, err)
  69. conn:add_write(from_cb, 'MAIL FROM: <>\r\n')
  70. end
  71. local function hello_cb(err, conn)
  72. logger.errx(task, 'written hello, error: %s', err)
  73. conn:add_read(hello_done_cb, '\r\n')
  74. end
  75. local function init_cb(err, data, conn)
  76. logger.errx(task, 'got reply: %s, error: %s', data, err)
  77. conn:add_write(hello_cb, 'HELO example.com\r\n')
  78. end
  79. tcp.request{
  80. task = task,
  81. callback = init_cb,
  82. stop_pattern = '\r\n',
  83. host = 'mx.yandex.ru',
  84. port = 25
  85. }
  86. end,
  87. priority = 10,
  88. })
  89. */
  90. LUA_FUNCTION_DEF (tcp, request);
  91. /***
  92. * @function rspamd_tcp.connect_sync()
  93. *
  94. * Creates pseudo-synchronous TCP connection.
  95. * Each method of the connection requiring IO, becames a yielding point,
  96. * i.e. current thread Lua thread is get suspended and resumes as soon as IO is done
  97. *
  98. * This class represents low-level API, using of "lua_tcp_sync" module is recommended.
  99. *
  100. * @example
  101. local rspamd_tcp = require "rspamd_tcp"
  102. local logger = require "rspamd_logger"
  103. local function http_simple_tcp_symbol(task)
  104. local err
  105. local is_ok, connection = rspamd_tcp.connect_sync {
  106. task = task,
  107. host = '127.0.0.1',
  108. timeout = 20,
  109. port = 18080,
  110. ssl = false, -- If SSL connection is needed
  111. ssl_verify = true, -- set to false if verify is not needed
  112. }
  113. is_ok, err = connection:write('GET /request_sync HTTP/1.1\r\nConnection: keep-alive\r\n\r\n')
  114. logger.errx(task, 'write %1, %2', is_ok, err)
  115. if not is_ok then
  116. logger.errx(task, 'write error: %1', err)
  117. end
  118. local data
  119. is_ok, data = connection:read_once();
  120. logger.errx(task, 'read_once: is_ok: %1, data: %2', is_ok, data)
  121. is_ok, err = connection:write("POST /request2 HTTP/1.1\r\n\r\n")
  122. logger.errx(task, 'write[2] %1, %2', is_ok, err)
  123. is_ok, data = connection:read_once();
  124. logger.errx(task, 'read_once[2]: is_ok %1, data: %2', is_ok, data)
  125. connection:close()
  126. end
  127. rspamd_config:register_symbol({
  128. name = 'SIMPLE_TCP_TEST',
  129. score = 1.0,
  130. callback = http_simple_tcp_symbol,
  131. no_squeeze = true
  132. })
  133. *
  134. */
  135. LUA_FUNCTION_DEF (tcp, connect_sync);
  136. /***
  137. * @method tcp:close()
  138. *
  139. * Closes TCP connection
  140. */
  141. LUA_FUNCTION_DEF (tcp, close);
  142. /***
  143. * @method tcp:add_read(callback, [pattern])
  144. *
  145. * Adds new read event to the tcp connection
  146. * @param {function} callback to be called when data is read
  147. * @param {string} pattern optional stop pattern
  148. */
  149. LUA_FUNCTION_DEF (tcp, add_read);
  150. /***
  151. * @method tcp:add_write(callback, data)
  152. *
  153. * Adds new write event to the tcp connection
  154. * @param {function} optional callback to be called when data is completely written
  155. * @param {table/string/text} data to send to a remote server
  156. */
  157. LUA_FUNCTION_DEF (tcp, add_write);
  158. /***
  159. * @method tcp:shift_callback()
  160. *
  161. * Shifts the current callback and go to the next one (if any)
  162. */
  163. LUA_FUNCTION_DEF (tcp, shift_callback);
  164. /***
  165. * @method tcp:starttls([no_verify])
  166. *
  167. * Starts tls connection
  168. * @param {boolean} no_verify used to skip ssl verification
  169. */
  170. LUA_FUNCTION_DEF (tcp, starttls);
  171. static const struct luaL_reg tcp_libf[] = {
  172. LUA_INTERFACE_DEF (tcp, request),
  173. {"new", lua_tcp_request},
  174. {"connect", lua_tcp_request},
  175. {"connect_sync", lua_tcp_connect_sync},
  176. {NULL, NULL}
  177. };
  178. static const struct luaL_reg tcp_libm[] = {
  179. LUA_INTERFACE_DEF (tcp, close),
  180. LUA_INTERFACE_DEF (tcp, add_read),
  181. LUA_INTERFACE_DEF (tcp, add_write),
  182. LUA_INTERFACE_DEF (tcp, shift_callback),
  183. LUA_INTERFACE_DEF (tcp, starttls),
  184. {"__tostring", rspamd_lua_class_tostring},
  185. {NULL, NULL}
  186. };
  187. /***
  188. * @method tcp:close()
  189. *
  190. * Closes TCP connection
  191. */
  192. LUA_FUNCTION_DEF (tcp_sync, close);
  193. /***
  194. * @method read_once()
  195. *
  196. * Performs one read operation. If syscall returned with EAGAIN/EINT,
  197. * restarts the operation, so it always returns either data or error.
  198. */
  199. LUA_FUNCTION_DEF (tcp_sync, read_once);
  200. /***
  201. * @method eof()
  202. *
  203. * True if last IO operation ended with EOF, i.e. endpoint closed connection
  204. */
  205. LUA_FUNCTION_DEF (tcp_sync, eof);
  206. /***
  207. * @method shutdown()
  208. *
  209. * Half-shutdown TCP connection
  210. */
  211. LUA_FUNCTION_DEF (tcp_sync, shutdown);
  212. /***
  213. * @method write()
  214. *
  215. * Writes data into the stream. If syscall returned with EAGAIN/EINT
  216. * restarts the operation. If performs write() until all the passed
  217. * data is written completely.
  218. */
  219. LUA_FUNCTION_DEF (tcp_sync, write);
  220. LUA_FUNCTION_DEF (tcp_sync, gc);
  221. static void lua_tcp_sync_session_dtor (gpointer ud);
  222. static const struct luaL_reg tcp_sync_libm[] = {
  223. LUA_INTERFACE_DEF (tcp_sync, close),
  224. LUA_INTERFACE_DEF (tcp_sync, read_once),
  225. LUA_INTERFACE_DEF (tcp_sync, write),
  226. LUA_INTERFACE_DEF (tcp_sync, eof),
  227. LUA_INTERFACE_DEF (tcp_sync, shutdown),
  228. {"__gc", lua_tcp_sync_gc},
  229. {"__tostring", rspamd_lua_class_tostring},
  230. {NULL, NULL}
  231. };
  232. struct lua_tcp_read_handler {
  233. gchar *stop_pattern;
  234. guint plen;
  235. gint cbref;
  236. };
  237. struct lua_tcp_write_handler {
  238. struct iovec *iov;
  239. guint iovlen;
  240. gint cbref;
  241. gsize pos;
  242. gsize total_bytes;
  243. };
  244. enum lua_tcp_handler_type {
  245. LUA_WANT_WRITE = 0,
  246. LUA_WANT_READ,
  247. LUA_WANT_CONNECT
  248. };
  249. struct lua_tcp_handler {
  250. union {
  251. struct lua_tcp_read_handler r;
  252. struct lua_tcp_write_handler w;
  253. } h;
  254. enum lua_tcp_handler_type type;
  255. };
  256. struct lua_tcp_dtor {
  257. rspamd_mempool_destruct_t dtor;
  258. void *data;
  259. struct lua_tcp_dtor *next;
  260. };
  261. #define LUA_TCP_FLAG_PARTIAL (1u << 0u)
  262. #define LUA_TCP_FLAG_SHUTDOWN (1u << 2u)
  263. #define LUA_TCP_FLAG_CONNECTED (1u << 3u)
  264. #define LUA_TCP_FLAG_FINISHED (1u << 4u)
  265. #define LUA_TCP_FLAG_SYNC (1u << 5u)
  266. #define LUA_TCP_FLAG_RESOLVED (1u << 6u)
  267. #define LUA_TCP_FLAG_SSL (1u << 7u)
  268. #define LUA_TCP_FLAG_SSL_NOVERIFY (1u << 8u)
  269. #undef TCP_DEBUG_REFS
  270. #ifdef TCP_DEBUG_REFS
  271. #define TCP_RETAIN(x) do { \
  272. msg_info ("retain ref %p, refcount: %d", (x), (x)->ref.refcount); \
  273. REF_RETAIN(x); \
  274. } while (0)
  275. #define TCP_RELEASE(x) do { \
  276. msg_info ("release ref %p, refcount: %d", (x), (x)->ref.refcount); \
  277. REF_RELEASE(x); \
  278. } while (0)
  279. #else
  280. #define TCP_RETAIN(x) REF_RETAIN(x)
  281. #define TCP_RELEASE(x) REF_RELEASE(x)
  282. #endif
  283. struct lua_tcp_cbdata {
  284. struct rspamd_async_session *session;
  285. struct rspamd_async_event *async_ev;
  286. struct ev_loop *event_loop;
  287. rspamd_inet_addr_t *addr;
  288. GByteArray *in;
  289. GQueue *handlers;
  290. gint fd;
  291. gint connect_cb;
  292. guint port;
  293. guint flags;
  294. gchar tag[7];
  295. struct rspamd_io_ev ev;
  296. struct lua_tcp_dtor *dtors;
  297. ref_entry_t ref;
  298. struct rspamd_task *task;
  299. struct rspamd_symcache_item *item;
  300. struct thread_entry *thread;
  301. struct rspamd_config *cfg;
  302. struct rspamd_ssl_connection *ssl_conn;
  303. gchar *hostname;
  304. gboolean eof;
  305. };
  306. #define IS_SYNC(c) (((c)->flags & LUA_TCP_FLAG_SYNC) != 0)
  307. #define msg_debug_tcp(...) rspamd_conditional_debug_fast (NULL, cbd->addr, \
  308. rspamd_lua_tcp_log_id, "lua_tcp", cbd->tag, \
  309. G_STRFUNC, \
  310. __VA_ARGS__)
  311. INIT_LOG_MODULE(lua_tcp)
  312. static void lua_tcp_handler (int fd, short what, gpointer ud);
  313. static void lua_tcp_plan_handler_event (struct lua_tcp_cbdata *cbd,
  314. gboolean can_read, gboolean can_write);
  315. static void lua_tcp_unregister_event (struct lua_tcp_cbdata *cbd);
  316. static void
  317. lua_tcp_void_finalyser (gpointer arg) {}
  318. static const gdouble default_tcp_timeout = 5.0;
  319. static struct rspamd_dns_resolver *
  320. lua_tcp_global_resolver (struct ev_loop *ev_base,
  321. struct rspamd_config *cfg)
  322. {
  323. static struct rspamd_dns_resolver *global_resolver;
  324. if (cfg && cfg->dns_resolver) {
  325. return cfg->dns_resolver;
  326. }
  327. if (global_resolver == NULL) {
  328. global_resolver = rspamd_dns_resolver_init (NULL, ev_base, cfg);
  329. }
  330. return global_resolver;
  331. }
  332. static gboolean
  333. lua_tcp_shift_handler (struct lua_tcp_cbdata *cbd)
  334. {
  335. struct lua_tcp_handler *hdl;
  336. hdl = g_queue_pop_head (cbd->handlers);
  337. if (hdl == NULL) {
  338. /* We are done */
  339. return FALSE;
  340. }
  341. if (hdl->type == LUA_WANT_READ) {
  342. msg_debug_tcp ("switch from read handler %d", hdl->h.r.cbref);
  343. if (hdl->h.r.cbref && hdl->h.r.cbref != -1) {
  344. luaL_unref (cbd->cfg->lua_state, LUA_REGISTRYINDEX, hdl->h.r.cbref);
  345. }
  346. if (hdl->h.r.stop_pattern) {
  347. g_free (hdl->h.r.stop_pattern);
  348. }
  349. }
  350. else if (hdl->type == LUA_WANT_WRITE) {
  351. msg_debug_tcp ("switch from write handler %d", hdl->h.r.cbref);
  352. if (hdl->h.w.cbref && hdl->h.w.cbref != -1) {
  353. luaL_unref (cbd->cfg->lua_state, LUA_REGISTRYINDEX, hdl->h.w.cbref);
  354. }
  355. if (hdl->h.w.iov) {
  356. g_free (hdl->h.w.iov);
  357. }
  358. }
  359. else {
  360. msg_debug_tcp ("removing connect handler");
  361. /* LUA_WANT_CONNECT: it doesn't allocate anything, nothing to do here */
  362. }
  363. g_free (hdl);
  364. return TRUE;
  365. }
  366. static void
  367. lua_tcp_fin (gpointer arg)
  368. {
  369. struct lua_tcp_cbdata *cbd = (struct lua_tcp_cbdata *)arg;
  370. struct lua_tcp_dtor *dtor, *dttmp;
  371. if (IS_SYNC (cbd) && cbd->task) {
  372. /*
  373. pointer is now becoming invalid, we should remove registered destructor,
  374. all the necessary steps are done here
  375. */
  376. rspamd_mempool_replace_destructor (cbd->task->task_pool,
  377. lua_tcp_sync_session_dtor, cbd, NULL);
  378. }
  379. msg_debug_tcp ("finishing TCP %s connection", IS_SYNC (cbd) ? "sync" : "async");
  380. if (cbd->connect_cb != -1) {
  381. luaL_unref (cbd->cfg->lua_state, LUA_REGISTRYINDEX, cbd->connect_cb);
  382. }
  383. if (cbd->ssl_conn) {
  384. /* TODO: postpone close in case ssl is used ! */
  385. rspamd_ssl_connection_free (cbd->ssl_conn);
  386. }
  387. if (cbd->fd != -1) {
  388. rspamd_ev_watcher_stop (cbd->event_loop, &cbd->ev);
  389. close (cbd->fd);
  390. cbd->fd = -1;
  391. }
  392. if (cbd->addr) {
  393. rspamd_inet_address_free (cbd->addr);
  394. }
  395. while (lua_tcp_shift_handler (cbd)) {}
  396. g_queue_free (cbd->handlers);
  397. LL_FOREACH_SAFE (cbd->dtors, dtor, dttmp) {
  398. dtor->dtor (dtor->data);
  399. g_free (dtor);
  400. }
  401. g_byte_array_unref (cbd->in);
  402. g_free (cbd->hostname);
  403. g_free (cbd);
  404. }
  405. static struct lua_tcp_cbdata *
  406. lua_check_tcp (lua_State *L, gint pos)
  407. {
  408. void *ud = rspamd_lua_check_udata (L, pos, "rspamd{tcp}");
  409. luaL_argcheck (L, ud != NULL, pos, "'tcp' expected");
  410. return ud ? *((struct lua_tcp_cbdata **)ud) : NULL;
  411. }
  412. static void
  413. lua_tcp_maybe_free (struct lua_tcp_cbdata *cbd)
  414. {
  415. if (IS_SYNC (cbd)) {
  416. /*
  417. * in this mode, we don't remove object, we only remove the event
  418. * Object is owned by lua and will be destroyed on __gc()
  419. */
  420. if (cbd->item) {
  421. rspamd_symcache_item_async_dec_check (cbd->task, cbd->item, M);
  422. cbd->item = NULL;
  423. }
  424. if (cbd->async_ev) {
  425. rspamd_session_remove_event (cbd->session, lua_tcp_void_finalyser, cbd);
  426. }
  427. cbd->async_ev = NULL;
  428. }
  429. else {
  430. if (cbd->item) {
  431. rspamd_symcache_item_async_dec_check (cbd->task, cbd->item, M);
  432. cbd->item = NULL;
  433. }
  434. if (cbd->async_ev) {
  435. rspamd_session_remove_event (cbd->session, lua_tcp_fin, cbd);
  436. }
  437. else {
  438. lua_tcp_fin (cbd);
  439. }
  440. }
  441. }
  442. #ifdef __GNUC__
  443. static void
  444. lua_tcp_push_error (struct lua_tcp_cbdata *cbd, gboolean is_fatal,
  445. const char *err, ...) __attribute__ ((format(printf, 3, 4)));
  446. #endif
  447. static void lua_tcp_resume_thread_error_argp (struct lua_tcp_cbdata *cbd, const gchar *error, va_list argp);
  448. static void
  449. lua_tcp_push_error (struct lua_tcp_cbdata *cbd, gboolean is_fatal,
  450. const char *err, ...)
  451. {
  452. va_list ap, ap_copy;
  453. struct lua_tcp_cbdata **pcbd;
  454. struct lua_tcp_handler *hdl;
  455. gint cbref, top;
  456. struct lua_callback_state cbs;
  457. lua_State *L;
  458. gboolean callback_called = FALSE;
  459. if (cbd->thread) {
  460. va_start (ap, err);
  461. lua_tcp_resume_thread_error_argp (cbd, err, ap);
  462. va_end (ap);
  463. return;
  464. }
  465. lua_thread_pool_prepare_callback (cbd->cfg->lua_thread_pool, &cbs);
  466. L = cbs.L;
  467. va_start (ap, err);
  468. for (;;) {
  469. hdl = g_queue_peek_head (cbd->handlers);
  470. if (hdl == NULL) {
  471. break;
  472. }
  473. if (hdl->type == LUA_WANT_READ) {
  474. cbref = hdl->h.r.cbref;
  475. }
  476. else {
  477. cbref = hdl->h.w.cbref;
  478. }
  479. if (cbref != -1) {
  480. top = lua_gettop (L);
  481. lua_rawgeti (L, LUA_REGISTRYINDEX, cbref);
  482. /* Error message */
  483. va_copy (ap_copy, ap);
  484. lua_pushvfstring (L, err, ap_copy);
  485. va_end (ap_copy);
  486. /* Body */
  487. lua_pushnil (L);
  488. /* Connection */
  489. pcbd = lua_newuserdata (L, sizeof (*pcbd));
  490. *pcbd = cbd;
  491. rspamd_lua_setclass (L, "rspamd{tcp}", -1);
  492. TCP_RETAIN (cbd);
  493. if (cbd->item) {
  494. rspamd_symcache_set_cur_item (cbd->task, cbd->item);
  495. }
  496. if (lua_pcall (L, 3, 0, 0) != 0) {
  497. msg_info ("callback call failed: %s", lua_tostring (L, -1));
  498. }
  499. lua_settop (L, top);
  500. TCP_RELEASE (cbd);
  501. callback_called = TRUE;
  502. }
  503. if (!is_fatal) {
  504. if (callback_called) {
  505. /* Stop on the first callback found */
  506. break;
  507. }
  508. else {
  509. /* Shift to another callback to inform about non fatal error */
  510. msg_debug_tcp ("non fatal error find matching callback");
  511. lua_tcp_shift_handler (cbd);
  512. continue;
  513. }
  514. }
  515. else {
  516. msg_debug_tcp ("fatal error rollback all handlers");
  517. lua_tcp_shift_handler (cbd);
  518. }
  519. }
  520. va_end (ap);
  521. lua_thread_pool_restore_callback (&cbs);
  522. }
  523. static void lua_tcp_resume_thread (struct lua_tcp_cbdata *cbd, const guint8 *str, gsize len);
  524. static void
  525. lua_tcp_push_data (struct lua_tcp_cbdata *cbd, const guint8 *str, gsize len)
  526. {
  527. struct rspamd_lua_text *t;
  528. struct lua_tcp_cbdata **pcbd;
  529. struct lua_tcp_handler *hdl;
  530. gint cbref, arg_cnt, top;
  531. struct lua_callback_state cbs;
  532. lua_State *L;
  533. if (cbd->thread) {
  534. lua_tcp_resume_thread (cbd, str, len);
  535. return;
  536. }
  537. lua_thread_pool_prepare_callback (cbd->cfg->lua_thread_pool, &cbs);
  538. L = cbs.L;
  539. hdl = g_queue_peek_head (cbd->handlers);
  540. g_assert (hdl != NULL);
  541. if (hdl->type == LUA_WANT_READ) {
  542. cbref = hdl->h.r.cbref;
  543. }
  544. else {
  545. cbref = hdl->h.w.cbref;
  546. }
  547. if (cbref != -1) {
  548. top = lua_gettop (L);
  549. lua_rawgeti (L, LUA_REGISTRYINDEX, cbref);
  550. /* Error */
  551. lua_pushnil (L);
  552. /* Body */
  553. if (hdl->type == LUA_WANT_READ) {
  554. t = lua_newuserdata (L, sizeof (*t));
  555. rspamd_lua_setclass (L, "rspamd{text}", -1);
  556. t->start = (const gchar *)str;
  557. t->len = len;
  558. t->flags = 0;
  559. arg_cnt = 3;
  560. }
  561. else {
  562. arg_cnt = 2;
  563. }
  564. /* Connection */
  565. pcbd = lua_newuserdata (L, sizeof (*pcbd));
  566. *pcbd = cbd;
  567. rspamd_lua_setclass (L, "rspamd{tcp}", -1);
  568. TCP_RETAIN (cbd);
  569. if (cbd->item) {
  570. rspamd_symcache_set_cur_item (cbd->task, cbd->item);
  571. }
  572. if (lua_pcall (L, arg_cnt, 0, 0) != 0) {
  573. msg_info ("callback call failed: %s", lua_tostring (L, -1));
  574. }
  575. lua_settop (L, top);
  576. TCP_RELEASE (cbd);
  577. }
  578. lua_thread_pool_restore_callback (&cbs);
  579. }
  580. static void
  581. lua_tcp_resume_thread_error_argp (struct lua_tcp_cbdata *cbd, const gchar *error, va_list argp)
  582. {
  583. struct thread_entry *thread = cbd->thread;
  584. lua_State *L = thread->lua_state;
  585. lua_pushboolean (L, FALSE);
  586. lua_pushvfstring (L, error, argp);
  587. lua_tcp_shift_handler (cbd);
  588. // lua_tcp_unregister_event (cbd);
  589. lua_thread_pool_set_running_entry (cbd->cfg->lua_thread_pool, cbd->thread);
  590. lua_thread_resume (thread, 2);
  591. TCP_RELEASE (cbd);
  592. }
  593. static void
  594. lua_tcp_resume_thread (struct lua_tcp_cbdata *cbd, const guint8 *str, gsize len)
  595. {
  596. /*
  597. * typical call returns:
  598. *
  599. * read:
  600. * error:
  601. * (nil, error message)
  602. * got data:
  603. * (true, data)
  604. * write/connect:
  605. * error:
  606. * (nil, error message)
  607. * wrote
  608. * (true)
  609. */
  610. lua_State *L = cbd->thread->lua_state;
  611. struct lua_tcp_handler *hdl;
  612. hdl = g_queue_peek_head (cbd->handlers);
  613. lua_pushboolean (L, TRUE);
  614. if (hdl->type == LUA_WANT_READ) {
  615. lua_pushlstring (L, str, len);
  616. }
  617. else {
  618. lua_pushnil (L);
  619. }
  620. lua_tcp_shift_handler (cbd);
  621. lua_thread_pool_set_running_entry (cbd->cfg->lua_thread_pool,
  622. cbd->thread);
  623. if (cbd->item) {
  624. rspamd_symcache_set_cur_item (cbd->task, cbd->item);
  625. }
  626. lua_thread_resume (cbd->thread, 2);
  627. TCP_RELEASE (cbd);
  628. }
  629. static void
  630. lua_tcp_plan_read (struct lua_tcp_cbdata *cbd)
  631. {
  632. rspamd_ev_watcher_reschedule (cbd->event_loop, &cbd->ev, EV_READ);
  633. }
  634. static void
  635. lua_tcp_connect_helper (struct lua_tcp_cbdata *cbd)
  636. {
  637. /* This is used for sync mode only */
  638. lua_State *L = cbd->thread->lua_state;
  639. struct lua_tcp_cbdata **pcbd;
  640. lua_pushboolean (L, TRUE);
  641. lua_thread_pool_set_running_entry (cbd->cfg->lua_thread_pool, cbd->thread);
  642. pcbd = lua_newuserdata (L, sizeof (*pcbd));
  643. *pcbd = cbd;
  644. rspamd_lua_setclass (L, "rspamd{tcp_sync}", -1);
  645. msg_debug_tcp ("tcp connected");
  646. lua_tcp_shift_handler (cbd);
  647. // lua_tcp_unregister_event (cbd);
  648. lua_thread_resume (cbd->thread, 2);
  649. TCP_RELEASE (cbd);
  650. }
  651. static void
  652. lua_tcp_write_helper (struct lua_tcp_cbdata *cbd)
  653. {
  654. struct iovec *start;
  655. guint niov, i;
  656. gint flags = 0;
  657. gsize remain;
  658. gssize r;
  659. struct iovec *cur_iov;
  660. struct lua_tcp_handler *hdl;
  661. struct lua_tcp_write_handler *wh;
  662. struct msghdr msg;
  663. hdl = g_queue_peek_head (cbd->handlers);
  664. g_assert (hdl != NULL && hdl->type == LUA_WANT_WRITE);
  665. wh = &hdl->h.w;
  666. if (wh->pos == wh->total_bytes) {
  667. goto call_finish_handler;
  668. }
  669. start = &wh->iov[0];
  670. niov = wh->iovlen;
  671. remain = wh->pos;
  672. /* We know that niov is small enough for that */
  673. if (niov < 1024) {
  674. cur_iov = g_alloca (niov * sizeof (struct iovec));
  675. }
  676. else {
  677. cur_iov = g_malloc0 (niov * sizeof (struct iovec));
  678. }
  679. memcpy (cur_iov, wh->iov, niov * sizeof (struct iovec));
  680. for (i = 0; i < wh->iovlen && remain > 0; i++) {
  681. /* Find out the first iov required */
  682. start = &cur_iov[i];
  683. if (start->iov_len <= remain) {
  684. remain -= start->iov_len;
  685. start = &cur_iov[i + 1];
  686. niov--;
  687. }
  688. else {
  689. start->iov_base = (void *)((char *)start->iov_base + remain);
  690. start->iov_len -= remain;
  691. remain = 0;
  692. }
  693. }
  694. memset (&msg, 0, sizeof (msg));
  695. msg.msg_iov = start;
  696. msg.msg_iovlen = MIN (IOV_MAX, niov);
  697. g_assert (niov > 0);
  698. #ifdef MSG_NOSIGNAL
  699. flags = MSG_NOSIGNAL;
  700. #endif
  701. msg_debug_tcp ("want write %d io vectors of %d", (int)msg.msg_iovlen,
  702. (int)niov);
  703. if (cbd->ssl_conn) {
  704. r = rspamd_ssl_writev (cbd->ssl_conn, msg.msg_iov, msg.msg_iovlen);
  705. }
  706. else {
  707. r = sendmsg (cbd->fd, &msg, flags);
  708. }
  709. if (niov >= 1024) {
  710. g_free (cur_iov);
  711. }
  712. if (r == -1) {
  713. if (!(cbd->ssl_conn)) {
  714. if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
  715. msg_debug_tcp ("got temporary failure, retry write");
  716. lua_tcp_plan_handler_event (cbd, TRUE, TRUE);
  717. return;
  718. }
  719. else {
  720. lua_tcp_push_error (cbd, TRUE,
  721. "IO write error while trying to write %d bytes: %s",
  722. (gint) remain, strerror (errno));
  723. msg_debug_tcp ("write error, terminate connection");
  724. TCP_RELEASE (cbd);
  725. }
  726. }
  727. return;
  728. }
  729. else {
  730. wh->pos += r;
  731. }
  732. msg_debug_tcp ("written %z bytes: %z/%z", r,
  733. wh->pos, wh->total_bytes);
  734. if (wh->pos >= wh->total_bytes) {
  735. goto call_finish_handler;
  736. }
  737. else {
  738. /* Want to write more */
  739. if (r > 0) {
  740. /* XXX: special case: we know that we want to write more data
  741. * than it is available in iov function.
  742. *
  743. * Hence, we need to check if we can write more at some point...
  744. */
  745. lua_tcp_write_helper (cbd);
  746. }
  747. }
  748. return;
  749. call_finish_handler:
  750. msg_debug_tcp ("finishing TCP write, calling TCP handler");
  751. if ((cbd->flags & LUA_TCP_FLAG_SHUTDOWN)) {
  752. /* Half close the connection */
  753. shutdown (cbd->fd, SHUT_WR);
  754. cbd->flags &= ~LUA_TCP_FLAG_SHUTDOWN;
  755. }
  756. lua_tcp_push_data (cbd, NULL, 0);
  757. if (!IS_SYNC (cbd)) {
  758. lua_tcp_shift_handler (cbd);
  759. lua_tcp_plan_handler_event (cbd, TRUE, TRUE);
  760. }
  761. }
  762. static gboolean
  763. lua_tcp_process_read_handler (struct lua_tcp_cbdata *cbd,
  764. struct lua_tcp_read_handler *rh, gboolean eof)
  765. {
  766. guint slen;
  767. goffset pos;
  768. if (rh->stop_pattern) {
  769. slen = rh->plen;
  770. if (cbd->in->len >= slen) {
  771. if ((pos = rspamd_substring_search (cbd->in->data, cbd->in->len,
  772. rh->stop_pattern, slen)) != -1) {
  773. msg_debug_tcp ("found TCP stop pattern");
  774. lua_tcp_push_data (cbd, cbd->in->data, pos);
  775. if (!IS_SYNC (cbd)) {
  776. lua_tcp_shift_handler (cbd);
  777. }
  778. if (pos + slen < cbd->in->len) {
  779. /* We have a leftover */
  780. memmove (cbd->in->data, cbd->in->data + pos + slen,
  781. cbd->in->len - (pos + slen));
  782. cbd->in->len = cbd->in->len - (pos + slen);
  783. }
  784. else {
  785. cbd->in->len = 0;
  786. }
  787. return TRUE;
  788. }
  789. else {
  790. /* Plan new read */
  791. msg_debug_tcp ("NOT found TCP stop pattern");
  792. if (!cbd->eof) {
  793. lua_tcp_plan_read (cbd);
  794. }
  795. else {
  796. /* Got session finished but no stop pattern */
  797. lua_tcp_push_error (cbd, TRUE,
  798. "IO read error: connection terminated");
  799. }
  800. }
  801. }
  802. }
  803. else {
  804. msg_debug_tcp ("read TCP partial data %d bytes", cbd->in->len);
  805. slen = cbd->in->len;
  806. /* we have eaten all the data, handler should not know that there is something */
  807. cbd->in->len = 0;
  808. lua_tcp_push_data (cbd, cbd->in->data, slen);
  809. if (!IS_SYNC (cbd)) {
  810. lua_tcp_shift_handler (cbd);
  811. }
  812. return TRUE;
  813. }
  814. return FALSE;
  815. }
  816. static void
  817. lua_tcp_process_read (struct lua_tcp_cbdata *cbd,
  818. guchar *in, gssize r)
  819. {
  820. struct lua_tcp_handler *hdl;
  821. struct lua_tcp_read_handler *rh;
  822. hdl = g_queue_peek_head (cbd->handlers);
  823. g_assert (hdl != NULL && hdl->type == LUA_WANT_READ);
  824. rh = &hdl->h.r;
  825. if (r > 0) {
  826. if (cbd->flags & LUA_TCP_FLAG_PARTIAL) {
  827. lua_tcp_push_data (cbd, in, r);
  828. /* Plan next event */
  829. lua_tcp_plan_read (cbd);
  830. }
  831. else {
  832. g_byte_array_append (cbd->in, in, r);
  833. if (!lua_tcp_process_read_handler (cbd, rh, FALSE)) {
  834. /* Plan more read */
  835. lua_tcp_plan_read (cbd);
  836. }
  837. else {
  838. /* Go towards the next handler */
  839. if (!IS_SYNC (cbd)) {
  840. lua_tcp_plan_handler_event (cbd, TRUE, TRUE);
  841. }
  842. }
  843. }
  844. }
  845. else if (r == 0) {
  846. /* EOF */
  847. cbd->eof = TRUE;
  848. if (cbd->in->len > 0) {
  849. /* We have some data to process */
  850. lua_tcp_process_read_handler (cbd, rh, TRUE);
  851. }
  852. else {
  853. lua_tcp_push_error (cbd, TRUE, "IO read error: connection terminated");
  854. }
  855. lua_tcp_plan_handler_event (cbd, FALSE, FALSE);
  856. }
  857. else {
  858. /* An error occurred */
  859. if (errno == EAGAIN || errno == EINTR) {
  860. /* Restart call */
  861. lua_tcp_plan_read (cbd);
  862. return;
  863. }
  864. /* Fatal error */
  865. cbd->eof = TRUE;
  866. if (cbd->in->len > 0) {
  867. /* We have some data to process */
  868. lua_tcp_process_read_handler (cbd, rh, TRUE);
  869. }
  870. else {
  871. lua_tcp_push_error (cbd, TRUE,
  872. "IO read error while trying to read data: %s",
  873. strerror (errno));
  874. }
  875. lua_tcp_plan_handler_event (cbd, FALSE, FALSE);
  876. }
  877. }
  878. static void
  879. lua_tcp_handler (int fd, short what, gpointer ud)
  880. {
  881. struct lua_tcp_cbdata *cbd = ud;
  882. guchar inbuf[8192];
  883. gssize r;
  884. gint so_error = 0;
  885. socklen_t so_len = sizeof (so_error);
  886. struct lua_callback_state cbs;
  887. lua_State *L;
  888. enum lua_tcp_handler_type event_type;
  889. TCP_RETAIN (cbd);
  890. msg_debug_tcp ("processed TCP event: %d", what);
  891. struct lua_tcp_handler *rh = g_queue_peek_head (cbd->handlers);
  892. event_type = rh->type;
  893. rspamd_ev_watcher_stop (cbd->event_loop, &cbd->ev);
  894. if (what == EV_READ) {
  895. if (cbd->ssl_conn) {
  896. r = rspamd_ssl_read (cbd->ssl_conn, inbuf, sizeof (inbuf));
  897. }
  898. else {
  899. r = read (cbd->fd, inbuf, sizeof (inbuf));
  900. }
  901. lua_tcp_process_read (cbd, inbuf, r);
  902. }
  903. else if (what == EV_WRITE) {
  904. if (!(cbd->flags & LUA_TCP_FLAG_CONNECTED)) {
  905. if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &so_error, &so_len) == -1) {
  906. lua_tcp_push_error (cbd, TRUE, "Cannot get socket error: %s",
  907. strerror (errno));
  908. TCP_RELEASE (cbd);
  909. goto out;
  910. }
  911. else if (so_error != 0) {
  912. lua_tcp_push_error (cbd, TRUE, "Socket error detected: %s",
  913. strerror (so_error));
  914. TCP_RELEASE (cbd);
  915. goto out;
  916. }
  917. else {
  918. cbd->flags |= LUA_TCP_FLAG_CONNECTED;
  919. if (cbd->connect_cb != -1) {
  920. struct lua_tcp_cbdata **pcbd;
  921. gint top;
  922. lua_thread_pool_prepare_callback (cbd->cfg->lua_thread_pool, &cbs);
  923. L = cbs.L;
  924. top = lua_gettop (L);
  925. lua_rawgeti (L, LUA_REGISTRYINDEX, cbd->connect_cb);
  926. pcbd = lua_newuserdata (L, sizeof (*pcbd));
  927. *pcbd = cbd;
  928. TCP_RETAIN (cbd);
  929. rspamd_lua_setclass (L, "rspamd{tcp}", -1);
  930. if (cbd->item) {
  931. rspamd_symcache_set_cur_item (cbd->task, cbd->item);
  932. }
  933. if (lua_pcall (L, 1, 0, 0) != 0) {
  934. msg_info ("callback call failed: %s", lua_tostring (L, -1));
  935. }
  936. lua_settop (L, top);
  937. TCP_RELEASE (cbd);
  938. lua_thread_pool_restore_callback (&cbs);
  939. }
  940. }
  941. }
  942. if (event_type == LUA_WANT_WRITE) {
  943. lua_tcp_write_helper (cbd);
  944. }
  945. else if (event_type == LUA_WANT_CONNECT) {
  946. lua_tcp_connect_helper (cbd);
  947. }
  948. else {
  949. g_assert_not_reached ();
  950. }
  951. }
  952. else {
  953. lua_tcp_push_error (cbd, TRUE, "IO timeout");
  954. TCP_RELEASE (cbd);
  955. }
  956. out:
  957. TCP_RELEASE (cbd);
  958. }
  959. static void
  960. lua_tcp_plan_handler_event (struct lua_tcp_cbdata *cbd, gboolean can_read,
  961. gboolean can_write)
  962. {
  963. struct lua_tcp_handler *hdl;
  964. hdl = g_queue_peek_head (cbd->handlers);
  965. if (hdl == NULL) {
  966. if (!(cbd->flags & LUA_TCP_FLAG_FINISHED)) {
  967. /* We are finished with a connection */
  968. msg_debug_tcp ("no handlers left, finish session");
  969. TCP_RELEASE (cbd);
  970. cbd->flags |= LUA_TCP_FLAG_FINISHED;
  971. }
  972. }
  973. else {
  974. if (hdl->type == LUA_WANT_READ) {
  975. /* We need to check if we have some leftover in the buffer */
  976. if (cbd->in->len > 0) {
  977. msg_debug_tcp ("process read buffer leftover");
  978. if (lua_tcp_process_read_handler (cbd, &hdl->h.r, FALSE)) {
  979. if (!IS_SYNC(cbd)) {
  980. /* We can go to the next handler */
  981. lua_tcp_plan_handler_event (cbd, can_read, can_write);
  982. }
  983. }
  984. }
  985. else {
  986. if (can_read) {
  987. /* We need to plan a new event */
  988. msg_debug_tcp ("plan new read");
  989. rspamd_ev_watcher_reschedule (cbd->event_loop, &cbd->ev,
  990. EV_READ);
  991. }
  992. else {
  993. /* Cannot read more */
  994. msg_debug_tcp ("cannot read more");
  995. lua_tcp_push_error (cbd, FALSE, "EOF, cannot read more data");
  996. if (!IS_SYNC (cbd)) {
  997. lua_tcp_shift_handler (cbd);
  998. lua_tcp_plan_handler_event (cbd, can_read, can_write);
  999. }
  1000. }
  1001. }
  1002. }
  1003. else if (hdl->type == LUA_WANT_WRITE) {
  1004. /*
  1005. * We need to plan write event if there is something in the
  1006. * write request
  1007. */
  1008. if (hdl->h.w.pos < hdl->h.w.total_bytes) {
  1009. msg_debug_tcp ("plan new write");
  1010. if (can_write) {
  1011. rspamd_ev_watcher_reschedule (cbd->event_loop, &cbd->ev,
  1012. EV_WRITE);
  1013. }
  1014. else {
  1015. /* Cannot write more */
  1016. lua_tcp_push_error (cbd, FALSE, "EOF, cannot write more data");
  1017. if (!IS_SYNC(cbd)) {
  1018. lua_tcp_shift_handler (cbd);
  1019. lua_tcp_plan_handler_event (cbd, can_read, can_write);
  1020. }
  1021. }
  1022. }
  1023. else {
  1024. /* We shouldn't have empty write handlers */
  1025. g_assert_not_reached ();
  1026. }
  1027. }
  1028. else { /* LUA_WANT_CONNECT */
  1029. msg_debug_tcp ("plan new connect");
  1030. rspamd_ev_watcher_reschedule (cbd->event_loop, &cbd->ev,
  1031. EV_WRITE);
  1032. }
  1033. }
  1034. }
  1035. static gboolean
  1036. lua_tcp_register_event (struct lua_tcp_cbdata *cbd)
  1037. {
  1038. if (cbd->session) {
  1039. event_finalizer_t fin = IS_SYNC (cbd) ? lua_tcp_void_finalyser : lua_tcp_fin;
  1040. cbd->async_ev = rspamd_session_add_event (cbd->session, fin, cbd, M);
  1041. if (!cbd->async_ev) {
  1042. return FALSE;
  1043. }
  1044. }
  1045. return TRUE;
  1046. }
  1047. static void
  1048. lua_tcp_register_watcher (struct lua_tcp_cbdata *cbd)
  1049. {
  1050. if (cbd->item) {
  1051. rspamd_symcache_item_async_inc (cbd->task, cbd->item, M);
  1052. }
  1053. }
  1054. static void
  1055. lua_tcp_ssl_on_error (gpointer ud, GError *err)
  1056. {
  1057. struct lua_tcp_cbdata *cbd = (struct lua_tcp_cbdata *)ud;
  1058. if (err) {
  1059. lua_tcp_push_error (cbd, TRUE, "ssl error: %s", err->message);
  1060. }
  1061. else {
  1062. lua_tcp_push_error (cbd, TRUE, "ssl error: unknown error");
  1063. }
  1064. TCP_RELEASE (cbd);
  1065. }
  1066. static gboolean
  1067. lua_tcp_make_connection (struct lua_tcp_cbdata *cbd)
  1068. {
  1069. int fd;
  1070. rspamd_inet_address_set_port (cbd->addr, cbd->port);
  1071. fd = rspamd_inet_address_connect (cbd->addr, SOCK_STREAM, TRUE);
  1072. if (fd == -1) {
  1073. if (cbd->session) {
  1074. rspamd_mempool_t *pool = rspamd_session_mempool (cbd->session);
  1075. msg_info_pool ("cannot connect to %s (%s): %s",
  1076. rspamd_inet_address_to_string (cbd->addr),
  1077. cbd->hostname,
  1078. strerror (errno));
  1079. }
  1080. else {
  1081. msg_info ("cannot connect to %s (%s): %s",
  1082. rspamd_inet_address_to_string (cbd->addr),
  1083. cbd->hostname,
  1084. strerror (errno));
  1085. }
  1086. return FALSE;
  1087. }
  1088. cbd->fd = fd;
  1089. #if 0
  1090. if (!(cbd->flags & LUA_TCP_FLAG_RESOLVED)) {
  1091. /* We come here without resolving, so we need to add a watcher */
  1092. lua_tcp_register_watcher (cbd);
  1093. }
  1094. else {
  1095. cbd->flags |= LUA_TCP_FLAG_RESOLVED;
  1096. }
  1097. #endif
  1098. if (cbd->flags & LUA_TCP_FLAG_SSL) {
  1099. gpointer ssl_ctx;
  1100. gboolean verify_peer;
  1101. if (cbd->flags & LUA_TCP_FLAG_SSL_NOVERIFY) {
  1102. ssl_ctx = cbd->cfg->libs_ctx->ssl_ctx_noverify;
  1103. verify_peer = FALSE;
  1104. }
  1105. else {
  1106. ssl_ctx = cbd->cfg->libs_ctx->ssl_ctx;
  1107. verify_peer = TRUE;
  1108. }
  1109. cbd->ssl_conn = rspamd_ssl_connection_new (ssl_ctx,
  1110. cbd->event_loop,
  1111. verify_peer,
  1112. cbd->tag);
  1113. if (!rspamd_ssl_connect_fd (cbd->ssl_conn, fd, cbd->hostname, &cbd->ev,
  1114. cbd->ev.timeout, lua_tcp_handler, lua_tcp_ssl_on_error, cbd)) {
  1115. lua_tcp_push_error (cbd, TRUE, "ssl connection failed: %s",
  1116. strerror (errno));
  1117. return FALSE;
  1118. }
  1119. else {
  1120. lua_tcp_register_event (cbd);
  1121. }
  1122. }
  1123. else {
  1124. rspamd_ev_watcher_init (&cbd->ev, cbd->fd, EV_WRITE,
  1125. lua_tcp_handler, cbd);
  1126. lua_tcp_register_event (cbd);
  1127. lua_tcp_plan_handler_event (cbd, TRUE, TRUE);
  1128. }
  1129. return TRUE;
  1130. }
  1131. static void
  1132. lua_tcp_dns_handler (struct rdns_reply *reply, gpointer ud)
  1133. {
  1134. struct lua_tcp_cbdata *cbd = (struct lua_tcp_cbdata *)ud;
  1135. const struct rdns_request_name *rn;
  1136. if (reply->code != RDNS_RC_NOERROR) {
  1137. rn = rdns_request_get_name (reply->request, NULL);
  1138. lua_tcp_push_error (cbd, TRUE, "unable to resolve host: %s",
  1139. rn->name);
  1140. TCP_RELEASE (cbd);
  1141. }
  1142. else {
  1143. /*
  1144. * We set this flag as it means that we have already registered the watcher
  1145. * when started DNS query
  1146. */
  1147. cbd->flags |= LUA_TCP_FLAG_RESOLVED;
  1148. if (reply->entries->type == RDNS_REQUEST_A) {
  1149. cbd->addr = rspamd_inet_address_new (AF_INET,
  1150. &reply->entries->content.a.addr);
  1151. }
  1152. else if (reply->entries->type == RDNS_REQUEST_AAAA) {
  1153. cbd->addr = rspamd_inet_address_new (AF_INET6,
  1154. &reply->entries->content.aaa.addr);
  1155. }
  1156. rspamd_inet_address_set_port (cbd->addr, cbd->port);
  1157. if (!lua_tcp_make_connection (cbd)) {
  1158. lua_tcp_push_error (cbd, TRUE, "unable to make connection to the host %s",
  1159. rspamd_inet_address_to_string (cbd->addr));
  1160. TCP_RELEASE (cbd);
  1161. }
  1162. }
  1163. }
  1164. static gboolean
  1165. lua_tcp_arg_toiovec (lua_State *L, gint pos, struct lua_tcp_cbdata *cbd,
  1166. struct iovec *vec)
  1167. {
  1168. struct rspamd_lua_text *t;
  1169. gsize len;
  1170. const gchar *str;
  1171. struct lua_tcp_dtor *dtor;
  1172. if (lua_type (L, pos) == LUA_TUSERDATA) {
  1173. t = lua_check_text (L, pos);
  1174. if (t) {
  1175. vec->iov_base = (void *)t->start;
  1176. vec->iov_len = t->len;
  1177. if (t->flags & RSPAMD_TEXT_FLAG_OWN) {
  1178. /* Steal ownership */
  1179. t->flags = 0;
  1180. dtor = g_malloc0 (sizeof (*dtor));
  1181. dtor->dtor = g_free;
  1182. dtor->data = (void *)t->start;
  1183. LL_PREPEND (cbd->dtors, dtor);
  1184. }
  1185. }
  1186. else {
  1187. msg_err ("bad userdata argument at position %d", pos);
  1188. return FALSE;
  1189. }
  1190. }
  1191. else if (lua_type (L, pos) == LUA_TSTRING) {
  1192. str = luaL_checklstring (L, pos, &len);
  1193. vec->iov_base = g_malloc (len);
  1194. dtor = g_malloc0 (sizeof (*dtor));
  1195. dtor->dtor = g_free;
  1196. dtor->data = vec->iov_base;
  1197. LL_PREPEND (cbd->dtors, dtor);
  1198. memcpy (vec->iov_base, str, len);
  1199. vec->iov_len = len;
  1200. }
  1201. else {
  1202. msg_err ("bad argument at position %d", pos);
  1203. return FALSE;
  1204. }
  1205. return TRUE;
  1206. }
  1207. /***
  1208. * @function rspamd_tcp.request({params})
  1209. * This function creates and sends TCP request to the specified host and port,
  1210. * resolves hostname (if needed) and invokes continuation callback upon data received
  1211. * from the remote peer. This function accepts table of arguments with the following
  1212. * attributes
  1213. *
  1214. * - `task`: rspamd task objects (implies `pool`, `session`, `ev_base` and `resolver` arguments)
  1215. * - `ev_base`: event base (if no task specified)
  1216. * - `resolver`: DNS resolver (no task)
  1217. * - `session`: events session (no task)
  1218. * - `host`: IP or name of the peer (required)
  1219. * - `port`: remote port to use
  1220. * - `data`: a table of strings or `rspamd_text` objects that contains data pieces
  1221. * - `callback`: continuation function (required)
  1222. * - `on_connect`: callback called on connection success
  1223. * - `timeout`: floating point value that specifies timeout for IO operations in **seconds**
  1224. * - `partial`: boolean flag that specifies that callback should be called on any data portion received
  1225. * - `stop_pattern`: stop reading on finding a certain pattern (e.g. \r\n.\r\n for smtp)
  1226. * - `shutdown`: half-close socket after writing (boolean: default false)
  1227. * - `read`: read response after sending request (boolean: default true)
  1228. * @return {boolean} true if request has been sent
  1229. */
  1230. static gint
  1231. lua_tcp_request (lua_State *L)
  1232. {
  1233. LUA_TRACE_POINT;
  1234. const gchar *host;
  1235. gchar *stop_pattern = NULL;
  1236. guint port;
  1237. gint cbref, tp, conn_cbref = -1;
  1238. gsize plen = 0;
  1239. struct ev_loop *event_loop = NULL;
  1240. struct lua_tcp_cbdata *cbd;
  1241. struct rspamd_dns_resolver *resolver = NULL;
  1242. struct rspamd_async_session *session = NULL;
  1243. struct rspamd_task *task = NULL;
  1244. struct rspamd_config *cfg = NULL;
  1245. struct iovec *iov = NULL;
  1246. guint niov = 0, total_out;
  1247. guint64 h;
  1248. gdouble timeout = default_tcp_timeout;
  1249. gboolean partial = FALSE, do_shutdown = FALSE, do_read = TRUE,
  1250. ssl = FALSE, ssl_noverify = FALSE;
  1251. if (lua_type (L, 1) == LUA_TTABLE) {
  1252. lua_pushstring (L, "host");
  1253. lua_gettable (L, -2);
  1254. host = luaL_checkstring (L, -1);
  1255. lua_pop (L, 1);
  1256. lua_pushstring (L, "port");
  1257. lua_gettable (L, -2);
  1258. if (lua_type (L, -1) == LUA_TNUMBER) {
  1259. port = lua_tointeger (L, -1);
  1260. }
  1261. else {
  1262. /* We assume that it is a unix socket */
  1263. port = 0;
  1264. }
  1265. lua_pop (L, 1);
  1266. lua_pushstring (L, "callback");
  1267. lua_gettable (L, -2);
  1268. if (host == NULL || lua_type (L, -1) != LUA_TFUNCTION) {
  1269. lua_pop (L, 1);
  1270. msg_err ("tcp request has bad params");
  1271. lua_pushboolean (L, FALSE);
  1272. return 1;
  1273. }
  1274. cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  1275. cbd = g_malloc0 (sizeof (*cbd));
  1276. lua_pushstring (L, "task");
  1277. lua_gettable (L, -2);
  1278. if (lua_type (L, -1) == LUA_TUSERDATA) {
  1279. task = lua_check_task (L, -1);
  1280. event_loop = task->event_loop;
  1281. resolver = task->resolver;
  1282. session = task->s;
  1283. cfg = task->cfg;
  1284. }
  1285. lua_pop (L, 1);
  1286. if (task == NULL) {
  1287. lua_pushstring (L, "ev_base");
  1288. lua_gettable (L, -2);
  1289. if (rspamd_lua_check_udata_maybe (L, -1, "rspamd{ev_base}")) {
  1290. event_loop = *(struct ev_loop **)lua_touserdata (L, -1);
  1291. }
  1292. else {
  1293. return luaL_error (L, "event loop is required");
  1294. }
  1295. lua_pop (L, 1);
  1296. lua_pushstring (L, "session");
  1297. lua_gettable (L, -2);
  1298. if (rspamd_lua_check_udata_maybe (L, -1, "rspamd{session}")) {
  1299. session = *(struct rspamd_async_session **)lua_touserdata (L, -1);
  1300. }
  1301. else {
  1302. session = NULL;
  1303. }
  1304. lua_pop (L, 1);
  1305. lua_pushstring (L, "config");
  1306. lua_gettable (L, -2);
  1307. if (rspamd_lua_check_udata_maybe (L, -1, "rspamd{config}")) {
  1308. cfg = *(struct rspamd_config **)lua_touserdata (L, -1);
  1309. }
  1310. else {
  1311. cfg = NULL;
  1312. }
  1313. lua_pop (L, 1);
  1314. lua_pushstring (L, "resolver");
  1315. lua_gettable (L, -2);
  1316. if (rspamd_lua_check_udata_maybe (L, -1, "rspamd{resolver}")) {
  1317. resolver = *(struct rspamd_dns_resolver **)lua_touserdata (L, -1);
  1318. }
  1319. else {
  1320. resolver = lua_tcp_global_resolver (event_loop, cfg);
  1321. }
  1322. lua_pop (L, 1);
  1323. }
  1324. lua_pushstring (L, "timeout");
  1325. lua_gettable (L, -2);
  1326. if (lua_type (L, -1) == LUA_TNUMBER) {
  1327. timeout = lua_tonumber (L, -1);
  1328. }
  1329. lua_pop (L, 1);
  1330. lua_pushstring (L, "stop_pattern");
  1331. lua_gettable (L, -2);
  1332. if (lua_type (L, -1) == LUA_TSTRING) {
  1333. const gchar *p;
  1334. p = lua_tolstring (L, -1, &plen);
  1335. if (p && plen > 0) {
  1336. stop_pattern = g_malloc (plen);
  1337. memcpy (stop_pattern, p, plen);
  1338. }
  1339. }
  1340. lua_pop (L, 1);
  1341. lua_pushstring (L, "partial");
  1342. lua_gettable (L, -2);
  1343. if (lua_type (L, -1) == LUA_TBOOLEAN) {
  1344. partial = lua_toboolean (L, -1);
  1345. }
  1346. lua_pop (L, 1);
  1347. lua_pushstring (L, "shutdown");
  1348. lua_gettable (L, -2);
  1349. if (lua_type (L, -1) == LUA_TBOOLEAN) {
  1350. do_shutdown = lua_toboolean (L, -1);
  1351. }
  1352. lua_pop (L, 1);
  1353. lua_pushstring (L, "read");
  1354. lua_gettable (L, -2);
  1355. if (lua_type (L, -1) == LUA_TBOOLEAN) {
  1356. do_read = lua_toboolean (L, -1);
  1357. }
  1358. lua_pop (L, 1);
  1359. lua_pushstring (L, "ssl");
  1360. lua_gettable (L, -2);
  1361. if (lua_type (L, -1) == LUA_TBOOLEAN) {
  1362. ssl = lua_toboolean (L, -1);
  1363. }
  1364. lua_pop (L, 1);
  1365. lua_pushstring (L, "ssl_noverify");
  1366. lua_gettable (L, -2);
  1367. if (lua_type (L, -1) == LUA_TBOOLEAN) {
  1368. ssl_noverify = lua_toboolean (L, -1);
  1369. lua_pop (L, 1);
  1370. }
  1371. else {
  1372. lua_pop (L, 1); /* Previous nil... */
  1373. /* Similar to lua http, meh... */
  1374. lua_pushstring (L, "no_ssl_verify");
  1375. lua_gettable (L, -2);
  1376. if (lua_type (L, -1) == LUA_TBOOLEAN) {
  1377. ssl_noverify = lua_toboolean (L, -1);
  1378. }
  1379. lua_pop (L, 1);
  1380. }
  1381. lua_pushstring (L, "on_connect");
  1382. lua_gettable (L, -2);
  1383. if (lua_type (L, -1) == LUA_TFUNCTION) {
  1384. conn_cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  1385. }
  1386. else {
  1387. lua_pop (L, 1);
  1388. }
  1389. lua_pushstring (L, "data");
  1390. lua_gettable (L, -2);
  1391. total_out = 0;
  1392. tp = lua_type (L, -1);
  1393. if (tp == LUA_TSTRING || tp == LUA_TUSERDATA) {
  1394. iov = g_malloc (sizeof (*iov));
  1395. niov = 1;
  1396. if (!lua_tcp_arg_toiovec (L, -1, cbd, iov)) {
  1397. lua_pop (L, 1);
  1398. msg_err ("tcp request has bad data argument");
  1399. lua_pushboolean (L, FALSE);
  1400. g_free (iov);
  1401. g_free (cbd);
  1402. return 1;
  1403. }
  1404. total_out = iov[0].iov_len;
  1405. }
  1406. else if (tp == LUA_TTABLE) {
  1407. /* Count parts */
  1408. lua_pushnil (L);
  1409. while (lua_next (L, -2) != 0) {
  1410. niov ++;
  1411. lua_pop (L, 1);
  1412. }
  1413. iov = g_malloc (sizeof (*iov) * niov);
  1414. lua_pushnil (L);
  1415. niov = 0;
  1416. while (lua_next (L, -2) != 0) {
  1417. if (!lua_tcp_arg_toiovec (L, -1, cbd, &iov[niov])) {
  1418. lua_pop (L, 2);
  1419. msg_err ("tcp request has bad data argument at pos %d", niov);
  1420. lua_pushboolean (L, FALSE);
  1421. g_free (iov);
  1422. g_free (cbd);
  1423. return 1;
  1424. }
  1425. total_out += iov[niov].iov_len;
  1426. niov ++;
  1427. lua_pop (L, 1);
  1428. }
  1429. }
  1430. lua_pop (L, 1);
  1431. }
  1432. else {
  1433. return luaL_error (L, "tcp request has bad params");
  1434. }
  1435. if (resolver == NULL && cfg == NULL && task == NULL) {
  1436. return luaL_error (L, "tcp request has bad params: one of "
  1437. "{resolver,task,config} should be set");
  1438. }
  1439. cbd->task = task;
  1440. if (task) {
  1441. cbd->item = rspamd_symcache_get_cur_item (task);
  1442. }
  1443. cbd->cfg = cfg;
  1444. h = rspamd_random_uint64_fast ();
  1445. rspamd_snprintf (cbd->tag, sizeof (cbd->tag), "%uxL", h);
  1446. cbd->handlers = g_queue_new ();
  1447. cbd->hostname = g_strdup (host);
  1448. if (total_out > 0) {
  1449. struct lua_tcp_handler *wh;
  1450. wh = g_malloc0 (sizeof (*wh));
  1451. wh->type = LUA_WANT_WRITE;
  1452. wh->h.w.iov = iov;
  1453. wh->h.w.iovlen = niov;
  1454. wh->h.w.total_bytes = total_out;
  1455. wh->h.w.pos = 0;
  1456. /* Cannot set write handler here */
  1457. wh->h.w.cbref = -1;
  1458. if (cbref != -1 && !do_read) {
  1459. /* We have write only callback */
  1460. wh->h.w.cbref = cbref;
  1461. }
  1462. else {
  1463. /* We have simple client callback */
  1464. wh->h.w.cbref = -1;
  1465. }
  1466. g_queue_push_tail (cbd->handlers, wh);
  1467. }
  1468. cbd->event_loop = event_loop;
  1469. cbd->fd = -1;
  1470. cbd->port = port;
  1471. cbd->ev.timeout = timeout;
  1472. if (ssl) {
  1473. cbd->flags |= LUA_TCP_FLAG_SSL;
  1474. if (ssl_noverify) {
  1475. cbd->flags |= LUA_TCP_FLAG_SSL_NOVERIFY;
  1476. }
  1477. }
  1478. if (do_read) {
  1479. cbd->in = g_byte_array_sized_new (8192);
  1480. }
  1481. else {
  1482. /* Save some space... */
  1483. cbd->in = g_byte_array_new ();
  1484. }
  1485. if (partial) {
  1486. cbd->flags |= LUA_TCP_FLAG_PARTIAL;
  1487. }
  1488. if (do_shutdown) {
  1489. cbd->flags |= LUA_TCP_FLAG_SHUTDOWN;
  1490. }
  1491. if (do_read) {
  1492. struct lua_tcp_handler *rh;
  1493. rh = g_malloc0 (sizeof (*rh));
  1494. rh->type = LUA_WANT_READ;
  1495. rh->h.r.cbref = cbref;
  1496. rh->h.r.stop_pattern = stop_pattern;
  1497. rh->h.r.plen = plen;
  1498. g_queue_push_tail (cbd->handlers, rh);
  1499. }
  1500. cbd->connect_cb = conn_cbref;
  1501. REF_INIT_RETAIN (cbd, lua_tcp_maybe_free);
  1502. if (session) {
  1503. cbd->session = session;
  1504. if (rspamd_session_blocked (session)) {
  1505. lua_tcp_push_error (cbd, TRUE, "async session is the blocked state");
  1506. TCP_RELEASE (cbd);
  1507. cbd->item = NULL; /* To avoid decrease with no watcher */
  1508. lua_pushboolean (L, FALSE);
  1509. return 1;
  1510. }
  1511. }
  1512. if (rspamd_parse_inet_address (&cbd->addr,
  1513. host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
  1514. rspamd_inet_address_set_port (cbd->addr, port);
  1515. /* Host is numeric IP, no need to resolve */
  1516. lua_tcp_register_watcher (cbd);
  1517. if (!lua_tcp_make_connection (cbd)) {
  1518. lua_tcp_push_error (cbd, TRUE, "cannot connect to the host: %s", host);
  1519. lua_pushboolean (L, FALSE);
  1520. /* No reset of the item as watcher has been registered */
  1521. TCP_RELEASE (cbd);
  1522. return 1;
  1523. }
  1524. }
  1525. else {
  1526. if (task == NULL) {
  1527. if (!rspamd_dns_resolver_request (resolver, session, NULL, lua_tcp_dns_handler, cbd,
  1528. RDNS_REQUEST_A, host)) {
  1529. lua_tcp_push_error (cbd, TRUE, "cannot resolve host: %s", host);
  1530. lua_pushboolean (L, FALSE);
  1531. cbd->item = NULL; /* To avoid decrease with no watcher */
  1532. TCP_RELEASE (cbd);
  1533. return 1;
  1534. }
  1535. else {
  1536. lua_tcp_register_watcher (cbd);
  1537. }
  1538. }
  1539. else {
  1540. if (!rspamd_dns_resolver_request_task (task, lua_tcp_dns_handler, cbd,
  1541. RDNS_REQUEST_A, host)) {
  1542. lua_tcp_push_error (cbd, TRUE, "cannot resolve host: %s", host);
  1543. lua_pushboolean (L, FALSE);
  1544. cbd->item = NULL; /* To avoid decrease with no watcher */
  1545. TCP_RELEASE (cbd);
  1546. return 1;
  1547. }
  1548. else {
  1549. lua_tcp_register_watcher (cbd);
  1550. }
  1551. }
  1552. }
  1553. lua_pushboolean (L, TRUE);
  1554. return 1;
  1555. }
  1556. /***
  1557. * @function rspamd_tcp.connect_sync({params})
  1558. * Creates new pseudo-synchronous connection to the specific address:port
  1559. *
  1560. * - `task`: rspamd task objects (implies `pool`, `session`, `ev_base` and `resolver` arguments)
  1561. * - `ev_base`: event base (if no task specified)
  1562. * - `resolver`: DNS resolver (no task)
  1563. * - `session`: events session (no task)
  1564. * - `config`: config (no task)
  1565. * - `host`: IP or name of the peer (required)
  1566. * - `port`: remote port to use
  1567. * - `timeout`: floating point value that specifies timeout for IO operations in **seconds**
  1568. * @return {boolean} true if request has been sent
  1569. */
  1570. static gint
  1571. lua_tcp_connect_sync (lua_State *L)
  1572. {
  1573. LUA_TRACE_POINT;
  1574. GError *err = NULL;
  1575. gint64 port = -1;
  1576. gdouble timeout = default_tcp_timeout;
  1577. const gchar *host = NULL;
  1578. gint ret;
  1579. guint64 h;
  1580. struct rspamd_task *task = NULL;
  1581. struct rspamd_async_session *session = NULL;
  1582. struct rspamd_dns_resolver *resolver = NULL;
  1583. struct rspamd_config *cfg = NULL;
  1584. struct ev_loop *ev_base = NULL;
  1585. struct lua_tcp_cbdata *cbd;
  1586. int arguments_validated = rspamd_lua_parse_table_arguments (L, 1, &err,
  1587. RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
  1588. "task=U{task};session=U{session};resolver=U{resolver};ev_base=U{ev_base};"
  1589. "*host=S;*port=I;timeout=D;config=U{config}",
  1590. &task, &session, &resolver, &ev_base,
  1591. &host, &port, &timeout, &cfg);
  1592. if (!arguments_validated) {
  1593. if (err) {
  1594. ret = luaL_error (L, "invalid arguments: %s", err->message);
  1595. g_error_free (err);
  1596. return ret;
  1597. }
  1598. return luaL_error (L, "invalid arguments");
  1599. }
  1600. if (0 > port || port > 65535) {
  1601. return luaL_error (L, "invalid port given (correct values: 1..65535)");
  1602. }
  1603. if (task == NULL && (cfg == NULL || ev_base == NULL || session == NULL)) {
  1604. return luaL_error (L, "invalid arguments: either task or config+ev_base+session should be set");
  1605. }
  1606. if (isnan (timeout)) {
  1607. /* rspamd_lua_parse_table_arguments() sets missing N field to zero */
  1608. timeout = default_tcp_timeout;
  1609. }
  1610. cbd = g_new0 (struct lua_tcp_cbdata, 1);
  1611. if (task) {
  1612. static const gchar hexdigests[16] = "0123456789abcdef";
  1613. cfg = task->cfg;
  1614. ev_base = task->event_loop;
  1615. session = task->s;
  1616. /* Make a readable tag */
  1617. memcpy (cbd->tag, task->task_pool->tag.uid, sizeof (cbd->tag) - 2);
  1618. cbd->tag[sizeof (cbd->tag) - 2] = hexdigests[GPOINTER_TO_INT (cbd) & 0xf];
  1619. cbd->tag[sizeof (cbd->tag) - 1] = 0;
  1620. }
  1621. else {
  1622. h = rspamd_random_uint64_fast ();
  1623. rspamd_snprintf (cbd->tag, sizeof (cbd->tag), "%uxL", h);
  1624. }
  1625. if (resolver == NULL) {
  1626. if (task) {
  1627. resolver = task->resolver;
  1628. }
  1629. else {
  1630. resolver = lua_tcp_global_resolver (ev_base, cfg);
  1631. }
  1632. }
  1633. cbd->task = task;
  1634. cbd->cfg = cfg;
  1635. cbd->thread = lua_thread_pool_get_running_entry (cfg->lua_thread_pool);
  1636. cbd->handlers = g_queue_new ();
  1637. cbd->event_loop = ev_base;
  1638. cbd->flags |= LUA_TCP_FLAG_SYNC;
  1639. cbd->fd = -1;
  1640. cbd->port = (guint16)port;
  1641. cbd->in = g_byte_array_new ();
  1642. cbd->connect_cb = -1;
  1643. REF_INIT_RETAIN (cbd, lua_tcp_maybe_free);
  1644. if (task) {
  1645. rspamd_mempool_add_destructor (task->task_pool, lua_tcp_sync_session_dtor, cbd);
  1646. }
  1647. struct lua_tcp_handler *wh;
  1648. wh = g_malloc0 (sizeof (*wh));
  1649. wh->type = LUA_WANT_CONNECT;
  1650. g_queue_push_tail (cbd->handlers, wh);
  1651. if (session) {
  1652. cbd->session = session;
  1653. if (rspamd_session_blocked (session)) {
  1654. TCP_RELEASE (cbd);
  1655. lua_pushboolean (L, FALSE);
  1656. lua_pushliteral (L, "Session is being destroyed, requests are not allowed");
  1657. return 2;
  1658. }
  1659. }
  1660. if (rspamd_parse_inet_address (&cbd->addr,
  1661. host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
  1662. rspamd_inet_address_set_port (cbd->addr, (guint16)port);
  1663. /* Host is numeric IP, no need to resolve */
  1664. if (!lua_tcp_make_connection (cbd)) {
  1665. lua_pushboolean (L, FALSE);
  1666. lua_pushliteral (L, "Failed to initiate connection");
  1667. TCP_RELEASE (cbd);
  1668. return 2;
  1669. }
  1670. }
  1671. else {
  1672. if (task == NULL) {
  1673. if (!rspamd_dns_resolver_request (resolver, session, NULL, lua_tcp_dns_handler, cbd,
  1674. RDNS_REQUEST_A, host)) {
  1675. lua_pushboolean (L, FALSE);
  1676. lua_pushliteral (L, "Failed to initiate dns request");
  1677. TCP_RELEASE (cbd);
  1678. return 2;
  1679. }
  1680. else {
  1681. lua_tcp_register_watcher (cbd);
  1682. }
  1683. }
  1684. else {
  1685. cbd->item = rspamd_symcache_get_cur_item (task);
  1686. if (!rspamd_dns_resolver_request_task (task, lua_tcp_dns_handler, cbd,
  1687. RDNS_REQUEST_A, host)) {
  1688. lua_pushboolean (L, FALSE);
  1689. lua_pushliteral (L, "Failed to initiate dns request");
  1690. TCP_RELEASE (cbd);
  1691. return 2;
  1692. }
  1693. else {
  1694. lua_tcp_register_watcher (cbd);
  1695. }
  1696. }
  1697. }
  1698. return lua_thread_yield (cbd->thread, 0);
  1699. }
  1700. static gint
  1701. lua_tcp_close (lua_State *L)
  1702. {
  1703. LUA_TRACE_POINT;
  1704. struct lua_tcp_cbdata *cbd = lua_check_tcp (L, 1);
  1705. if (cbd == NULL) {
  1706. return luaL_error (L, "invalid arguments");
  1707. }
  1708. cbd->flags |= LUA_TCP_FLAG_FINISHED;
  1709. TCP_RELEASE (cbd);
  1710. return 0;
  1711. }
  1712. static gint
  1713. lua_tcp_add_read (lua_State *L)
  1714. {
  1715. LUA_TRACE_POINT;
  1716. struct lua_tcp_cbdata *cbd = lua_check_tcp (L, 1);
  1717. struct lua_tcp_handler *rh;
  1718. gchar *stop_pattern = NULL;
  1719. const gchar *p;
  1720. gsize plen = 0;
  1721. gint cbref = -1;
  1722. if (cbd == NULL) {
  1723. return luaL_error (L, "invalid arguments");
  1724. }
  1725. if (lua_type (L, 2) == LUA_TFUNCTION) {
  1726. lua_pushvalue (L, 2);
  1727. cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  1728. }
  1729. if (lua_type (L, 3) == LUA_TSTRING) {
  1730. p = lua_tolstring (L, 3, &plen);
  1731. if (p && plen > 0) {
  1732. stop_pattern = g_malloc (plen);
  1733. memcpy (stop_pattern, p, plen);
  1734. }
  1735. }
  1736. rh = g_malloc0 (sizeof (*rh));
  1737. rh->type = LUA_WANT_READ;
  1738. rh->h.r.cbref = cbref;
  1739. rh->h.r.stop_pattern = stop_pattern;
  1740. rh->h.r.plen = plen;
  1741. msg_debug_tcp ("added read event, cbref: %d", cbref);
  1742. g_queue_push_tail (cbd->handlers, rh);
  1743. return 0;
  1744. }
  1745. static gint
  1746. lua_tcp_add_write (lua_State *L)
  1747. {
  1748. LUA_TRACE_POINT;
  1749. struct lua_tcp_cbdata *cbd = lua_check_tcp (L, 1);
  1750. struct lua_tcp_handler *wh;
  1751. gint cbref = -1, tp;
  1752. struct iovec *iov = NULL;
  1753. guint niov = 0, total_out = 0;
  1754. if (cbd == NULL) {
  1755. return luaL_error (L, "invalid arguments");
  1756. }
  1757. if (lua_type (L, 2) == LUA_TFUNCTION) {
  1758. lua_pushvalue (L, 2);
  1759. cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  1760. }
  1761. tp = lua_type (L, 3);
  1762. if (tp == LUA_TSTRING || tp == LUA_TUSERDATA) {
  1763. iov = g_malloc (sizeof (*iov));
  1764. niov = 1;
  1765. if (!lua_tcp_arg_toiovec (L, 3, cbd, iov)) {
  1766. msg_err ("tcp request has bad data argument");
  1767. lua_pushboolean (L, FALSE);
  1768. g_free (iov);
  1769. return 1;
  1770. }
  1771. total_out = iov[0].iov_len;
  1772. }
  1773. else if (tp == LUA_TTABLE) {
  1774. /* Count parts */
  1775. lua_pushvalue (L, 3);
  1776. lua_pushnil (L);
  1777. while (lua_next (L, -2) != 0) {
  1778. niov ++;
  1779. lua_pop (L, 1);
  1780. }
  1781. iov = g_malloc (sizeof (*iov) * niov);
  1782. lua_pushnil (L);
  1783. niov = 0;
  1784. while (lua_next (L, -2) != 0) {
  1785. if (!lua_tcp_arg_toiovec (L, -1, cbd, &iov[niov])) {
  1786. lua_pop (L, 2);
  1787. msg_err ("tcp request has bad data argument at pos %d", niov);
  1788. lua_pushboolean (L, FALSE);
  1789. g_free (iov);
  1790. g_free (cbd);
  1791. return 1;
  1792. }
  1793. total_out += iov[niov].iov_len;
  1794. niov ++;
  1795. lua_pop (L, 1);
  1796. }
  1797. lua_pop (L, 1);
  1798. }
  1799. wh = g_malloc0 (sizeof (*wh));
  1800. wh->type = LUA_WANT_WRITE;
  1801. wh->h.w.iov = iov;
  1802. wh->h.w.iovlen = niov;
  1803. wh->h.w.total_bytes = total_out;
  1804. wh->h.w.pos = 0;
  1805. /* Cannot set write handler here */
  1806. wh->h.w.cbref = cbref;
  1807. msg_debug_tcp ("added write event, cbref: %d", cbref);
  1808. g_queue_push_tail (cbd->handlers, wh);
  1809. lua_pushboolean (L, TRUE);
  1810. return 1;
  1811. }
  1812. static gint
  1813. lua_tcp_shift_callback (lua_State *L)
  1814. {
  1815. LUA_TRACE_POINT;
  1816. struct lua_tcp_cbdata *cbd = lua_check_tcp (L, 1);
  1817. if (cbd == NULL) {
  1818. return luaL_error (L, "invalid arguments");
  1819. }
  1820. lua_tcp_shift_handler (cbd);
  1821. lua_tcp_plan_handler_event (cbd, TRUE, TRUE);
  1822. return 0;
  1823. }
  1824. static struct lua_tcp_cbdata *
  1825. lua_check_sync_tcp (lua_State *L, gint pos)
  1826. {
  1827. void *ud = rspamd_lua_check_udata (L, pos, "rspamd{tcp_sync}");
  1828. luaL_argcheck (L, ud != NULL, pos, "'tcp' expected");
  1829. return ud ? *((struct lua_tcp_cbdata **)ud) : NULL;
  1830. }
  1831. static int
  1832. lua_tcp_sync_close (lua_State *L)
  1833. {
  1834. LUA_TRACE_POINT;
  1835. struct lua_tcp_cbdata *cbd = lua_check_sync_tcp (L, 1);
  1836. if (cbd == NULL) {
  1837. return luaL_error (L, "invalid arguments [self is not rspamd{tcp_sync}]");
  1838. }
  1839. cbd->flags |= LUA_TCP_FLAG_FINISHED;
  1840. if (cbd->fd != -1) {
  1841. rspamd_ev_watcher_stop (cbd->event_loop, &cbd->ev);
  1842. close (cbd->fd);
  1843. cbd->fd = -1;
  1844. }
  1845. return 0;
  1846. }
  1847. static void
  1848. lua_tcp_sync_session_dtor (gpointer ud)
  1849. {
  1850. struct lua_tcp_cbdata *cbd = ud;
  1851. cbd->flags |= LUA_TCP_FLAG_FINISHED;
  1852. if (cbd->fd != -1) {
  1853. msg_debug ("closing sync TCP connection");
  1854. rspamd_ev_watcher_stop (cbd->event_loop, &cbd->ev);
  1855. close (cbd->fd);
  1856. cbd->fd = -1;
  1857. }
  1858. /* Task is gone, we should not try use it anymore */
  1859. cbd->task = NULL;
  1860. /* All events are removed when task is done, we should not refer them */
  1861. cbd->async_ev = NULL;
  1862. }
  1863. static int
  1864. lua_tcp_sync_read_once (lua_State *L)
  1865. {
  1866. LUA_TRACE_POINT;
  1867. struct lua_tcp_cbdata *cbd = lua_check_sync_tcp (L, 1);
  1868. struct lua_tcp_handler *rh;
  1869. if (cbd == NULL) {
  1870. return luaL_error (L, "invalid arguments [self is not rspamd{tcp_sync}]");
  1871. }
  1872. struct thread_entry *thread = lua_thread_pool_get_running_entry (cbd->cfg->lua_thread_pool);
  1873. rh = g_malloc0 (sizeof (*rh));
  1874. rh->type = LUA_WANT_READ;
  1875. rh->h.r.cbref = -1;
  1876. msg_debug_tcp ("added read sync event, thread: %p", thread);
  1877. g_queue_push_tail (cbd->handlers, rh);
  1878. lua_tcp_plan_handler_event (cbd, TRUE, TRUE);
  1879. TCP_RETAIN (cbd);
  1880. return lua_thread_yield (thread, 0);
  1881. }
  1882. static int
  1883. lua_tcp_sync_write (lua_State *L)
  1884. {
  1885. LUA_TRACE_POINT;
  1886. struct lua_tcp_cbdata *cbd = lua_check_sync_tcp (L, 1);
  1887. struct lua_tcp_handler *wh;
  1888. gint tp;
  1889. struct iovec *iov = NULL;
  1890. guint niov = 0;
  1891. gsize total_out = 0;
  1892. if (cbd == NULL) {
  1893. return luaL_error (L, "invalid arguments [self is not rspamd{tcp_sync}]");
  1894. }
  1895. struct thread_entry *thread = lua_thread_pool_get_running_entry (cbd->cfg->lua_thread_pool);
  1896. tp = lua_type (L, 2);
  1897. if (tp == LUA_TSTRING || tp == LUA_TUSERDATA) {
  1898. iov = g_malloc (sizeof (*iov));
  1899. niov = 1;
  1900. if (!lua_tcp_arg_toiovec (L, 2, cbd, iov)) {
  1901. msg_err ("tcp request has bad data argument");
  1902. g_free (iov);
  1903. g_free (cbd);
  1904. return luaL_error (L, "invalid arguments second parameter (data) is expected to be either string or rspamd{text}");
  1905. }
  1906. total_out = iov[0].iov_len;
  1907. }
  1908. else if (tp == LUA_TTABLE) {
  1909. /* Count parts */
  1910. lua_pushvalue (L, 3);
  1911. lua_pushnil (L);
  1912. while (lua_next (L, -2) != 0) {
  1913. niov ++;
  1914. lua_pop (L, 1);
  1915. }
  1916. iov = g_malloc (sizeof (*iov) * niov);
  1917. lua_pushnil (L);
  1918. niov = 0;
  1919. while (lua_next (L, -2) != 0) {
  1920. if (!lua_tcp_arg_toiovec (L, -1, cbd, &iov[niov])) {
  1921. msg_err ("tcp request has bad data argument at pos %d", niov);
  1922. g_free (iov);
  1923. g_free (cbd);
  1924. return luaL_error (L, "invalid arguments second parameter (data) is expected to be either string or rspamd{text}");
  1925. }
  1926. total_out += iov[niov].iov_len;
  1927. niov ++;
  1928. lua_pop (L, 1);
  1929. }
  1930. lua_pop (L, 1);
  1931. }
  1932. wh = g_malloc0 (sizeof (*wh));
  1933. wh->type = LUA_WANT_WRITE;
  1934. wh->h.w.iov = iov;
  1935. wh->h.w.iovlen = niov;
  1936. wh->h.w.total_bytes = total_out;
  1937. wh->h.w.pos = 0;
  1938. wh->h.w.cbref = -1;
  1939. msg_debug_tcp ("added sync write event, thread: %p", thread);
  1940. g_queue_push_tail (cbd->handlers, wh);
  1941. lua_tcp_plan_handler_event (cbd, TRUE, TRUE);
  1942. TCP_RETAIN (cbd);
  1943. return lua_thread_yield (thread, 0);
  1944. }
  1945. static gint
  1946. lua_tcp_sync_eof(lua_State *L)
  1947. {
  1948. LUA_TRACE_POINT;
  1949. struct lua_tcp_cbdata *cbd = lua_check_sync_tcp (L, 1);
  1950. if (cbd == NULL) {
  1951. return luaL_error (L, "invalid arguments [self is not rspamd{tcp_sync}]");
  1952. }
  1953. lua_pushboolean(L, cbd->eof);
  1954. return 1;
  1955. }
  1956. static gint
  1957. lua_tcp_sync_shutdown (lua_State *L)
  1958. {
  1959. LUA_TRACE_POINT;
  1960. struct lua_tcp_cbdata *cbd = lua_check_sync_tcp (L, 1);
  1961. if (cbd == NULL) {
  1962. return luaL_error (L, "invalid arguments [self is not rspamd{tcp_sync}]");
  1963. }
  1964. shutdown (cbd->fd, SHUT_WR);
  1965. return 0;
  1966. }
  1967. static gint
  1968. lua_tcp_starttls (lua_State * L)
  1969. {
  1970. LUA_TRACE_POINT;
  1971. struct lua_tcp_cbdata *cbd = lua_check_tcp (L, 1);
  1972. gpointer ssl_ctx;
  1973. gboolean verify_peer;
  1974. if (cbd == NULL || cbd->ssl_conn != NULL) {
  1975. return luaL_error (L, "invalid arguments");
  1976. }
  1977. if (cbd->flags & LUA_TCP_FLAG_SSL_NOVERIFY) {
  1978. ssl_ctx = cbd->cfg->libs_ctx->ssl_ctx_noverify;
  1979. verify_peer = FALSE;
  1980. }
  1981. else {
  1982. ssl_ctx = cbd->cfg->libs_ctx->ssl_ctx;
  1983. verify_peer = TRUE;
  1984. }
  1985. cbd->ssl_conn = rspamd_ssl_connection_new (ssl_ctx,
  1986. cbd->event_loop,
  1987. verify_peer,
  1988. cbd->tag);
  1989. if (!rspamd_ssl_connect_fd (cbd->ssl_conn, cbd->fd, cbd->hostname, &cbd->ev,
  1990. cbd->ev.timeout, lua_tcp_handler, lua_tcp_ssl_on_error, cbd)) {
  1991. lua_tcp_push_error (cbd, TRUE, "ssl connection failed: %s",
  1992. strerror (errno));
  1993. }
  1994. return 0;
  1995. }
  1996. static gint
  1997. lua_tcp_sync_gc (lua_State * L)
  1998. {
  1999. struct lua_tcp_cbdata *cbd = lua_check_sync_tcp (L, 1);
  2000. if (!cbd) {
  2001. return luaL_error (L, "invalid arguments [self is not rspamd{tcp_sync}]");
  2002. }
  2003. lua_tcp_maybe_free(cbd);
  2004. lua_tcp_fin (cbd);
  2005. return 0;
  2006. }
  2007. static gint
  2008. lua_load_tcp (lua_State * L)
  2009. {
  2010. lua_newtable (L);
  2011. luaL_register (L, NULL, tcp_libf);
  2012. return 1;
  2013. }
  2014. void
  2015. luaopen_tcp (lua_State * L)
  2016. {
  2017. rspamd_lua_add_preload (L, "rspamd_tcp", lua_load_tcp);
  2018. rspamd_lua_new_class (L, "rspamd{tcp}", tcp_libm);
  2019. rspamd_lua_new_class (L, "rspamd{tcp_sync}", tcp_sync_libm);
  2020. lua_pop (L, 1);
  2021. }