LuaFlexible

Introducción

LuaFlexible es una biblioteca, programada en C, diseñada para servir de pasarela entre Lua y C. La idea es tener una pasarela que permita poder registrar, desde lua, y por lo tanto sin necesidad de compilación, diferentes bibliotecas y los símbolos que éstas contienen (variables globales o funciones). Pudiendo invocar a dichas funciones o manipular las variables directamente desde Lua.
Para esto se utiliza la API estándar de Lua, que sirve de interfaz entre Lua y C.

Se decidió codificarla en inglés, con la idea de compartirla con la comunidad Lua una vez finalizada, aunque al final se vió que ya existía una solución similar en dicha comunidad. Se dicidió finalmente incorporar esta otra solución, llamada C/Invoke, debido a que era más completa, sin embargo, se consiguió desarrollar LuaFlexible hasta un punto que satisfacía todas las necesidades del proyecto.

Desarrollo

Como se ha dicho anteriormente, esta biblioteca ha sido programada en C. Se ha dividido el código en dos módulos, según las funcionalidades que proporcionaban.

  1. El primer módulo, llamado dllHandler, proporciona operaciones de manejo de bibliotecas de bajo nivel, como son:
    • Obtener la referencia de una biblioteca.
    • Liberar una referencia de una biblioteca.
    • Obtener un símbolo de una biblioteca.
    • Invocar a un símbolo de una biblioteca (para símbolos de funciones).
    • Obtener el valor de un símbolo de una biblioteca (para símbolos de variables).
    • Fijar el valor de un símbolo de una biblioteca (para símbolos de variables).
  2. El segundo módulo, llamado luaFlexible, utiliza la funcionalidad del primero para ofrecer operaciones de más alto nivel, éstas son:
    • Registrar una función. La forma de invocar a una función registrada por este método es equivalente a invocar cualquier función de Lua.
    • Registrar una variable. Además, se crean dos funciones asociadas a una variable registrada por este método, una para obtener su valor y otra para fijarlo.

Desde Lua se puede hacer uso de cualquiera de estos dos niveles, según se prefiera en cada caso.

Manual de Referencia

  • require(“luaFlexible”) Lo primero de todo es importar la biblioteca.
  • luaFlexible.openLib(l) Obtiene una referencia a la biblioteca con nombre l. Si tiene éxito devuelve la refencia. En caso de error devuelve nil y el error producido.

Operaciones de bajo nivel, pertenecientes al módulo dllHandler:

  • lib:getRef(s) Donde lib es una referencia obtenida con luaFlexible.openLib, y s es un string. Busca en la biblioteca lib el símbolo s y devuelve su referencia. En caso de error devuelve nil y el error producido.
  • lib.callRef(r[type, args…]) [sólo símbolos de función] Donde lib es una referencia obtenida con luaFlexible.openLib y r es una referencia obtenida con getRef. type es un string que define el tipo del valor de retorno, el cual puede ser {“nil”,”int”,”string”}, si no especifica se presupone “int”. Invoca a la función referenciada por r con los argumentos args y devuelve aquello que devuelva la función.
  • lib.getValue(r,type) [sólo símbolos de variable] Obtiene el valor del símbolo referenciado por r. type es un string que define el tipo de la variable, el cual puede ser {“nil”,”int”,”string”}, si no especifica se presupone “int”.
  • lib.setValue(r,value) [sólo símbolos de variable] Fija el valor del símbolo referenciado por r.

Operaciones de alto nivel, pertenecientes al módulo luaFlexible:

  • lib:registerFunction(s,type) Registra una función con el símbolo s. type es un string que define el tipo del valor de retorno, el cual puede ser {“nil”,”int”,”string”}, si no especifica se presupone “int”. Devuelve true si la operación ha sido satisfactoria, o nil y un error en caso contrario. Una vez que una función ha sido registrada se puede invocar de la siguiente forma:
    • lib.s([args…]) Donde s es el nombre del símbolo.
  • lib:registerValue(s,type) Registra una variable con el símbolo s. type es un string que define el tipo de la variable, el cual puede ser {“nil”,”int”,”string”}, si no especifica se presupone “int”. Una vez que una variable ha sido registrada se puede acceder de la siguiente forma:
    • lib.s:getValue() Donde s es el nombre del símbolo.
    • lib.s:setValue(value) Donde s es el nombre del símbolo.

Ejemplos

A continuación se muestran algunos ejemplos de cómo utilizar esta biblioteca, tanto a bajo como a alto nivel. Las funciones utilizadas en estos ejemplos son las descritas anteriormente.

