44#include <string.h>
55#include "script.h"
66#include "http_parser.h"
7+ #include "zmalloc.h"
78
89typedef struct {
910 char * name ;
1011 int type ;
1112 void * value ;
1213} table_field ;
1314
15+ static int script_addr_tostring (lua_State * );
16+ static int script_addr_gc (lua_State * );
1417static int script_stats_len (lua_State * );
1518static int script_stats_get (lua_State * );
19+ static int script_wrk_lookup (lua_State * );
20+ static int script_wrk_connect (lua_State * );
1621static void set_fields (lua_State * , int index , const table_field * );
1722
23+ static const struct luaL_reg addrlib [] = {
24+ { "__tostring" , script_addr_tostring },
25+ { "__gc" , script_addr_gc },
26+ { NULL , NULL }
27+ };
28+
1829static const struct luaL_reg statslib [] = {
1930 { "__index" , script_stats_get },
2031 { "__len" , script_stats_len },
@@ -26,16 +37,22 @@ lua_State *script_create(char *scheme, char *host, char *port, char *path) {
2637 luaL_openlibs (L );
2738 luaL_dostring (L , "wrk = require \"wrk\"" );
2839
40+ luaL_newmetatable (L , "wrk.addr" );
41+ luaL_register (L , NULL , addrlib );
42+ lua_pop (L , 1 );
43+
2944 luaL_newmetatable (L , "wrk.stats" );
3045 luaL_register (L , NULL , statslib );
3146 lua_pop (L , 1 );
3247
3348 const table_field fields [] = {
34- { "scheme" , LUA_TSTRING , scheme },
35- { "host" , LUA_TSTRING , host },
36- { "port" , LUA_TSTRING , port },
37- { "path" , LUA_TSTRING , path },
38- { NULL , 0 , NULL },
49+ { "scheme" , LUA_TSTRING , scheme },
50+ { "host" , LUA_TSTRING , host },
51+ { "port" , LUA_TSTRING , port },
52+ { "path" , LUA_TSTRING , path },
53+ { "lookup" , LUA_TFUNCTION , script_wrk_lookup },
54+ { "connect" , LUA_TFUNCTION , script_wrk_connect },
55+ { NULL , 0 , NULL },
3956 };
4057
4158 lua_getglobal (L , "wrk" );
@@ -45,6 +62,36 @@ lua_State *script_create(char *scheme, char *host, char *port, char *path) {
4562 return L ;
4663}
4764
65+ void script_prepare_setup (lua_State * L , char * script ) {
66+ if (script && luaL_dofile (L , script )) {
67+ const char * cause = lua_tostring (L , -1 );
68+ fprintf (stderr , "%s: %s\n" , script , cause );
69+ }
70+ }
71+
72+ bool script_resolve (lua_State * L , char * host , char * service ) {
73+ lua_getglobal (L , "wrk" );
74+
75+ lua_getfield (L , -1 , "resolve" );
76+ lua_pushstring (L , host );
77+ lua_pushstring (L , service );
78+ lua_call (L , 2 , 0 );
79+
80+ lua_getfield (L , -1 , "addrs" );
81+ size_t count = lua_objlen (L , -1 );
82+ lua_pop (L , 2 );
83+ return count > 0 ;
84+ }
85+
86+ struct addrinfo * script_peek_addr (lua_State * L ) {
87+ lua_getglobal (L , "wrk" );
88+ lua_getfield (L , -1 , "addrs" );
89+ lua_rawgeti (L , -1 , 1 );
90+ struct addrinfo * addr = lua_touserdata (L , -1 );
91+ lua_pop (L , 3 );
92+ return addr ;
93+ }
94+
4895void script_headers (lua_State * L , char * * headers ) {
4996 lua_getglobal (L , "wrk" );
5097 lua_getfield (L , 1 , "headers" );
@@ -225,6 +272,34 @@ size_t script_verify_request(lua_State *L) {
225272 return count ;
226273}
227274
275+ static struct addrinfo * checkaddr (lua_State * L ) {
276+ struct addrinfo * addr = luaL_checkudata (L , -1 , "wrk.addr" );
277+ luaL_argcheck (L , addr != NULL , 1 , "`addr' expected" );
278+ return addr ;
279+ }
280+
281+ static int script_addr_tostring (lua_State * L ) {
282+ struct addrinfo * addr = checkaddr (L );
283+ char host [NI_MAXHOST ];
284+ char service [NI_MAXSERV ];
285+
286+ int flags = NI_NUMERICHOST | NI_NUMERICSERV ;
287+ int rc = getnameinfo (addr -> ai_addr , addr -> ai_addrlen , host , NI_MAXHOST , service , NI_MAXSERV , flags );
288+ if (rc != 0 ) {
289+ const char * msg = gai_strerror (rc );
290+ return luaL_error (L , "addr tostring failed %s" , msg );
291+ }
292+
293+ lua_pushfstring (L , "%s:%s" , host , service );
294+ return 1 ;
295+ }
296+
297+ static int script_addr_gc (lua_State * L ) {
298+ struct addrinfo * addr = checkaddr (L );
299+ zfree (addr -> ai_addr );
300+ return 0 ;
301+ }
302+
228303static stats * checkstats (lua_State * L ) {
229304 stats * * s = luaL_checkudata (L , 1 , "wrk.stats" );
230305 luaL_argcheck (L , s != NULL , 1 , "`stats' expected" );
@@ -262,10 +337,57 @@ static int script_stats_len(lua_State *L) {
262337 return 1 ;
263338}
264339
340+ static int script_wrk_lookup (lua_State * L ) {
341+ struct addrinfo * addrs ;
342+ struct addrinfo hints = {
343+ .ai_family = AF_UNSPEC ,
344+ .ai_socktype = SOCK_STREAM
345+ };
346+ int rc , index = 1 ;
347+
348+ const char * host = lua_tostring (L , -2 );
349+ const char * service = lua_tostring (L , -1 );
350+
351+ if ((rc = getaddrinfo (host , service , & hints , & addrs )) != 0 ) {
352+ const char * msg = gai_strerror (rc );
353+ fprintf (stderr , "unable to resolve %s:%s %s\n" , host , service , msg );
354+ exit (1 );
355+ }
356+
357+ lua_newtable (L );
358+ for (struct addrinfo * addr = addrs ; addr != NULL ; addr = addr -> ai_next ) {
359+ struct addrinfo * udata = lua_newuserdata (L , sizeof (* udata ));
360+ luaL_getmetatable (L , "wrk.addr" );
361+ lua_setmetatable (L , -2 );
362+
363+ * udata = * addr ;
364+ udata -> ai_addr = zmalloc (addr -> ai_addrlen );
365+ memcpy (udata -> ai_addr , addr -> ai_addr , addr -> ai_addrlen );
366+ lua_rawseti (L , -2 , index ++ );
367+ }
368+
369+ freeaddrinfo (addrs );
370+ return 1 ;
371+ }
372+
373+ static int script_wrk_connect (lua_State * L ) {
374+ struct addrinfo * addr = checkaddr (L );
375+ int fd , connected = 0 ;
376+ if ((fd = socket (addr -> ai_family , addr -> ai_socktype , addr -> ai_protocol )) != -1 ) {
377+ connected = connect (fd , addr -> ai_addr , addr -> ai_addrlen ) == 0 ;
378+ close (fd );
379+ }
380+ lua_pushboolean (L , connected );
381+ return 1 ;
382+ }
383+
265384static void set_fields (lua_State * L , int index , const table_field * fields ) {
266385 for (int i = 0 ; fields [i ].name ; i ++ ) {
267386 table_field f = fields [i ];
268387 switch (f .value == NULL ? LUA_TNIL : f .type ) {
388+ case LUA_TFUNCTION :
389+ lua_pushcfunction (L , (lua_CFunction ) f .value );
390+ break ;
269391 case LUA_TNUMBER :
270392 lua_pushinteger (L , * ((lua_Integer * ) f .value ));
271393 break ;
0 commit comments