From: Vsevolod Stakhov Date: Sat, 10 Oct 2015 13:20:14 +0000 (+0100) Subject: Start control interface implementation. X-Git-Tag: 1.0.5~38 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=10542268e3167adac672b23ae184cb5810034e9a;p=rspamd.git Start control interface implementation. --- diff --git a/src/libserver/rspamd_control.c b/src/libserver/rspamd_control.c index 99b76058c..aa2edaf74 100644 --- a/src/libserver/rspamd_control.c +++ b/src/libserver/rspamd_control.c @@ -20,4 +20,211 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */#include "rspamd_control.h" + */ + +#include "config.h" +#include "rspamd.h" +#include "rspamd_control.h" +#include "http.h" +#include "unix-std.h" +#include "utlist.h" + +static struct timeval io_timeout = { + .tv_sec = 30, + .tv_usec = 0 +}; + +struct rspamd_control_reply_elt { + struct rspamd_control_reply reply; + struct event io_ev; + struct event tm_ev; + struct rspamd_worker *wrk; + struct rspamd_control_reply_elt *prev, *next; +}; + +struct rspamd_control_session { + gint fd; + struct rspamd_main *rspamd_main; + struct rspamd_http_connection *conn; + struct rspamd_control_command cmd; + struct rspamd_control_reply_elt *replies; + gboolean is_reply; +}; + +static const struct rspamd_control_cmd_match { + rspamd_ftok_t name; + enum rspamd_control_type type; +} cmd_matches[] = { + { + .name = { + .begin = "/stat", + .len = 5 + }, + .type = RSPAMD_CONTROL_STAT + }, + { + .name = { + .begin = "/reload", + .len = 7 + }, + .type = RSPAMD_CONTROL_RELOAD + }, +}; + +void +rspamd_control_send_error (struct rspamd_control_session *session, + gint code, const gchar *error_msg, ...) +{ + struct rspamd_http_message *msg; + va_list args; + + msg = rspamd_http_new_message (HTTP_RESPONSE); + + va_start (args, error_msg); + msg->status = rspamd_fstring_sized_new (128); + rspamd_vprintf_fstring (&msg->status, error_msg, args); + va_end (args); + + msg->date = time (NULL); + msg->code = code; + msg->body = rspamd_fstring_sized_new (128); + rspamd_printf_fstring (&msg->body, "{\"error\":\"%V\"}", msg->status); + rspamd_http_connection_reset (session->conn); + rspamd_http_connection_write_message (session->conn, + msg, + NULL, + "application/json", + session, + session->fd, + &io_timeout, + session->rspamd_main->ev_base); +} + +static void +rspamd_control_send_ucl (struct rspamd_control_session *session, + ucl_object_t *obj) +{ + struct rspamd_http_message *msg; + + msg = rspamd_http_new_message (HTTP_RESPONSE); + msg->date = time (NULL); + msg->code = 200; + msg->body = rspamd_fstring_sized_new (BUFSIZ); + rspamd_ucl_emit_fstring (obj, UCL_EMIT_JSON_COMPACT, &msg->body); + rspamd_http_connection_reset (session->conn); + rspamd_http_connection_write_message (session->conn, + msg, + NULL, + "application/json", + session, + session->fd, + &io_timeout, + session->rspamd_main->ev_base); +} + +static void +rspamd_control_connection_close (struct rspamd_control_session *session) +{ + struct rspamd_control_reply_elt *elt, *telt; + + DL_FOREACH_SAFE (session->replies, elt, telt) { + g_slice_free1 (sizeof (*elt), elt); + } + + rspamd_http_connection_unref (session->conn); + close (session->fd); + g_slice_free1 (sizeof (*session), session); +} + +static void +rspamd_control_error_handler (struct rspamd_http_connection *conn, GError *err) +{ + struct rspamd_control_session *session = conn->ud; + + if (!session->is_reply) { + msg_info ("abnormally closing control connection: %e", err); + session->is_reply = TRUE; + rspamd_control_send_error (session, err->code, "%s", err->message); + } + else { + rspamd_control_connection_close (session); + } +} + +static gint +rspamd_control_finish_hadler (struct rspamd_http_connection *conn, + struct rspamd_http_message *msg) +{ + struct rspamd_control_session *session = conn->ud; + rspamd_ftok_t srch; + guint i; + gboolean found = FALSE; + + if (!session->is_reply) { + if (msg->url == NULL) { + rspamd_control_connection_close (session); + + return 0; + } + + srch.begin = msg->url->str; + srch.len = msg->url->len; + + session->is_reply = TRUE; + + for (i = 0; i < G_N_ELEMENTS (cmd_matches); i++) { + if (rspamd_ftok_casecmp (&srch, &cmd_matches[i].name) == 0) { + session->cmd.type = cmd_matches[i].type; + found = TRUE; + break; + } + } + + if (!found) { + rspamd_control_send_error (session, 404, "Command not defined"); + } + else { + rspamd_control_send_error (session, 500, "Not implemented yet"); + } + } + else { + rspamd_control_connection_close (session); + } + + + return 0; +} + +void +rspamd_control_process_client_socket (struct rspamd_main *rspamd_main, + gint fd) +{ + struct rspamd_control_session *session; + + session = g_slice_alloc0 (sizeof (*session)); + + session->fd = fd; + session->conn = rspamd_http_connection_new (NULL, rspamd_control_error_handler, + rspamd_control_finish_hadler, 0, RSPAMD_HTTP_SERVER, NULL); + session->rspamd_main = rspamd_main; + rspamd_http_connection_read_message (session->conn, session, session->fd, + &io_timeout, rspamd_main->ev_base); +} + +void +rspamd_control_worker_add_default_handler (struct rspamd_worker *worker) +{ + +} + +/** + * Register custom handler for a specific control command for this worker + */ +void +rspamd_control_worker_add_cmd_handler (struct rspamd_worker *worker, + enum rspamd_control_type type, + rspamd_worker_control_handler handler, + gpointer ud) +{ + +} diff --git a/src/libserver/rspamd_control.h b/src/libserver/rspamd_control.h index d8a25990d..2863f2988 100644 --- a/src/libserver/rspamd_control.h +++ b/src/libserver/rspamd_control.h @@ -25,6 +25,64 @@ #ifndef RSPAMD_RSPAMD_CONTROL_H #define RSPAMD_RSPAMD_CONTROL_H +#include "config.h" +struct rspamd_main; +struct rspamd_worker; + +enum rspamd_control_type { + RSPAMD_CONTROL_STAT = 0, + RSPAMD_CONTROL_RELOAD, + RSPAMD_CONTROL_MAX +}; + +struct rspamd_control_command { + enum rspamd_control_type type; + union { + struct { + guint unused; + } stat; + struct { + guint unused; + } reload; + } cmd; +}; + +struct rspamd_control_reply { + enum rspamd_control_type type; + union { + struct { + guint conns; + guint64 uptime; + } stat; + struct { + guint status; + } reload; + } reply; +}; + +typedef gboolean (*rspamd_worker_control_handler) (struct rspamd_main *rspamd_main, + struct rspamd_worker *worker, gint fd, + struct rspamd_control_command *cmd, + gpointer ud); + +/** + * Process client socket connection + */ +void rspamd_control_process_client_socket (struct rspamd_main *rspamd_main, + gint fd); + +/** + * Register default handlers for a worker + */ +void rspamd_control_worker_add_default_handler (struct rspamd_worker *worker); + +/** + * Register custom handler for a specific control command for this worker + */ +void rspamd_control_worker_add_cmd_handler (struct rspamd_worker *worker, + enum rspamd_control_type type, + rspamd_worker_control_handler handler, + gpointer ud); #endif diff --git a/src/rspamd.c b/src/rspamd.c index 19d04aae0..dccd3b6c5 100644 --- a/src/rspamd.c +++ b/src/rspamd.c @@ -789,6 +789,8 @@ rspamd_control_handler (gint fd, short what, gpointer arg) msg_info_main ("accepted control connection from %s", rspamd_inet_address_to_string (addr)); + + rspamd_control_process_client_socket (rspamd_main, nfd); } gint