Ejemplo 1

Este primer ejemplo es un código sencillo que obtiene el PID del proceso, utilizando las funcionalidades de bajo nivel. Primero se carga la biblioteca de C (libc), localizada en la ruta /lib/libc-2.7.so mediante luaFlexible.openLib (Nota: el nombre puede cambiar según el sistema). A continuación se obtiene de dicha biblioteca la llamada al sistema getpid haciendo uso de la función libc:getRef explicada anteriormente. Por último se invoca a la referencia obtenida mediante libc.callRef y se imprime su resultado.

require("luaFlexible");
 
print("Loading libc library...");
libc, err = luaFlexible.openLib("/lib/libc-2.7.so");
if (libc == nil) then
	print("Libc loading failed: " .. err);
	os.exit();
else
	print("Libc loaded correctly");
end
 
print("\nGetting reference for getpid() C function...");
refgetpid, err = libc:getRef("getpid");
if (refgetpid == nil) then
	print("getpid reference error: " .. err);
	os.exit();
end
 
print("\nCalling getpid()...");
pid = libc.callRef(refgetpid);
 
print("getpid() result: " .. pid);

Ejemplo 2

Este ejemplo es similar al anterior, pero se ha utilizado la interfaz de alto nivel. Primero se carga la biblioteca libc al igual que en el caso anterior. A continuación se registra la función getpid mediante libc:registerFunction y por último se invoca de igual manera que si se tratase de una función Lua: libc.getpid().

require("luaFlexible");
 
print("Loading libc library...");
libc, err = luaFlexible.openLib("/lib/libc-2.7.so");
if (libc == nil) then
	print("Libc loading failed: " .. err);
	os.exit();
else
	print("Libc loaded correctly");
end
print("");
 
print("Getting reference for getpid() C function...");
res, err = libc:registerFunction("getpid","int");
if (res == nil) then
	print("getpid reference error: " .. err);
	os.exit();
end
 
print("Calling getpid()...");
pid=libc.getpid();
 
print("getpid() result: " .. pid);

Ejemplo 3

Aquí se muestra cómo se puede hacer referencia a variables globales de otras bibliotecas. En este ejemplo se hará referencia a la variable errno. Para poder tener un valor hemos generado un error de “descriptor incorrecto” al intentar hacer un write sobre el descriptor -1.

require("luaFlexible");
 
print("Loading libc library...");
libc, err = luaFlexible.openLib("/lib/libc-2.7.so");
if (libc == nil) then
	print("Libc loading failed: " .. err);
	os.exit();
else
	print("Libc loaded correctly");
end
print("");
 
res, err = libc:registerFunction("write","int");
res, err = libc:registerFunction("strerror","string");
res, err = libc:registerValue("errno","int");
 
res=libc.write(-1, "hello", 5);
print("Result from write: " .. res);
err=libc.errno:getValue();
print("Errno: " .. err);
print("Error: " .. libc.strerror(err));

Ejemplo 4

En este último ejemplo se mostrará un esquema muy conocido al programar en C: un proceso hace un fork; el proceso hijo pasa a ejecutar otro programa mediante un exec y el padre espera por el hijo con wait.

require("luaFlexible");
 
print("Loading libc library...");
libc, err = luaFlexible.openLib("/lib/libc-2.7.so");
if (libc == nil) then
	print("Libc loading failed: " .. err);
	os.exit();
else
	print("Libc loaded correctly");
end
print("");
 
libc:registerFunction("fork","int");
libc:registerFunction("execl","int");
libc:registerFunction("wait","int");
 
pid=libc.fork();
if (pid == 0) then
	print("Children executing 'ls -lah'");
	libc.execl("/bin/ls","/bin/ls","-lah",nil);
else
	print("Father waiting for child");
	libc.wait(nil);
	print("Children ended");
end

Instalación

Se ha creado un paquete con el código fuente y los ejemplos mostrados, el cual se puede descargar aquí: luaFlexible

A continuación se muestra cómo compilar el paquete e instalarlo en el router:

wget http://laurel.datsi.fi.upm.es/_media/proyectos/teldatsi/luaflexible.tar
tar -xvpf luaflexible.tar
cd luaFlexible
make CC=powerpc-linux-gcc
sudo cp luaFlexible.so /NFSroot/usr/local/lib/lua/5.1/
 
proyectos/teldatsi/luaflexible.txt · Última modificación: 2012/10/08 17:58 (editor externo)
 
Recent changes RSS feed Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki