Module rspamd_tcp

Rspamd TCP module represents generic TCP asynchronous client available from LUA code. This module hides all complexity: DNS resolving, sessions management, zero-copy text transfers and so on under the hood. It can work in partial or complete modes:

  • partial mode is used when you need to call a continuation routine each time data is available for read
  • complete mode calls for continuation merely when all data is read from socket (e.g. when a server sends reply and closes a connection)

Example:

local logger = require "rspamd_logger"
local tcp = require "rspamd_tcp"

rspamd_config.SYM = function(task)

    local function cb(err, data)
        logger.infox('err: %1, data: %2', err, tostring(data))
    end

    tcp.request({
    	task = task,
    	host = "google.com",
    	port = 80,
    	data = {"GET / HTTP/1.0\r\n", "Host: google.com\r\n", "\r\n"},
    	callback = cb})
end

-- New TCP syntax test
rspamd_config:register_symbol({
  name = 'TCP_TEST',
  type = "normal",
  callback = function(task)
    local logger = require "rspamd_logger"
    local function rcpt_done_cb(err, data, conn)
      logger.errx(task, 'RCPT: got reply: %s, error: %s', data, err)
      conn:close()
    end
    local function rcpt_cb(err, conn)
      logger.errx(task, 'written rcpt, error: %s', err)
      conn:add_read(rcpt_done_cb, '\r\n')
    end
    local function from_done_cb(err, data, conn)
      logger.errx(task, 'FROM: got reply: %s, error: %s', data, err)
      conn:add_write(rcpt_cb, 'RCPT TO: <test@yandex.ru>\r\n')
    end
    local function from_cb(err, conn)
      logger.errx(task, 'written from, error: %s', err)
      conn:add_read(from_done_cb, '\r\n')
    end
    local function hello_done_cb(err, data, conn)
      logger.errx(task, 'HELO: got reply: %s, error: %s', data, err)
      conn:add_write(from_cb, 'MAIL FROM: <>\r\n')
    end
    local function hello_cb(err, conn)
      logger.errx(task, 'written hello, error: %s', err)
      conn:add_read(hello_done_cb, '\r\n')
    end
    local function init_cb(err, data, conn)
      logger.errx(task, 'got reply: %s, error: %s', data, err)
      conn:add_write(hello_cb, 'HELO example.com\r\n')
    end
    tcp.request{
      task = task,
      callback = init_cb,
      stop_pattern = '\r\n',
      host = 'mx.yandex.ru',
      port = 25

  end,
  priority = 10,
})

Brief content:

Functions:

Function Description
rspamd_tcp.connect_sync() .
rspamd_tcp.request({params}) This function creates and sends TCP request to the specified host and port,.
rspamd_tcp.connect_sync({params}) Creates new pseudo-synchronous connection to the specific address:port.

Methods:

Method Description
tcp:close() .
tcp:add_read(callback, [pattern]) .
tcp:add_write(callback, data) .
tcp:shift_callback() .
tcp:starttls([no_verify]) .
tcp:close() .
read_once() .
eof() .
shutdown() .
write() .

Functions

The module rspamd_tcp defines the following functions.

Function rspamd_tcp.connect_sync()

Creates pseudo-synchronous TCP connection. Each method of the connection requiring IO, becomes a yielding point, i.e. current thread Lua thread is get suspended and resumes as soon as IO is done

This class represents low-level API, using of “lua_tcp_sync” module is recommended.

Parameters:

No parameters

Returns:

No return

Example:

local rspamd_tcp = require "rspamd_tcp"
local logger = require "rspamd_logger"

local function http_simple_tcp_symbol(task)

    local err
    local is_ok, connection = rspamd_tcp.connect_sync {
      task = task,
      host = '127.0.0.1',
      timeout = 20,
      port = 18080,
      ssl = false, -- If SSL connection is needed
      ssl_verify = true, -- set to false if verify is not needed


    is_ok, err = connection:write('GET /request_sync HTTP/1.1\r\nConnection: keep-alive\r\n\r\n')

    logger.errx(task, 'write %1, %2', is_ok, err)
    if not is_ok then
      logger.errx(task, 'write error: %1', err)
    end

    local data
    is_ok, data = connection:read_once();

    logger.errx(task, 'read_once: is_ok: %1, data: %2', is_ok, data)

    is_ok, err = connection:write("POST /request2 HTTP/1.1\r\n\r\n")
    logger.errx(task, 'write[2] %1, %2', is_ok, err)

    is_ok, data = connection:read_once();
    logger.errx(task, 'read_once[2]: is_ok %1, data: %2', is_ok, data)

    connection:close()
end

rspamd_config:register_symbol({
  name = 'SIMPLE_TCP_TEST',
  score = 1.0,
  callback = http_simple_tcp_symbol,
  no_squeeze = true
})

Back to module description.

Function rspamd_tcp.request({params})

This function creates and sends TCP request to the specified host and port, resolves hostname (if needed) and invokes continuation callback upon data received from the remote peer. This function accepts table of arguments with the following attributes

  • task: rspamd task objects (implies pool, session, ev_base and resolver arguments)
  • ev_base: event base (if no task specified)
  • resolver: DNS resolver (no task)
  • session: events session (no task)
  • host: IP or name of the peer (required)
  • port: remote port to use
  • data: a table of strings or rspamd_text objects that contains data pieces
  • callback: continuation function (required)
  • on_connect: callback called on connection success
  • timeout: floating point value that specifies timeout for IO operations in seconds
  • partial: boolean flag that specifies that callback should be called on any data portion received
  • stop_pattern: stop reading on finding a certain pattern (e.g. \r\n.\r\n for smtp)
  • shutdown: half-close socket after writing (boolean: default false)
  • read: read response after sending request (boolean: default true)
  • upstream: optional upstream object that would be used to get an address

Parameters:

No parameters

Returns:

  • {boolean}: true if request has been sent

Back to module description.

Function rspamd_tcp.connect_sync({params})

Creates new pseudo-synchronous connection to the specific address:port

  • task: rspamd task objects (implies pool, session, ev_base and resolver arguments)
  • ev_base: event base (if no task specified)
  • resolver: DNS resolver (no task)
  • session: events session (no task)
  • config: config (no task)
  • host: IP or name of the peer (required)
  • port: remote port to use
  • timeout: floating point value that specifies timeout for IO operations in seconds

Parameters:

No parameters

Returns:

  • {boolean}: true if request has been sent

Back to module description.

Methods

The module rspamd_tcp defines the following methods.

Method tcp:close()

Closes TCP connection

Parameters:

No parameters

Returns:

No return

Back to module description.

Method tcp:add_read(callback, [pattern])

Adds new read event to the tcp connection

Parameters:

  • callback {function}: to be called when data is read
  • pattern {string}: optional stop pattern

Returns:

No return

Back to module description.

Method tcp:add_write(callback, data)

Adds new write event to the tcp connection

Parameters:

  • optional {function}: callback to be called when data is completely written
  • data {table/string/text}: to send to a remote server

Returns:

No return

Back to module description.

Method tcp:shift_callback()

Shifts the current callback and go to the next one (if any)

Parameters:

No parameters

Returns:

No return

Back to module description.

Method tcp:starttls([no_verify])

Starts tls connection

Parameters:

  • no_verify {boolean}: used to skip ssl verification

Returns:

No return

Back to module description.

Method tcp:close()

Closes TCP connection

Parameters:

No parameters

Returns:

No return

Back to module description.

Method read_once()

Performs one read operation. If syscall returned with EAGAIN/EINT, restarts the operation, so it always returns either data or error.

Parameters:

No parameters

Returns:

No return

Back to module description.

Method eof()

True if last IO operation ended with EOF, i.e. endpoint closed connection

Parameters:

No parameters

Returns:

No return

Back to module description.

Method shutdown()

Half-shutdown TCP connection

Parameters:

No parameters

Returns:

No return

Back to module description.

Method write()

Writes data into the stream. If syscall returned with EAGAIN/EINT restarts the operation. If performs write() until all the passed data is written completely.

Parameters:

No parameters

Returns:

No return

Back to module description.

Back to top.