Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'agent/tcf/main/main_lua.c')
-rw-r--r--agent/tcf/main/main_lua.c1627
1 files changed, 1627 insertions, 0 deletions
diff --git a/agent/tcf/main/main_lua.c b/agent/tcf/main/main_lua.c
new file mode 100644
index 00000000..758232dc
--- /dev/null
+++ b/agent/tcf/main/main_lua.c
@@ -0,0 +1,1627 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Agent main module.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#if ENABLE_LUA
+
+#include <errno.h>
+#include <assert.h>
+#include <signal.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <lualib.h>
+#include <lauxlib.h>
+#ifdef __cplusplus
+}
+#endif
+
+#include <framework/asyncreq.h>
+#include <framework/events.h>
+#include <framework/trace.h>
+#include <framework/channel.h>
+#include <framework/protocol.h>
+#include <framework/proxy.h>
+#include <framework/myalloc.h>
+#include <framework/errors.h>
+#include <services/discovery.h>
+
+static const char * progname;
+static lua_State *luastate;
+
+struct luaref {
+ int ref;
+ void *owner;
+ struct luaref *next;
+};
+
+enum {
+ bufst_normal,
+ bufst_normal_optnl,
+ bufst_esc,
+ bufst_esc2,
+ bufst_eol,
+ bufst_eol_optnl
+};
+
+struct lua_read_command_state {
+ int reqline;
+ int reqdata;
+ struct luaref *refp;
+ AsyncReqInfo req;
+ int eof;
+ int bufrd;
+ int bufwr;
+ int bufst;
+ char buf[1024];
+ int linemax;
+ int lineind;
+ char *line;
+};
+
+struct peer_extra {
+ lua_State *L;
+ PeerServer * ps;
+ int managed;
+};
+
+struct protocol_extra {
+ lua_State *L;
+ Protocol * p;
+ unsigned int ucnt;
+ struct luaref *self_refp;
+};
+
+struct channel_extra {
+ lua_State *L;
+ Channel * c;
+ struct protocol_extra * pe;
+ struct luaref *self_refp;
+ struct luaref *connect_cbrefp;
+ struct luaref *connecting_cbrefp;
+ struct luaref *connected_cbrefp;
+ struct luaref *receive_cbrefp;
+ struct luaref *disconnected_cbrefp;
+};
+
+struct command_extra {
+ struct luaref *self_refp;
+ struct luaref *result_cbrefp;
+ ReplyHandlerInfo * replyinfo;
+};
+
+struct post_event_extra {
+ lua_State *L;
+ struct luaref *self_refp;
+ struct luaref *handler_refp;
+};
+
+static struct luaref *refroot;
+static struct luaref *peers_refp;
+static struct lua_read_command_state lua_read_command_state;
+
+static void lua_read_command_fillbuf(struct lua_read_command_state *state);
+
+
+static struct luaref *luaref_new(lua_State *L, void * owner)
+{
+ struct luaref *refp = (struct luaref *)loc_alloc(sizeof *refp);
+
+ refp->ref = luaL_ref(L, LUA_REGISTRYINDEX);
+ refp->owner = owner;
+ refp->next = refroot;
+ refroot = refp;
+ return refp;
+}
+
+static void luaref_free(lua_State *L, struct luaref *p)
+{
+ struct luaref **refpp;
+ struct luaref *refp;
+
+ refpp = &refroot;
+ while((refp = *refpp) != NULL) {
+ if(refp == p) {
+ *refpp = refp->next;
+ luaL_unref(L, LUA_REGISTRYINDEX, refp->ref);
+ loc_free(refp);
+ return;
+ }
+ refpp = &refp->next;
+ }
+ assert(!"lua reference not found in list");
+}
+
+static void luaref_owner_free(lua_State *L, void * owner)
+{
+ struct luaref **refpp;
+ struct luaref *refp;
+
+ refpp = &refroot;
+ while((refp = *refpp) != NULL) {
+ if(refp->owner == owner) {
+ *refpp = refp->next;
+ luaL_unref(L, LUA_REGISTRYINDEX, refp->ref);
+ loc_free(refp);
+ continue;
+ }
+ refpp = &refp->next;
+ }
+}
+
+#ifndef NDEBUG
+static int lua_isclass(lua_State *L, int index, const char *name)
+{
+ int rval;
+
+ if(!lua_getmetatable(L, index)) return 0;
+ lua_getfield(L, LUA_REGISTRYINDEX, name);
+ rval = lua_rawequal(L, -1, -2);
+ lua_pop(L, 2);
+ return rval;
+}
+#endif
+
+static struct peer_extra *lua2peer(lua_State *L, int index)
+{
+ if(luaL_checkudata(L, index, "tcf_peer") == NULL) {
+ return NULL;
+ }
+ return (struct peer_extra *)lua_touserdata(L, index);
+}
+
+static struct protocol_extra *lua2protocol(lua_State *L, int index)
+{
+ if(luaL_checkudata(L, index, "tcf_protocol") == NULL) {
+ return NULL;
+ }
+ return (struct protocol_extra *)lua_touserdata(L, index);
+}
+
+static struct channel_extra *lua2channel(lua_State *L, int index)
+{
+ if(luaL_checkudata(L, index, "tcf_channel") == NULL) {
+ return NULL;
+ }
+ return (struct channel_extra *)lua_touserdata(L, index);
+}
+
+static struct post_event_extra *lua2postevent(lua_State *L, int index)
+{
+ if(luaL_checkudata(L, index, "tcf_post_event") == NULL) {
+ return NULL;
+ }
+ return (struct post_event_extra *)lua_touserdata(L, index);
+}
+
+static void lua_read_command_getline(void *client_data)
+{
+ int c;
+ lua_State *L = luastate;
+ struct lua_read_command_state *state = (struct lua_read_command_state *)client_data;
+
+ assert(state->reqline != 0);
+ assert(state->reqdata == 0);
+ while(state->bufrd < state->bufwr) {
+ c = state->buf[state->bufrd++];
+ switch(state->bufst) {
+ case bufst_normal:
+ case_bufst_normal:
+ if(c == '\\') {
+ state->bufst = bufst_esc;
+ continue;
+ }
+ if(c == '\r') {
+ state->bufst = bufst_eol_optnl;
+ goto eol;
+ }
+ if(c == '\n') {
+ state->bufst = bufst_eol;
+ goto eol;
+ }
+ break;
+
+ case bufst_normal_optnl:
+ if(c == '\n') {
+ state->bufst = bufst_normal;
+ continue;
+ }
+ goto case_bufst_normal;
+
+ case bufst_esc:
+ if(c == '\r') {
+ state->bufst = bufst_normal_optnl;
+ c = '\n';
+ break;
+ }
+ if(c == '\n') {
+ state->bufst = bufst_normal;
+ break;
+ }
+ state->bufst = bufst_esc2;
+ state->bufrd--;
+ c = '\\';
+ break;
+
+ case bufst_esc2:
+ state->bufst = bufst_normal;
+ break;
+
+ case bufst_eol:
+ state->bufst = bufst_normal;
+ goto case_bufst_normal;
+
+ case bufst_eol_optnl:
+ state->bufst = bufst_normal;
+ if(c == '\n') continue;
+ goto case_bufst_normal;
+
+ default:
+ assert(!"unexpected state");
+ }
+ if(state->lineind == state->linemax) {
+ if(state->linemax == 0) {
+ state->linemax = 1024;
+ state->line = (char *)loc_alloc(state->linemax);
+ } else {
+ state->linemax *= 2;
+ state->line = (char *)loc_realloc(state->line, state->linemax);
+ }
+ }
+ state->line[state->lineind++] = (char)c;
+ }
+eol:
+ if(state->bufst != bufst_eol_optnl && state->bufst != bufst_eol && !state->eof) {
+ assert(state->bufrd == state->bufwr);
+ lua_read_command_fillbuf(state);
+ return;
+ }
+ state->reqline = 0;
+ assert(state->refp != NULL);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, state->refp->ref);
+ luaref_free(L, state->refp);
+ state->refp = NULL;
+ if(state->lineind > 0 || !state->eof) {
+ trace(LOG_LUA, "lua_read_command: %.*s", state->lineind, state->line);
+ lua_pushlstring(L, state->line, state->lineind);
+ state->lineind = 0;
+ } else {
+ trace(LOG_LUA, "lua_read_command: EOF");
+ lua_pushnil(L);
+ }
+ if(lua_pcall(L, 1, 0, 0) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+ return;
+}
+
+static void lua_read_command_done(void *client_data)
+{
+ AsyncReqInfo *req = (AsyncReqInfo *)client_data;
+ struct lua_read_command_state *state = (struct lua_read_command_state *)req->client_data;
+
+ assert(state->reqdata != 0);
+ state->reqdata = 0;
+ if(state->req.u.fio.rval > 0) {
+ state->bufwr += state->req.u.fio.rval;
+ state->eof = 0;
+ } else {
+ state->eof = 1;
+ }
+ lua_read_command_getline(state);
+}
+
+static void lua_read_command_fillbuf(struct lua_read_command_state *state)
+{
+ assert(state->reqdata == 0);
+ assert(state->bufrd == state->bufwr);
+ state->reqdata = 1;
+ state->bufrd = 0;
+ state->bufwr = 0;
+ state->req.done = lua_read_command_done;
+ state->req.client_data = state;
+ state->req.type = AsyncReqRead;
+ state->req.u.fio.bufp = state->buf;
+ state->req.u.fio.bufsz = sizeof state->buf;
+ async_req_post(&state->req);
+}
+
+static int lua_read_command(lua_State *L)
+{
+ struct lua_read_command_state *state = &lua_read_command_state;
+
+ assert(L == luastate);
+ assert(state->reqline == 0);
+ if(lua_gettop(L) != 1 || !lua_isfunction(L, 1)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ trace(LOG_LUA, "lua_read_command start");
+ lua_pushvalue(L, 1);
+ state->refp = luaref_new(L, state);
+ state->reqline = 1;
+ if(state->bufrd == state->bufwr) {
+ lua_read_command_fillbuf(state);
+ } else {
+ post_event(lua_read_command_getline, state);
+ }
+ return 0;
+}
+
+static struct peer_extra *lookup_pse(lua_State *L, PeerServer *ps)
+{
+ struct peer_extra *pse;
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, peers_refp->ref);
+ lua_pushstring(L, ps->id); /* Key */
+ lua_rawget(L, -2);
+ if((pse = (struct peer_extra *)lua_touserdata(L, -1)) == NULL) {
+ assert(lua_isnil(L, -1));
+ lua_pop(L, 2);
+ return NULL;
+ }
+ assert(lua_isclass(L, -1, "tcf_peer"));
+ lua_pop(L, 2);
+ return pse;
+}
+
+static struct peer_extra *lua_alloc_pse(lua_State *L, PeerServer *ps)
+{
+ struct peer_extra *pse;
+
+ /* Allocate new LUA object for peer */
+ pse = (struct peer_extra *)lua_newuserdata(L, sizeof *pse);
+ memset(pse, 0, sizeof *pse);
+ pse->L = L;
+ pse->ps = ps;
+ luaL_getmetatable(L, "tcf_peer");
+ lua_setmetatable(L, -2);
+ /* Returns userdata for peer on LUA stack */
+ return pse;
+}
+
+static struct peer_extra *lua_push_pse(lua_State *L, PeerServer *ps)
+{
+ struct peer_extra *pse;
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, peers_refp->ref);
+ lua_pushstring(L, ps->id); /* Key */
+ lua_rawget(L, -2);
+ if((pse = (struct peer_extra *)lua_touserdata(L, -1)) != NULL) {
+ assert(lua_isclass(L, -1, "tcf_peer"));
+ assert(pse->managed);
+ } else {
+ assert(lua_isnil(L, -1));
+ lua_pop(L, 1);
+
+ pse = lua_alloc_pse(L, ps);
+ pse->managed = 1;
+
+ /* Register mapping from PS to LUA object */
+ lua_pushstring(L, ps->id); /* Key */
+ lua_pushvalue(L, -2); /* Value */
+ lua_rawset(L, -4); /* peers[id] = pse */
+ }
+ lua_remove(L, -2); /* Remove peers table */
+ /* Returns userdata for peer on LUA stack */
+ return pse;
+}
+
+static void peer_server_changes(PeerServer *ps, int changeType, void * client_data)
+{
+ lua_State *L = (lua_State *)client_data;
+ struct peer_extra *pse = lookup_pse(L, ps);
+
+ switch(changeType) {
+ case PS_EVENT_ADDED:
+ assert(pse == NULL);
+ break;
+
+ case PS_EVENT_HEART_BEAT:
+ break;
+
+ case PS_EVENT_CHANGED:
+ if(pse != NULL) pse->ps = ps;
+ break;
+
+ case PS_EVENT_REMOVED:
+ if(pse != NULL) pse->ps = NULL;
+ break;
+
+ default:
+ assert(!"unknown peer change type");
+ }
+}
+
+static int lua_peer_server_find(lua_State *L)
+{
+ PeerServer *ps;
+ const char *name;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || !lua_isstring(L, 1)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ name = lua_tostring(L, 1);
+ ps = peer_server_find(name);
+ trace(LOG_LUA, "lua_peer_server_find %s %p", name, ps);
+ if(ps == NULL) {
+ lua_pushnil(L);
+ return 1;
+ }
+ lua_push_pse(L, ps);
+ return 1;
+}
+
+static int lua_peer_server_list_entry(PeerServer * ps, void * client_data)
+{
+ lua_State *L = (lua_State *)client_data;
+ lua_push_pse(L, ps);
+ lua_rawseti(L, -2, lua_objlen(L, -2) + 1);
+ return 0;
+}
+
+static int lua_peer_server_list(lua_State *L)
+{
+ assert(L == luastate);
+ if(lua_gettop(L) != 0) {
+ luaL_error(L, "wrong number of arguments");
+ }
+ trace(LOG_LUA, "lua_peer_server_list");
+ lua_newtable(L);
+ peer_server_iter(lua_peer_server_list_entry, L);
+ return 1;
+}
+
+static int lua_peer_server_from_url(lua_State *L)
+{
+ PeerServer *ps;
+ const char *url;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || !lua_isstring(L, 1)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ url = lua_tostring(L, 1);
+ ps = channel_peer_from_url(url);
+ trace(LOG_LUA, "lua_peer_server_from_url %s %p", url, ps);
+ if(ps == NULL) luaL_error(L, "cannot parse url: %s", lua_tostring(L, 1));
+ if(ps->id == NULL) {
+ peer_server_addprop(ps, loc_strdup("ID"), loc_strdup(lua_tostring(L, 1)));
+ }
+ lua_alloc_pse(L, ps);
+ return 1;
+}
+
+static struct protocol_extra *lua_protocol_ref(struct protocol_extra *pe, int index)
+{
+ if(pe->ucnt == 0) {
+ assert(lua_touserdata(pe->L, index) == pe);
+ lua_pushvalue(pe->L, index); /* Prevent GC while connection is active */
+ pe->self_refp = luaref_new(pe->L, pe);
+ }
+ pe->ucnt++;
+ return pe;
+}
+
+static void lua_protocol_unref(struct protocol_extra *pe)
+{
+ assert(pe->ucnt > 0);
+ assert(pe->self_refp != NULL);
+ pe->ucnt--;
+ if(pe->ucnt == 0) {
+ luaref_free(pe->L, pe->self_refp);
+ pe->self_refp = NULL;
+ }
+}
+
+static int lua_protocol_alloc(lua_State *L)
+{
+ struct protocol_extra *pe;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 0) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ trace(LOG_LUA, "lua_protocol_alloc");
+ pe = (struct protocol_extra *)lua_newuserdata(L, sizeof *pe);
+ memset(pe, 0, sizeof *pe);
+ pe->L = L;
+ pe->p = protocol_alloc();
+ luaL_getmetatable(L, "tcf_protocol");
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int lua_channel_server(lua_State *L)
+{
+ trace(LOG_LUA, "lua_channel_server");
+ luaL_error(L, "not implemented");
+ return 0;
+}
+
+
+static void channel_connecting(Channel * c) {
+ struct channel_extra *ce = (struct channel_extra *)c->client_data;
+ lua_State *L = ce->L;
+
+ if(ce->connecting_cbrefp != NULL) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ce->connecting_cbrefp->ref);
+ if(lua_pcall(L, 0, 0, 0) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+ }
+ trace(LOG_LUA, "lua_channel_connecting %p", c);
+ send_hello_message(c);
+}
+
+static void channel_connected(Channel * c) {
+ struct channel_extra *ce = (struct channel_extra *)c->client_data;
+ lua_State *L = ce->L;
+
+ trace(LOG_LUA, "lua_channel_connected %p", c);
+ if(ce->connected_cbrefp != NULL) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ce->connected_cbrefp->ref);
+ if(lua_pcall(L, 0, 0, 0) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+ }
+}
+
+static void channel_receive(Channel * c) {
+ struct channel_extra *ce = (struct channel_extra *)c->client_data;
+ lua_State *L = ce->L;
+
+ trace(LOG_LUA, "lua_channel_receive %p", c);
+ if(ce->receive_cbrefp != NULL) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ce->receive_cbrefp->ref);
+ if(lua_pcall(L, 0, 0, 0) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+ }
+ handle_protocol_message(c);
+}
+
+static void channel_disconnected(Channel * c) {
+ struct channel_extra *ce = (struct channel_extra *)c->client_data;
+ lua_State *L = ce->L;
+
+ trace(LOG_LUA, "lua_channel_disconnected %p", c);
+ if(ce->disconnected_cbrefp != NULL) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ce->disconnected_cbrefp->ref);
+ if(lua_pcall(L, 0, 0, 0) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+ }
+ lua_protocol_unref(ce->pe);
+ ce->pe = NULL;
+ c->client_data = NULL;
+ ce->c = NULL;
+ luaref_owner_free(L, ce);
+}
+
+static void lua_channel_connect_cb(void * client_data, int error, Channel * c)
+{
+ struct channel_extra *ce = (struct channel_extra *)client_data;
+ lua_State *L = ce->L;
+
+ trace(LOG_LUA, "lua_channel_connect_cb %p %d", c, error);
+ assert(ce->connect_cbrefp != NULL);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ce->connect_cbrefp->ref);
+ if(!error) {
+ assert(c != NULL);
+ ce->c = c;
+ c->client_data = ce;
+ c->protocol = ce->pe->p;
+ c->connecting = channel_connecting;
+ c->connected = channel_connected;
+ c->receive = channel_receive;
+ c->disconnected = channel_disconnected;
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ce->self_refp->ref);
+ lua_pushnil(L);
+ } else {
+ assert(c == NULL);
+ luaref_owner_free(L, ce);
+ lua_pushnil(L);
+ lua_pushstring(L, errno_to_str(error));
+ }
+ if(lua_pcall(L, 2, 0, 0) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+}
+
+static int lua_channel_connect(lua_State *L)
+{
+ struct peer_extra *pse = NULL;
+ struct protocol_extra *pe = NULL;
+ struct channel_extra *ce;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 3 ||
+ (pse = lua2peer(L, 1)) == NULL ||
+ (pe = lua2protocol(L, 2)) == NULL ||
+ !lua_isfunction(L, 3)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ trace(LOG_LUA, "lua_channel_connect %p", pse->ps);
+ if(pse->ps == NULL) luaL_error(L, "stale peer");
+ ce = (struct channel_extra *)lua_newuserdata(L, sizeof *ce);
+ memset(ce, 0, sizeof *ce);
+ lua_pushvalue(L, -1); /* Prevent GC while connection is active */
+ ce->self_refp = luaref_new(L, ce);
+ ce->L = L;
+ ce->pe = lua_protocol_ref(pe, 2);
+ luaL_getmetatable(L, "tcf_channel");
+ lua_setmetatable(L, -2);
+ lua_pushvalue(L, 3);
+ ce->connect_cbrefp = luaref_new(L, ce);
+ channel_connect(pse->ps, lua_channel_connect_cb, ce);
+ return 0;
+}
+
+static void lua_post_event_cb(void * client_data)
+{
+ struct post_event_extra *p = (struct post_event_extra *)client_data;
+ lua_State *L = p->L;
+
+ assert(p->handler_refp != NULL);
+ trace(LOG_LUA, "lua_post_event_cb %d", p->handler_refp);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, p->handler_refp->ref);
+ luaref_owner_free(L, p);
+ if(lua_pcall(L, 0, 0, 0) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+}
+
+static int lua_post_event(lua_State *L)
+{
+ struct post_event_extra *p;
+ unsigned long delay;
+
+ assert(L == luastate);
+
+ if(lua_gettop(L) > 2 || !lua_isfunction(L, 1) ||
+ (lua_gettop(L) > 1 && !(lua_isnil(L, 2) || lua_isnumber(L, 2)))) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ p = (struct post_event_extra *)lua_newuserdata(L, sizeof *p);
+ memset(p, 0, sizeof *p);
+ p->L = L;
+ lua_pushvalue(L, -1);
+ p->self_refp = luaref_new(L, p);
+ lua_pushvalue(L, 1);
+ p->handler_refp = luaref_new(L, p);
+ trace(LOG_LUA, "lua_post_event %d", p->handler_refp);
+ luaL_getmetatable(L, "tcf_post_event");
+ lua_setmetatable(L, -2);
+ delay = lua_tointeger(L, 2);
+ if(delay == 0) {
+ post_event(lua_post_event_cb, p);
+ } else {
+ post_event_with_delay(lua_post_event_cb, p, delay);
+ }
+ return 1;
+}
+
+static const luaL_Reg tcffuncs[] = {
+ { "read_command", lua_read_command },
+ { "peer_server_find", lua_peer_server_find },
+ { "peer_server_list", lua_peer_server_list },
+ { "peer_server_from_url",lua_peer_server_from_url },
+ { "protocol_alloc", lua_protocol_alloc },
+ { "channel_server", lua_channel_server },
+ { "channel_connect", lua_channel_connect },
+ { "post_event", lua_post_event },
+ { 0 }
+};
+
+
+static int lua_protocol_tostring(lua_State *L)
+{
+ struct protocol_extra *pe = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (pe = lua2protocol(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ trace(LOG_LUA, "lua_protocol_tostring %p", pe->p);
+ lua_pushfstring(L, "tcf_protocol (%p, %d)", pe, pe->ucnt);
+ return 1;
+}
+
+static int lua_protocol_gc(lua_State *L)
+{
+ struct protocol_extra *pe = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (pe = lua2protocol(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ assert(pe->ucnt == 0);
+ assert(pe->p != NULL);
+ trace(LOG_LUA, "lua_protocol_gc %p", pe->p);
+ protocol_release(pe->p);
+ pe->p = NULL;
+ return 0;
+}
+
+static void protocol_command_handler(char * token, Channel * c, void * client_data) {
+ struct channel_extra *ce = (struct channel_extra *)c->client_data;
+ struct luaref *refp = (struct luaref *)client_data;
+ lua_State *L = ce->L;
+ InputStream * inp = &c->inp;
+ luaL_Buffer msg;
+ int ch;
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, refp->ref);
+ lua_pushstring(L, token);
+ luaL_buffinit(L, &msg);
+ while((ch = read_stream(inp)) >= 0) {
+ luaL_addchar(&msg, ch);
+ }
+ luaL_pushresult(&msg);
+ trace(LOG_LUA, "lua_protocol_command %d %s", refp->ref, lua_tostring(L, -1));
+ if(lua_pcall(L, 2, 0, 0) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+}
+
+static int lua_protocol_command_handler(lua_State *L)
+{
+ struct protocol_extra *pe = NULL;
+ struct luaref *refp;
+ const char *service;
+ const char *name;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 4 || (pe = lua2protocol(L, 1)) == NULL ||
+ !lua_isstring(L, 2) || !lua_isstring(L, 3) ||
+ !lua_isfunction(L, 4)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ lua_pushvalue(L, 4);
+ refp = luaref_new(L, pe);
+ service = lua_tostring(L, 2);
+ name = lua_tostring(L, 3);
+ trace(LOG_LUA, "lua_protocol_command_handler %d %s %s", refp->ref, service, name);
+ add_command_handler2(pe->p, service, name, protocol_command_handler, refp);
+ return 0;
+}
+
+static const luaL_Reg protocolfuncs[] = {
+ { "__tostring", lua_protocol_tostring },
+ { "__gc", lua_protocol_gc },
+ { "command_handler", lua_protocol_command_handler },
+ // { "default_message_handler", lua_protocol_default_message_handler },
+ { 0 }
+};
+
+
+static const char *channel_state_string(Channel * c)
+{
+ if (c == NULL) return "Disconnected";
+ switch(c->state) {
+ case ChannelStateStartWait: return "StartWait";
+ case ChannelStateStarted: return "Started";
+ case ChannelStateHelloSent: return "HelloSent";
+ case ChannelStateHelloReceived: return "HelloReceived";
+ case ChannelStateConnected: return "Connected";
+ case ChannelStateRedirectSent: return "RedirectSent";
+ case ChannelStateRedirectReceived: return "RedirectReceived";
+ case ChannelStateDisconnected: return "Disconnected";
+ default: return "Unknown";
+ }
+}
+
+static int lua_channel_tostring(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (ce = lua2channel(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ trace(LOG_LUA, "lua_channel_tostring %p", ce->c);
+ if(ce->c != NULL) {
+ lua_pushfstring(L, "tcf_channel (%s, %p, %s)", ce->c->peer_name, ce,
+ channel_state_string(ce->c));
+ } else {
+ lua_pushfstring(L, "tcf_channel (<disconnected>, %p)", ce);
+ }
+ return 1;
+}
+
+static int lua_channel_state(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (ce = lua2channel(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ trace(LOG_LUA, "lua_channel_state %p", ce->c);
+ lua_pushstring(L, channel_state_string(ce->c));
+ return 1;
+}
+
+static int lua_channel_close(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (ce = lua2channel(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ trace(LOG_LUA, "lua_channel_close %p", ce->c);
+ if(ce->c == NULL) luaL_error(L, "disconnected channel");
+ channel_close(ce->c);
+ return 0;
+}
+
+static void update_callback(lua_State *L, int index, struct luaref **cbrefpp, void * owner) {
+ if(!lua_isfunction(L, index) && !lua_isnil(L, index)) {
+ luaL_error(L, "handler must be function or nil");
+ }
+ if(*cbrefpp != NULL) {
+ luaref_free(L, *cbrefpp);
+ *cbrefpp = NULL;
+ }
+ if(lua_isfunction(L, index)) {
+ lua_pushvalue(L, index);
+ *cbrefpp = luaref_new(L, owner);
+ }
+}
+
+static int lua_channel_connecting_handler(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 2 || (ce = lua2channel(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(ce->c == NULL) luaL_error(L, "disconnected channel");
+ update_callback(L, 2, &ce->connecting_cbrefp, ce);
+ trace(LOG_LUA, "lua_channel_connecting_handler %p", ce->c, ce->connecting_cbrefp->ref);
+ return 0;
+}
+
+static int lua_channel_connected_handler(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 2 || (ce = lua2channel(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(ce->c == NULL) luaL_error(L, "disconnected channel");
+ update_callback(L, 2, &ce->connected_cbrefp, ce);
+ trace(LOG_LUA, "lua_channel_connected_handler %p", ce->c, ce->connected_cbrefp->ref);
+ return 0;
+}
+
+static int lua_channel_receive_handler(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 2 || (ce = lua2channel(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(ce->c == NULL) luaL_error(L, "disconnected channel");
+ update_callback(L, 2, &ce->receive_cbrefp, ce);
+ trace(LOG_LUA, "lua_channel_receive_handler %p", ce->c, ce->receive_cbrefp->ref);
+ return 0;
+}
+
+static int lua_channel_disconnected_handler(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 2 || (ce = lua2channel(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(ce->c == NULL) luaL_error(L, "disconnected channel");
+ update_callback(L, 2, &ce->disconnected_cbrefp, ce);
+ trace(LOG_LUA, "lua_channel_disconnected_handler %p", ce->c, ce->disconnected_cbrefp->ref);
+ return 0;
+}
+
+static void channel_event_handler(Channel * c, void * client_data) {
+ struct channel_extra *ce = (struct channel_extra *)c->client_data;
+ struct luaref *refp = (struct luaref *)client_data;
+ lua_State *L = ce->L;
+ InputStream * inp = &c->inp;
+ luaL_Buffer msg;
+ int ch;
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, refp->ref);
+ luaL_buffinit(L, &msg);
+ while((ch = read_stream(inp)) >= 0) {
+ luaL_addchar(&msg, ch);
+ }
+ luaL_pushresult(&msg);
+ trace(LOG_LUA, "lua_channel_event %p %d %s", c, refp->ref, lua_tostring(L, -1));
+ if(lua_pcall(L, 1, 0, 0) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+}
+
+static int lua_channel_event_handler(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+ struct luaref *refp;
+ const char *service;
+ const char *name;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 4 || (ce = lua2channel(L, 1)) == NULL ||
+ !lua_isstring(L, 2) || !lua_isstring(L, 3) ||
+ !lua_isfunction(L, 4)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(ce->c == NULL) luaL_error(L, "disconnected channel");
+ lua_pushvalue(L, 4);
+ refp = luaref_new(L, ce);
+ service = lua_tostring(L, 2);
+ name = lua_tostring(L, 3);
+ trace(LOG_LUA, "lua_channel_event_handler %p %s %s %d", ce->c, service, name, refp->ref);
+ add_event_handler2(ce->c, service, name, channel_event_handler, refp);
+ return 0;
+}
+
+static int lua_channel_start(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (ce = lua2channel(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(ce->c == NULL) luaL_error(L, "disconnected channel");
+ trace(LOG_LUA, "lua_channel_start %p", ce->c);
+ channel_start(ce->c);
+ return 0;
+}
+
+static int lua_channel_send_message(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+ OutputStream *out;
+ const char *s;
+ size_t l;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 2 ||
+ (ce = lua2channel(L, 1)) == NULL ||
+ !lua_isstring(L, 2)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(ce->c == NULL) luaL_error(L, "disconnected channel");
+
+ s = lua_tolstring(L, 2, &l);
+ trace(LOG_LUA, "lua_channel_send_message %p %.*s", ce->c, l, s);
+ out = &ce->c->out;
+ while(l-- > 0) {
+ write_stream(out, (*s++) & 0xff);
+ }
+ write_stream(out, MARKER_EOM);
+ return 0;
+}
+
+static void channel_send_command_cb(Channel * c, void * client_data, int error)
+{
+ struct channel_extra *ce = (struct channel_extra *)c->client_data;
+ struct command_extra *cmd = (struct command_extra *)client_data;
+ lua_State *L = ce->L;
+ InputStream * inp = &c->inp;
+ luaL_Buffer msg;
+ int ch;
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, cmd->result_cbrefp->ref);
+ if(!error) {
+ luaL_buffinit(L, &msg);
+ while((ch = read_stream(inp)) >= 0) {
+ luaL_addchar(&msg, ch);
+ }
+ luaL_pushresult(&msg);
+ lua_pushnil(L);
+ trace(LOG_LUA, "lua_channel_send_command_reply %p %d %s", c, cmd->result_cbrefp->ref, lua_tostring(L, -2));
+ } else {
+ lua_pushnil(L);
+ lua_pushstring(L, errno_to_str(error));
+ trace(LOG_LUA, "lua_channel_send_command_reply %p %d error %d", c, cmd->result_cbrefp->ref, error);
+ }
+ if(lua_pcall(L, 2, 0, 0) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+ luaref_owner_free(L, cmd);
+}
+
+static int lua_channel_send_command(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+ struct command_extra *cmd;
+ OutputStream *out;
+ const char *s;
+ size_t l;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 5 ||
+ (ce = lua2channel(L, 1)) == NULL ||
+ !lua_isstring(L, 2) ||
+ !lua_isstring(L, 3) ||
+ !lua_isstring(L, 4) ||
+ !lua_isfunction(L, 5)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(ce->c == NULL) luaL_error(L, "disconnected channel");
+
+ /* Object to track outstanding command */
+ cmd = (struct command_extra *)lua_newuserdata(L, sizeof *cmd);
+ memset(cmd, 0, sizeof *cmd);
+ luaL_getmetatable(L, "tcf_command");
+ lua_setmetatable(L, -2);
+
+ /* Make sure GC don't free until reply is received */
+ lua_pushvalue(L, -1);
+ cmd->self_refp = luaref_new(L, cmd);
+ lua_pushvalue(L, 5);
+ cmd->result_cbrefp = luaref_new(L, cmd);
+
+ /* Send command header */
+ cmd->replyinfo = protocol_send_command(ce->c,
+ lua_tostring(L, 2),
+ lua_tostring(L, 3),
+ channel_send_command_cb, cmd);
+ s = lua_tolstring(L, 4, &l);
+ trace(LOG_LUA, "lua_channel_send_command %p %d %.*s", ce->c, cmd->result_cbrefp->ref, l, s);
+ out = &ce->c->out;
+ while(l-- > 0) {
+ write_stream(out, (*s++) & 0xff);
+ }
+ write_stream(out, MARKER_EOM);
+ return 1;
+}
+
+static int lua_channel_cancel_command(lua_State *L)
+{
+ trace(LOG_LUA, "lua_channel_cancel_command");
+ luaL_error(L, "not implemented");
+ return 0;
+}
+
+static void channel_redirect_cb(Channel * c, void * client_data, int error)
+{
+ struct channel_extra *ce = (struct channel_extra *)c->client_data;
+ struct command_extra *cmd = (struct command_extra *)client_data;
+ lua_State *L = ce->L;
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, cmd->result_cbrefp->ref);
+ if(!error) {
+ lua_pushnil(L);
+ trace(LOG_LUA, "lua_channel_redirect_reply %p %d %s", c, cmd->result_cbrefp->ref, lua_tostring(L, -2));
+ } else {
+ lua_pushstring(L, errno_to_str(error));
+ trace(LOG_LUA, "lua_channel_redirect_reply %p %d error %d", c, cmd->result_cbrefp->ref, error);
+ }
+ if(lua_pcall(L, 1, 0, 0) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+ luaref_owner_free(L, cmd);
+}
+
+static int lua_channel_redirect(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+ struct command_extra *cmd;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 3 ||
+ (ce = lua2channel(L, 1)) == NULL ||
+ !lua_isstring(L, 2) ||
+ !lua_isfunction(L, 3)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(ce->c == NULL) luaL_error(L, "disconnected channel");
+
+ /* Object to track outstanding command */
+ cmd = (struct command_extra *)lua_newuserdata(L, sizeof *cmd);
+ memset(cmd, 0, sizeof *cmd);
+ luaL_getmetatable(L, "tcf_command");
+ lua_setmetatable(L, -2);
+
+ /* Make sure GC don't free until reply is received */
+ lua_pushvalue(L, -1);
+ cmd->self_refp = luaref_new(L, cmd);
+ lua_pushvalue(L, 3);
+ cmd->result_cbrefp = luaref_new(L, cmd);
+
+ /* Send command header */
+ cmd->replyinfo = send_redirect_command(ce->c,
+ lua_tostring(L, 2),
+ channel_redirect_cb, cmd);
+ trace(LOG_LUA, "lua_channel_redirect %p %d %s", ce->c, cmd->result_cbrefp->ref, lua_tostring(L, 2));
+ return 1;
+}
+
+static int lua_channel_get_services(lua_State *L)
+{
+ struct channel_extra *ce = NULL;
+ int i;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 ||
+ (ce = lua2channel(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(ce->c == NULL) luaL_error(L, "disconnected channel");
+ trace(LOG_LUA, "lua_channel_get_services %p", ce->c);
+ lua_newtable(L);
+ for (i = 0; i < ce->c->peer_service_cnt; i++) {
+ lua_pushstring(L, ce->c->peer_service_list[i]);
+ lua_rawseti(L, -2, i + 1);
+ }
+ return 1;
+}
+
+static const luaL_Reg channelfuncs[] = {
+ { "__tostring", lua_channel_tostring },
+ { "state", lua_channel_state },
+ { "close", lua_channel_close },
+ { "connecting_handler", lua_channel_connecting_handler },
+ { "connected_handler", lua_channel_connected_handler },
+ { "receive_handler", lua_channel_receive_handler },
+ { "disconnected_handler",lua_channel_disconnected_handler },
+ { "event_handler", lua_channel_event_handler },
+ { "start", lua_channel_start },
+ { "send_message", lua_channel_send_message },
+ { "send_command", lua_channel_send_command },
+ { "cancel_command", lua_channel_cancel_command },
+ { "redirect", lua_channel_redirect },
+ { "get_services", lua_channel_get_services },
+ { 0 }
+};
+
+static int lua_peer_tostring(lua_State *L)
+{
+ struct peer_extra *pse = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (pse = lua2peer(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ trace(LOG_LUA, "lua_peer_tostring %p", pse->ps);
+ lua_pushfstring(L, "tcf_peer (%s, %p)", pse->ps ? pse->ps->id : "<stale>", pse);
+ return 1;
+}
+
+static int lua_peer_gc(lua_State *L)
+{
+ struct peer_extra *pse = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (pse = lua2peer(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(pse->managed == 0) {
+ trace(LOG_LUA, "lua_peer_gc %p", pse->ps);
+ peer_server_free(pse->ps);
+ pse->ps = NULL;
+ }
+ return 0;
+}
+
+static int lua_peer_getid(lua_State *L)
+{
+ struct peer_extra *pse = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (pse = lua2peer(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(pse->ps == NULL) luaL_error(L, "stale peer");
+ trace(LOG_LUA, "lua_peer_getid %p", pse->ps);
+ lua_pushstring(L, pse->ps->id);
+ return 1;
+}
+
+static int lua_peer_getnames(lua_State *L)
+{
+ int i;
+ struct peer_extra *pse = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (pse = lua2peer(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(pse->ps == NULL) luaL_error(L, "stale peer");
+ trace(LOG_LUA, "lua_peer_getnames %p", pse->ps);
+ lua_createtable(L, pse->ps->ind, 0);
+ for(i = 0; i < pse->ps->ind; i++) {
+ lua_pushstring(L, pse->ps->list[i].name);
+ lua_rawseti(L, -2, i+1);
+ }
+ return 1;
+}
+
+static int lua_peer_getvalue(lua_State *L)
+{
+ struct peer_extra *pse = NULL;
+ const char *s;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 2 ||
+ (pse = lua2peer(L, 1)) == NULL ||
+ !lua_isstring(L, 2)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(pse->ps == NULL) luaL_error(L, "stale peer");
+ trace(LOG_LUA, "lua_peer_getvalue %p", pse->ps);
+ if((s = peer_server_getprop(pse->ps, lua_tostring(L, 2), NULL)) == NULL) {
+ lua_pushnil(L);
+ return 1;
+ }
+ lua_pushstring(L, s);
+ return 1;
+}
+
+static int lua_peer_setvalue(lua_State *L)
+{
+ struct peer_extra *pse = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 3 || (pse = lua2peer(L, 1)) == NULL ||
+ !lua_isstring(L, 2) || !lua_isstring(L, 3)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(pse->ps == NULL) luaL_error(L, "stale peer");
+ trace(LOG_LUA, "lua_peer_setvalue %p", pse->ps);
+ peer_server_addprop(pse->ps, loc_strdup(lua_tostring(L, 2)), loc_strdup(lua_tostring(L, 3)));
+ return 0;
+}
+
+static int lua_peer_getflags(lua_State *L)
+{
+ struct peer_extra *pse = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (pse = lua2peer(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(pse->ps == NULL) luaL_error(L, "stale peer");
+ trace(LOG_LUA, "lua_peer_getflags %p", pse->ps);
+ lua_createtable(L, 0, 0);
+ if(pse->ps->flags & PS_FLAG_LOCAL) {
+ lua_pushstring(L, "local");
+ lua_pushboolean(L, 1);
+ lua_rawset(L, -3);
+ }
+ if(pse->ps->flags & PS_FLAG_PRIVATE) {
+ lua_pushstring(L, "private");
+ lua_pushboolean(L, 1);
+ lua_rawset(L, -3);
+ }
+ if(pse->ps->flags & PS_FLAG_DISCOVERABLE) {
+ lua_pushstring(L, "discoverable");
+ lua_pushboolean(L, 1);
+ lua_rawset(L, -3);
+ }
+ return 1;
+}
+
+static int lua_peer_setflags(lua_State *L)
+{
+ struct peer_extra *pse = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 2 || (pse = lua2peer(L, 1)) == NULL ||
+ !lua_istable(L, 2)) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ if(pse->ps == NULL) luaL_error(L, "stale peer");
+ trace(LOG_LUA, "lua_peer_setflags %p", pse->ps);
+ lua_pushnil(L);
+ while(lua_next(L, 2) != 0) {
+ if(lua_isstring(L, -2)) {
+ if(strcmp(lua_tostring(L, -2), "local") == 0) {
+ if(lua_toboolean(L, 2)) {
+ pse->ps->flags |= PS_FLAG_LOCAL;
+ } else {
+ pse->ps->flags &= ~PS_FLAG_LOCAL;
+ }
+ } else if(strcmp(lua_tostring(L, -2), "private") == 0) {
+ if(lua_toboolean(L, 2)) {
+ pse->ps->flags |= PS_FLAG_PRIVATE;
+ } else {
+ pse->ps->flags &= ~PS_FLAG_PRIVATE;
+ }
+ } else if(strcmp(lua_tostring(L, -2), "discoverable") == 0) {
+ if(lua_toboolean(L, 2)) {
+ pse->ps->flags |= PS_FLAG_DISCOVERABLE;
+ } else {
+ pse->ps->flags &= ~PS_FLAG_DISCOVERABLE;
+ }
+ }
+ }
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+ return 0;
+}
+
+static const luaL_Reg peerfuncs[] = {
+ { "__tostring", lua_peer_tostring },
+ { "__gc", lua_peer_gc },
+ { "getid", lua_peer_getid },
+ { "getnames", lua_peer_getnames },
+ { "getvalue", lua_peer_getvalue },
+ { "setvalue", lua_peer_setvalue },
+ { "getflags", lua_peer_getflags },
+ { "setflags", lua_peer_setflags },
+ { 0 }
+};
+
+static int lua_post_event_tostring(lua_State *L)
+{
+ struct post_event_extra *p = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (p = lua2postevent(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ trace(LOG_LUA, "lua_post_event_tostring %p", p);
+ lua_pushfstring(L, "tcf_post_event (%s, %p)", p->handler_refp ? "pending" : "stale", p);
+ return 1;
+}
+
+static int lua_post_event_cancel(lua_State *L)
+{
+ struct post_event_extra *p = NULL;
+
+ assert(L == luastate);
+ if(lua_gettop(L) != 1 || (p = lua2postevent(L, 1)) == NULL) {
+ luaL_error(L, "wrong number or type of arguments");
+ }
+ trace(LOG_LUA, "lua_post_event_cancel %p", p);
+ p->self_refp = NULL;
+ p->handler_refp = NULL;
+ luaref_owner_free(L, p);
+ cancel_event(lua_post_event_cb, p, 0);
+ return 0;
+}
+
+static const luaL_Reg posteventfuncs[] = {
+ { "__tostring", lua_post_event_tostring },
+ { "cancel", lua_post_event_cancel },
+ { 0 }
+};
+
+
+/*
+ * main entry point for TCF client
+ *
+ * Command line options:
+ * -L <log_file> : specify a log file
+ * -l <log_mode> : logging level see trace.c for more details
+ * -S <script_file> : script of commands to run
+ */
+
+#if defined(_WRS_KERNEL)
+int tcf_lua(void) {
+#else
+int main(int argc, char ** argv) {
+#endif
+ int c;
+ int ind;
+ int error;
+ const char * log_name = "-";
+ const char * script_name = NULL;
+ char * engine_name;
+ lua_State *L;
+
+ log_mode = 0;
+
+#ifndef WIN32
+ signal(SIGPIPE, SIG_IGN);
+#endif
+ ini_mdep();
+ ini_trace();
+ ini_events_queue();
+ ini_asyncreq();
+
+#if defined(_WRS_KERNEL)
+
+ progname = "tcf";
+ open_log_file("-");
+
+#else
+
+ progname = argv[0];
+
+ /* Parse arguments */
+ for (ind = 1; ind < argc; ind++) {
+ const char * s = argv[ind];
+ if (*s != '-') {
+ break;
+ }
+ s++;
+ while ((c = *s++) != '\0') {
+ switch (c) {
+ case 'l':
+ case 'L':
+ case 'S':
+ if (*s == '\0') {
+ if (++ind >= argc) {
+ fprintf(stderr, "%s: error: no argument given to option '%c'\n", progname, c);
+ exit(1);
+ }
+ s = argv[ind];
+ }
+ switch (c) {
+ case 'l':
+ log_mode = strtol(s, 0, 0);
+ break;
+
+ case 'L':
+ log_name = s;
+ break;
+
+ case 'S':
+ script_name = s;
+ break;
+
+ default:
+ fprintf(stderr, "%s: error: illegal option '%c'\n", progname, c);
+ exit(1);
+ }
+ s = "";
+ break;
+
+ default:
+ fprintf(stderr, "%s: error: illegal option '%c'\n", progname, c);
+ exit(1);
+ }
+ }
+ }
+ if (ind >= argc) {
+ fprintf(stderr, "%s: error: no Lua script specified\n", progname);
+ exit(1);
+ }
+ engine_name = argv[ind++];
+ if (ind < argc) {
+ fprintf(stderr, "%s: error: too many arguments\n", progname);
+ exit(1);
+ }
+
+ open_log_file(log_name);
+
+#endif
+
+ if (script_name != NULL) {
+ if((lua_read_command_state.req.u.fio.fd = open(script_name, O_RDONLY, 0)) < 0) {
+ fprintf(stderr, "%s: error: cannot open script: %s\n", progname, script_name);
+ exit(1);
+ }
+ } else {
+ lua_read_command_state.req.u.fio.fd = fileno(stdin);
+ }
+
+ discovery_start();
+
+ if((luastate = L = luaL_newstate()) == NULL) {
+ fprintf(stderr, "error from luaL_newstate\n");
+ exit(1);
+ }
+ luaL_openlibs(L);
+
+ luaL_register(L, "tcf", tcffuncs);
+ lua_pop(L, 1);
+
+ /* Peer metatable */
+ luaL_newmetatable(L, "tcf_peer");
+ luaL_register(L, NULL, peerfuncs);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -1, "__index"); /* m.__index = m */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -1, "__metatable"); /* m.__metatable = m */
+ lua_pop(L, 1);
+
+ /* Protocol metatable */
+ luaL_newmetatable(L, "tcf_protocol");
+ luaL_register(L, NULL, protocolfuncs);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -1, "__index"); /* m.__index = m */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -1, "__metatable"); /* m.__metatable = m */
+ lua_pop(L, 1);
+
+ /* Channel metatable */
+ luaL_newmetatable(L, "tcf_channel");
+ luaL_register(L, NULL, channelfuncs);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -1, "__index"); /* m.__index = m */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -1, "__metatable"); /* m.__metatable = m */
+ lua_pop(L, 1);
+
+ /* Post event metatable */
+ luaL_newmetatable(L, "tcf_post_event");
+ luaL_register(L, NULL, posteventfuncs);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -1, "__index"); /* m.__index = m */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -1, "__metatable"); /* m.__metatable = m */
+ lua_pop(L, 1);
+
+ lua_newtable(L); /* peers = {} */
+ lua_newtable(L); /* m = {} */
+ lua_pushstring(L, "v"); /* Values are weak */
+ lua_setfield(L, -2, "__mode"); /* m.__mode = "v" */
+ lua_setmetatable(L, -2); /* setmetatable(peer, m) */
+ peers_refp = luaref_new(L, NULL);
+ peer_server_add_listener(peer_server_changes, L);
+
+ if((error = luaL_loadfile(L, engine_name)) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+
+ if((error = lua_pcall(L, 0, LUA_MULTRET, 0)) != 0) {
+ fprintf(stderr, "%s\n", lua_tostring(L,1));
+ exit(1);
+ }
+
+ /* Process events - must run on the initial thread since ptrace()
+ * returns ECHILD otherwise, thinking we are not the owner. */
+ run_event_loop();
+
+ lua_close(L);
+ return 0;
+}
+
+#else /* ENABLE_LUA */
+
+#if defined(_WRS_KERNEL)
+int tcf_lua(void) {
+#else
+int main(int argc, char ** argv) {
+#endif
+ fprintf(stderr, "Agent was built without LUA support\n");
+ return 1;
+}
+
+#endif /* ENABLE_LUA */

Back to the top