2012-03-02 17 views
11

El código relacionado con esta cuestión está aquí: https://github.com/jchester/lua-polarssl/tree/master/srcEnvolviendo una biblioteca C para Lua: ¿cómo creo tablas anidadas de funciones?

Actualmente estoy tratando de envolver una parte de la biblioteca PolarSSL (http://polarssl.org) que me diera acceso a SHA-512 HMAC (luacrypto hace no proporcionar esto).

La API estoy apuntando para es de la forma:

a_sha512_hash = polarssl.hash.sha512('text') 

o más plenamente

local polarssl = require 'polarssl' 
local hash = polarssl.hash 

a_sha512_hash = hash.sha512('test') 

Si se refiere a polarssl.c en el enlace anterior, verá que Tiene funciones escritas que envuelven el código PolarSSL. Entonces estoy tratando de construir las tablas de funciones así:

LUA_API int luaopen_polarssl(lua_State *L) { 
    static const struct luaL_Reg core[] = { 
    { NULL, NULL } 
    }; 

    static const struct luaL_Reg hash_functions[] = { 
    { "sha512", hash_sha512 }, 
    { "sha384", hash_sha384 }, 
    { NULL, NULL } 
    }; 

    static const struct luaL_Reg hmac_functions[] = { 
    { "sha512", hmac_sha512 }, 
    { "sha384", hmac_sha384 }, 
    { NULL, NULL } 
    }; 

    luaL_register(L, CORE_MOD_NAME, core); 
    luaL_register(L, HASH_MOD_NAME, hash_functions); 
    luaL_register(L, HMAC_MOD_NAME, hmac_functions); 

    return 1; 
} 

Dónde CORE_MOD_NAME = 'polarssl', HASH_MOD_NAME = 'polarssl.hash', HMAC_MOD_NAME = 'polarssl.hmac'.

Cuando ejecuto un script de prueba similar al código Lua en la parte superior de esta pregunta, me sale esto:

lua: test.lua:23: attempt to index global 'polarssl' (a nil value) 
stack traceback: 
    test.lua:23: in main chunk 
    [C]: ? 

He intentado buscar ejemplos de cómo lograr este enfoque module.submodule (por ejemplo, naim vs luasockets), pero todos parecen tener una forma diferente de lograrlo. Estoy completamente perdido.

+0

No puedo enlazar con naim y luasockets porque alcanzo el límite de <10 puntos en los enlaces. –

+0

Parece que el karma se entrega como deliciosos caramelos, así que actualiza la publicación con enlaces. –

Respuesta

14

todos parecen tener una forma diferente de lograrlo.

That's Lua; todos lo hacen a su manera. Es la mayor fortaleza y la mayor debilidad de Lua: el lenguaje proporciona mecanismos, no políticas.

Lo primero que debe hacer es dejar de usar luaL_register. Sí, sé que es conveniente. Pero quiere algo especial, y luaL_register no lo ayudará a conseguirlo.

Lo que desea es crear una tabla que contenga una tabla que contenga una o más funciones. Entonces ... haz eso.

Crear una tabla.

lua_newtable(L); 

Eso fue fácil. La función empuja una mesa a la pila, por lo que ahora nuestra pila tiene una mesa encima. Esta es la tabla que volveremos.

Ahora, tenemos que crear una nueva tabla para entrar en la anterior.

lua_newtable(L); 

De nuevo, fácil. Luego, queremos poner la función que queremos ingresar en esa tabla en la pila.

lua_pushcfunction(L, hash_sha512); 

Así que la pila tiene tres cosas: la tabla de destino, la tabla de "control" (vamos a llegar a "nombrar" en un segundo), y la función que queremos poner en el "control" mesa.

Ponga la función en la tabla hash.

lua_setfield(L, -2, "sha512"); 

Esto toma lo que está en la parte superior de la pila y la coloca en el campo denominado "sha512" sobre la mesa en el índice de -2 en la pila. Ahí es donde está nuestra tabla "hash". Una vez completada esta función, elimina el elemento superior de la pila. Esto deja la tabla "hash" en la parte superior.

Podemos repetir el proceso para la segunda función:

lua_pushcfunction(L, hash_sha384); 
lua_setfield(L, -2, "sha384"); 

Ahora, queremos poner la mesa "control" en la tabla queremos volver. Eso se hace con bastante facilidad con otra lua_setfield llamada:

lua_setfield(L, -2, "hash"); 

Recuerde: esta función toma lo es en la parte superior de la pila. En este punto, la tabla que queremos devolver (que será la tabla de nuestro módulo) está en la pila.

Podemos repetir este proceso para la tabla "hmac":

lua_newtable(L); //Create "hmac" table 
lua_pushcfunction(L, hmac_sha512); 
lua_setfield(L, -2, "sha512"); 
lua_pushcfunction(L, hmac_sha384); 
lua_setfield(L, -2, "sha384"); 
lua_setfield(L, -2, "hmac"); //Put the "hmac" table into our module table 

La mesa del módulo tiene ahora dos entradas en él: "control" y "hmac". Ambas son tablas con dos funciones en ellas.

Podemos meterlo en la tabla global con esto:

lua_pushvalue(L, -1); 
lua_setfield(L, LUA_GLOBALSINDEX, "polarssl"); 

No todos los fabricantes de módulo quiere hacer eso. Algunos prefieren forzar a las personas a usar la sintaxis local polarssl = require "polarssl" para evitar contaminar el espacio de nombres global. Tu decides.

Pero lo que debe hacer de cualquier manera es devolver esta tabla. Devuelve 1 desde su función luaopen, para que Lua sepa que hay un valor de retorno. La llamada anterior lua_pushvalue existe con el único propósito de copiar la tabla (recuerde: las tablas están referenciadas, por lo que es como copiar un puntero). De esta forma, cuando usa lua_setfield, la copia se elimina de la pila, mientras que el original queda por usar como valor de retorno.

+0

Gracias. Estaba un poco desconcertado al principio, pero dibujar los movimientos de la pila en papel me ayudó a entender el proceso. –

+3

+1 por tener problemas para analizar el valor de retorno de 'require' ... mucha gente realmente no parece estar al tanto de que la práctica recomendada ha cambiado de" solo inserte su módulo en un global "para" regresar " su módulo requiere, y la persona que llama debería ponerlo en una variable local " – snogglethorpe

2

no directamente relacionados con la pregunta, pero la siguiente afirmación no es del todo cierto:

Actualmente estoy tratando de envolver una parte de la biblioteca PolarSSL (http://polarssl.org) para dar acceso a SHA-512 HMAC (luacrypto no proporciona esto).

No sé qué versión de LuaCrypto te refieres, pero sí proporciona this LuaCrypto fork SHA-512 HMAC, así como cualquier otro tipo recopilación apoyado por OpenSSL automáticamente. Sólo tiene que pasar "sha512" como el tipo de digerir:

hmac.digest("sha512", message, key) 

La documentación indica sólo una parte de los tipos soportados Digest, la lista completa se puede recuperar llamando crypto.list("digests").

table.foreach(crypto.list("digests"), print) 

Cuando lo pienso, incluso el LuaCrypto original debería ser compatible con SHA-512.

+0

Gracias, no estaba al tanto. Sin embargo, estaba saliendo de la horquilla "principal" que no envuelve SHA512. Elegí envolver PolarSSL porque es pequeño y la API es muy simple: cada módulo es independiente y se puede compilar independientemente. Por ejemplo, he compilado solo el módulo SHA512/384. Tamaño total: 22kb. –

+0

¡De hecho, es un tamaño muy razonable! Se ve muy bien si quieres incrustar Lua con capacidades criptográficas. –

Cuestiones relacionadas