From e1c7b8dcaf5965e3b2894fa43132f731355afe10 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Tue, 5 Jan 2016 22:12:22 +0100
Subject: degesch: Lua: halfplement a connector wrapper
You can't do anything reasonable with the socket now.
---
degesch.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 237 insertions(+), 5 deletions(-)
diff --git a/degesch.c b/degesch.c
index 5d1186c..c8aa67f 100644
--- a/degesch.c
+++ b/degesch.c
@@ -7877,7 +7877,7 @@ lua_schema_item_gc (lua_State *L)
return 0;
}
-static luaL_Reg lua_schema_item_table[] =
+static luaL_Reg lua_schema_table[] =
{
{ "__gc", lua_schema_item_gc },
{ NULL, NULL }
@@ -8117,12 +8117,242 @@ lua_plugin_setup_config (lua_State *L)
return 0;
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+/// Identifier for the Lua metatable
+#define XLUA_CONNECTION_METATABLE "connection"
+
+struct lua_connection
+{
+ struct lua_plugin *plugin; ///< The plugin we belong to
+ struct poller_fd socket_event; ///< Socket is ready
+ int socket_fd; ///< Underlying connected socket
+};
+
+static int
+lua_connection_close (lua_State *L)
+{
+ struct lua_connection *self =
+ luaL_checkudata (L, 1, XLUA_CONNECTION_METATABLE);
+
+ if (self->socket_fd != -1)
+ {
+ poller_fd_reset (&self->socket_event);
+ xclose (self->socket_fd);
+ self->socket_fd = -1;
+ }
+
+ // Connection is dead, we don't need to hold onto any resources anymore
+ lua_cache_invalidate (L, self);
+ return 0;
+}
+
+static luaL_Reg lua_connection_table[] =
+{
+ { "close", lua_connection_close },
+ { "__gc", lua_connection_close },
+ { NULL, NULL }
+};
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+static void
+lua_connection_on_ready (const struct pollfd *pfd, struct lua_connection *self)
+{
+ // TODO: handle the event, invoke on_data, on_close, on_error from
+ // our associated uservalue table as needed
+ lua_cache_invalidate (self->plugin->L, self);
+}
+
+static struct lua_connection *
+lua_plugin_push_connection (struct lua_plugin *plugin, int socket_fd)
+{
+ lua_State *L = plugin->L;
+
+ struct lua_connection *self = lua_newuserdata (L, sizeof *self);
+ luaL_setmetatable (L, XLUA_CONNECTION_METATABLE);
+ memset (self, 0, sizeof *self);
+ self->plugin = plugin;
+
+ poller_fd_init (&self->socket_event, &plugin->ctx->poller,
+ (self->socket_fd = socket_fd));
+ self->socket_event.dispatcher = (poller_fd_fn) lua_connection_on_ready;
+ self->socket_event.user_data = self;
+ poller_fd_set (&self->socket_event, POLLIN);
+
+ // Make sure the connection doesn't get garbage collected and return it
+ lua_cache_store (L, self, -1);
+ return self;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+/// Identifier for the Lua metatable
+#define XLUA_CONNECTOR_METATABLE "connector"
+
+struct lua_connector
+{
+ struct lua_plugin *plugin; ///< The plugin we belong to
+ struct connector connector; ///< Connector object
+ bool active; ///< Whether the connector is alive
+
+ int ref_on_success; ///< Reference to "on_success" callback
+ int ref_on_error; ///< Reference to "on_error" callback
+
+ char *last_error; ///< Connecting error, if any
+};
+
+static void
+lua_connector_discard (struct lua_connector *self)
+{
+ if (self->active)
+ {
+ connector_free (&self->connector);
+ self->active = false;
+
+ luaL_unref (self->plugin->L, LUA_REGISTRYINDEX, self->ref_on_success);
+ luaL_unref (self->plugin->L, LUA_REGISTRYINDEX, self->ref_on_error);
+ self->ref_on_success = LUA_REFNIL;
+ self->ref_on_error = LUA_REFNIL;
+ }
+
+ free (self->last_error);
+ self->last_error = NULL;
+
+ lua_cache_invalidate (self->plugin->L, self);
+}
+
+static int
+lua_connector_abort (lua_State *L)
+{
+ struct lua_connector *self =
+ luaL_checkudata (L, 1, XLUA_CONNECTOR_METATABLE);
+ lua_connector_discard (self);
+ return 0;
+}
+
+static luaL_Reg lua_connector_table[] =
+{
+ { "abort", lua_connector_abort },
+ { "__gc", lua_connector_abort },
+ { NULL, NULL }
+};
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+static void
+lua_connector_on_connected (void *user_data, int socket, const char *hostname)
+{
+ struct lua_connector *self = user_data;
+ struct lua_plugin *plugin = self->plugin;
+ lua_State *L = plugin->L;
+
+ // TODO: use this for SNI once TLS is implemented
+ (void) hostname;
+
+ if (self->ref_on_success != LUA_REFNIL)
+ {
+ lua_pushcfunction (L, lua_plugin_error_handler);
+
+ lua_rawgeti (L, LUA_REGISTRYINDEX, self->ref_on_success);
+ lua_plugin_push_connection (plugin, socket); // 1: connection
+
+ if (lua_pcall (L, 1, 0, -3))
+ {
+ struct error *e = NULL;
+ (void) lua_plugin_process_error (plugin, lua_tostring (L, -1), &e);
+ lua_pop (L, 1);
+
+ log_global_error (plugin->ctx, "Lua: plugin \"#s\": #s: #s",
+ plugin->super.name, "connector on_success", e->message);
+ error_free (e);
+ }
+ }
+ lua_connector_discard (self);
+}
+
+static void
+lua_connector_on_failure (void *user_data)
+{
+ struct lua_connector *self = user_data;
+ struct lua_plugin *plugin = self->plugin;
+ lua_State *L = plugin->L;
+
+ if (self->ref_on_error != LUA_REFNIL)
+ {
+ lua_pushcfunction (L, lua_plugin_error_handler);
+
+ lua_rawgeti (L, LUA_REGISTRYINDEX, self->ref_on_error);
+ lua_pushstring (L, self->last_error); // 1: error string
+
+ if (lua_pcall (L, 1, 0, -3))
+ {
+ struct error *e = NULL;
+ (void) lua_plugin_process_error (plugin, lua_tostring (L, -1), &e);
+ lua_pop (L, 1);
+
+ log_global_error (plugin->ctx, "Lua: plugin \"#s\": #s: #s",
+ plugin->super.name, "connector on_error", e->message);
+ error_free (e);
+ }
+ }
+ lua_connector_discard (self);
+}
+
+static void
+lua_connector_on_error (void *user_data, const char *error)
+{
+ struct lua_connector *self = user_data;
+ free (self->last_error);
+ self->last_error = xstrdup (error);
+}
+
+static int
+lua_plugin_connect (lua_State *L)
+{
+ struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1));
+ const char *host = luaL_checkstring (L, 1);
+ const char *service = luaL_checkstring (L, 2);
+ luaL_checktype (L, 3, LUA_TTABLE);
+
+ struct lua_connector *self = lua_newuserdata (L, sizeof *self);
+ luaL_setmetatable (L, XLUA_CONNECTOR_METATABLE);
+ memset (self, 0, sizeof *self);
+
+ self->plugin = plugin;
+ self->ref_on_success = LUA_REFNIL;
+ self->ref_on_error = LUA_REFNIL;
+
+ if (lua_plugin_check_field (L, 3, "on_success", LUA_TFUNCTION, true))
+ self->ref_on_success = luaL_ref (L, -1);
+ if (lua_plugin_check_field (L, 3, "on_error", LUA_TFUNCTION, true))
+ self->ref_on_error = luaL_ref (L, -1);
+
+ lua_pop (L, 2);
+
+ struct app_context *ctx = plugin->ctx;
+ struct connector *connector = &self->connector;
+ connector_init (connector, &ctx->poller);
+ connector_add_target (connector, host, service);
+
+ connector->on_connected = lua_connector_on_connected;
+ connector->on_connecting = NULL;
+ connector->on_error = lua_connector_on_error;
+ connector->on_failure = lua_connector_on_failure;
+ connector->user_data = self;
+
+ self->active = true;
+ lua_cache_store (L, self, -1);
+ return 1;
+}
+
static luaL_Reg lua_plugin_library[] =
{
{ "hook_input", lua_plugin_hook_input },
{ "hook_irc", lua_plugin_hook_irc },
{ "hook_timer", lua_plugin_hook_timer },
{ "setup_config", lua_plugin_setup_config },
+ { "connect", lua_plugin_connect },
{ NULL, NULL },
};
@@ -8250,10 +8480,12 @@ lua_plugin_load (struct app_context *ctx, const char *filename,
lua_setglobal (L, PROGRAM_NAME);
// Create metatables for our objects
- lua_plugin_create_meta (L, XLUA_HOOK_METATABLE, lua_hook_table);
- lua_plugin_create_meta (L, XLUA_BUFFER_METATABLE, lua_buffer_table);
- lua_plugin_create_meta (L, XLUA_SERVER_METATABLE, lua_server_table);
- lua_plugin_create_meta (L, XLUA_SCHEMA_METATABLE, lua_schema_item_table);
+ lua_plugin_create_meta (L, XLUA_HOOK_METATABLE, lua_hook_table);
+ lua_plugin_create_meta (L, XLUA_BUFFER_METATABLE, lua_buffer_table);
+ lua_plugin_create_meta (L, XLUA_SERVER_METATABLE, lua_server_table);
+ lua_plugin_create_meta (L, XLUA_SCHEMA_METATABLE, lua_schema_table);
+ lua_plugin_create_meta (L, XLUA_CONNECTION_METATABLE, lua_connection_table);
+ lua_plugin_create_meta (L, XLUA_CONNECTOR_METATABLE, lua_connector_table);
int ret;
if (!(ret = luaL_loadfile (L, filename))
--
cgit v1.2.3-70-g09d2