blob: 090656f072d2900d3680f271c5d775cad065ba0f [file] [log] [blame]
/*******************************************************************************
* 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.
*
* 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
*
* The client is a simple shell permitting communication with the TCF agent.
* By default the client will run in interactive mode. The client accepts
* 3 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 - non-interactive mode
*/
#if defined(_WRS_KERNEL)
int tcf_lua(void) {
#else
int main(int argc, char ** argv) {
#endif
int c;
int ind;
int error;
int interactive = 1;
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 'b':
interactive = 0;
break;
case 'i':
interactive = 1;
break;
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;
interactive = 0;
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 */