mirror of
				https://github.com/lxsang/antd-lua-plugin
				synced 2025-10-30 10:03:00 +01:00 
			
		
		
		
	lua plugin now used a separated process to handle requests
This commit is contained in:
		
							
								
								
									
										133
									
								
								APIs/api.lua
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								APIs/api.lua
									
									
									
									
									
								
							| @@ -1,32 +1,23 @@ | ||||
|  | ||||
| package.cpath = __api__.apiroot..'/?.so' | ||||
| require("antd") | ||||
|  | ||||
| local readline = function() | ||||
|     local s = "" | ||||
|     repeat | ||||
|         local c = modules.std().antd_recv(HTTP_REQUEST.id,1) | ||||
|         if c ~= 0 and c ~= 10 then | ||||
|             s = s..utf8.char(c) | ||||
|         end | ||||
|     until(c == 0 or c == 10) | ||||
|     return s | ||||
| end | ||||
| std = modules.std() | ||||
| local read_header =function() | ||||
|     local l | ||||
|     repeat | ||||
|         local l = readline() | ||||
|         if l ~= '\r' then | ||||
|         l = std.antd_recv(HTTP_REQUEST.id) | ||||
|         if l and l ~= '\r'  then | ||||
|             if l == "HTTP_REQUEST" or l == "request" or l == "COOKIE" or l == "REQUEST_HEADER" or l == "REQUEST_DATA" then | ||||
|                 coroutine.yield(l, "LUA_TABLE") | ||||
|             else | ||||
|                 local l1 = readline() | ||||
|                 local l1 = std.antd_recv(HTTP_REQUEST.id) | ||||
|                 if l1 ~= '\r' then | ||||
|                     coroutine.yield(l, l1) | ||||
|                 end | ||||
|                 l = l1 | ||||
|             end | ||||
|         end | ||||
|     until l == '\r' | ||||
|     until not l or l == '\r' | ||||
| end | ||||
|  | ||||
|  | ||||
| @@ -85,11 +76,11 @@ if HEADER["User-Agent"] and HEADER["User-Agent"]:match("Mobi") then | ||||
| end | ||||
|  | ||||
| function LOG_INFO(fmt,...) | ||||
|     ulib.syslog(5,string.format(fmt, table.unpack({...}))) | ||||
|     ulib.syslog(5,string.format(fmt or "LOG", table.unpack({...}) or "")) | ||||
| end | ||||
|  | ||||
| function LOG_ERROR(fmt,...) | ||||
|     ulib.syslog(3,string.format(fmt, table.unpack({...}))) | ||||
|     ulib.syslog(3,string.format(fmt or "ERROR", table.unpack({...}) or "")) | ||||
| end | ||||
|  | ||||
| function has_module(m) | ||||
| @@ -190,88 +181,13 @@ function loadscript(file, args) | ||||
|     end | ||||
| end | ||||
|  | ||||
| local decode_post_data = function(ctype, clen, is_url) | ||||
|     local raw_data,size = std.antd_recv(HTTP_REQUEST.id, clen) | ||||
|     if not raw_data or size ~= clen then | ||||
|         LOG_ERROR("Unable to read request data: received %d bytes expected %d bytes", size, clen) | ||||
|         return 400, "Unable to read request data" | ||||
|     end | ||||
|     if is_url then | ||||
|         local str = tostring(raw) | ||||
|         local arr = explode(str, "&") | ||||
|         LOG_INFO("encoded POST URI: %s", str) | ||||
|         for i,v in ipairs(arr) do | ||||
|             local assoc = explode(v,"=") | ||||
|             if #assoc == 2 then | ||||
|                 REQUEST[assoc[1]] = untils.decodeURI(assoc[2]) | ||||
|             else | ||||
|                 REQUEST[assoc[1]] = "" | ||||
|             end | ||||
|         end | ||||
|     else | ||||
|         local key = ctype:gsub("^[^/]*", "") | ||||
|         REQUEST[key] = raw_data | ||||
|     end | ||||
|     return 0 | ||||
| end | ||||
|  | ||||
| local decode_multi_part = function(ctype, clen) | ||||
|     --[[ | ||||
|         local arr = explode(ctype, "=") | ||||
|     if #arr ~= 2 then | ||||
|         LOG_ERROR("Unable to parsed boundary for: %s", ctype) | ||||
|         return 400, "Multipart Boundary not found" | ||||
|     end | ||||
|     local boundary = std.trim(arr[2]," ") | ||||
|     local boundary_end = boundary.."--" | ||||
|     LOG_INFO("Boundary found: %s", boundary) | ||||
|     local line = nil | ||||
|     repeat | ||||
|         line = readline() | ||||
|     until not line or line:find(boundary) or line == "" | ||||
|     if not line or line == "" then | ||||
|         LOG_ERROR("Cannot find first match for boundary %s", boundary) | ||||
|         return 400, "Unable to decode data based on content boundary" | ||||
|     end | ||||
|     repeat | ||||
|         line = readline() | ||||
|     until not line or line:find("Content-Disposition:") or line == "" | ||||
|     if not line or line == "" then | ||||
|         LOG_ERROR("Content-Disposition meta data not fond") | ||||
|         return 400, "Unable to query Content-Disposition from request" | ||||
|     end | ||||
|     line = line:gsub("Content-Disposition:",""):gsub("\r\n","") | ||||
|     -- extract parameters from header | ||||
|     arr = explode(line,";") | ||||
|     local part_name, part_file = nil, nil | ||||
|     for i,v in ipairs(arr) do | ||||
|         LOG_INFO('Decoding: %s', v) | ||||
|         local assoc = explode(v, "=") | ||||
|         local key = std.trim(assoc[1]) | ||||
|         local val = assoc[1] | ||||
|         if val then | ||||
|             val = std.trim(val, " ") | ||||
|             if key == "name" then | ||||
|                 LOG_INFO("Part name: %s", val) | ||||
|                 part_name = val | ||||
|             end | ||||
|             if key == "filename" then | ||||
|                 LOG_INFO("Part file: %s", val) | ||||
|                 part_file = val | ||||
|             end | ||||
|         end | ||||
|     end | ||||
|     -- TODO: to be continue | ||||
|     ]] | ||||
|     return 0 | ||||
| end | ||||
| -- decode post data if any | ||||
| local decode_request = function() | ||||
|     LOG_INFO("Request method %s", REQUEST.method) | ||||
| local decode_request_data = function() | ||||
|     if (not REQUEST.method) | ||||
|         or (REQUEST.method ~= "POST" | ||||
|             and REQUEST.method ~= "PUT" | ||||
|             and REQUEST.method ~= "PATCH") then | ||||
|             and REQUEST.method ~= "PATCH") | ||||
|         or (not REQUEST.HAS_RAW_BODY) then | ||||
|             return 0 | ||||
|     end | ||||
|     local ctype = HEADER['Content-Type'] | ||||
| @@ -283,16 +199,31 @@ local decode_request = function() | ||||
|         LOG_ERROR("Invalid content type %s or content length %d", ctype, clen) | ||||
|         return 400, "Bad Request, missing content description" | ||||
|     end | ||||
|     if ctype == "application/x-www-form-urlencoded" then | ||||
|         return decode_post_data(ctype, clen, true) | ||||
|     elseif ctype == "multipart/form-data" then | ||||
|         return decode_multi_part(ctype, clen) | ||||
|     local raw_data, len = std.antd_recv(HTTP_REQUEST.id, clen) | ||||
|     if len ~= clen then | ||||
|         LOG_ERROR("Unable to read all data: read %d expected %d", len, clen) | ||||
|         return 400, "Bad Request, missing content data" | ||||
|     end | ||||
|     if ctype:find("application/json") then | ||||
|         REQUEST.json = bytes.__tostring(raw_data) | ||||
|     else | ||||
|         return decode_post_data(ctype, clen, false) | ||||
|         REQUEST[ctype] = raw_data | ||||
|     end | ||||
|     REQUEST.HAS_RAW_BODY = nil | ||||
|     return 0 | ||||
| end | ||||
|  | ||||
| -- set compression level | ||||
| local accept_encoding = HEADER["Accept-Encoding"] | ||||
| if accept_encoding then | ||||
|     if accept_encoding:find("gzip") then | ||||
|         std.antd_set_zlevel(HTTP_REQUEST.id, "gzip") | ||||
|     elseif accept_encoding:find("deflate") then | ||||
|         std.antd_set_zlevel(HTTP_REQUEST.id, "deflate") | ||||
|     end | ||||
| end | ||||
|  | ||||
| local code, error = decode_request() | ||||
| local code, error = decode_request_data() | ||||
|  | ||||
| if code ~= 0 then | ||||
|     LOG_ERROR(error) | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| function std.extra_mime(name) | ||||
| 	local ext = std.ext(name); | ||||
| 	local ext = std.ext(name) | ||||
| 	local mpath = __ROOT__.."/".."mimes.json" | ||||
| 	local xmimes = {} | ||||
| 	if utils.file_exists(mpath) then | ||||
| @@ -15,7 +15,7 @@ function std.extra_mime(name) | ||||
| 	elseif ext == "cpp" or ext == "hpp" then return "text/cpp",false | ||||
| 	elseif ext == "md" then return "text/markdown",false | ||||
| 	elseif ext == "lua" then return "text/lua",false | ||||
| 	elseif ext == "yaml" then return "application/x-yaml", false | ||||
| 	elseif ext == "yml" then return "application/x-yaml", false | ||||
| 	elseif xmimes[ext] then return xmimes[ext].mime, xmimes[ext].binary | ||||
| 	--elseif ext == "pgm" then return "image/x-portable-graymap", true | ||||
| 	else  | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| std = modules.std() | ||||
| bytes = modules.bytes() | ||||
| array = modules.array() | ||||
|  | ||||
| @@ -61,7 +60,8 @@ function std.b(s) | ||||
| 	std._b(HTTP_REQUEST.id,s) | ||||
| end | ||||
| function std.f(v) | ||||
| 	ulib.send_file(v, HTTP_REQUEST.socket) | ||||
| 	std._f(HTTP_REQUEST.id,v) | ||||
| 	--ulib.send_file(v, HTTP_REQUEST.socket) | ||||
| end | ||||
|  | ||||
| function std.setCookie(v) | ||||
|   | ||||
							
								
								
									
										1272
									
								
								lib/asl/antd.c
									
									
									
									
									
								
							
							
						
						
									
										1272
									
								
								lib/asl/antd.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										177
									
								
								lib/asl/handle.c
									
									
									
									
									
								
							
							
						
						
									
										177
									
								
								lib/asl/handle.c
									
									
									
									
									
								
							| @@ -1,6 +1,4 @@ | ||||
| #include <antd/plugin.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/types.h>          /* See NOTES */ | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/tcp.h>  | ||||
| #include <errno.h> | ||||
| @@ -8,105 +6,100 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <netinet/in.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/wait.h> | ||||
| #include "../lualib.h" | ||||
|  | ||||
| typedef struct { | ||||
| 	plugin_header_t* __plugin__; | ||||
| 	int fd; | ||||
|     plugin_header_t* __plugin__; | ||||
|     int fd; | ||||
| } lua_thread_data_t; | ||||
|  | ||||
| void* lua_handle(void* ptr) | ||||
| { | ||||
| 	lua_thread_data_t* data = (lua_thread_data_t**)ptr; | ||||
| 	lua_State* L = NULL; | ||||
| 	antd_client_t cl = {0}; | ||||
| 	cl.sock = data->fd; | ||||
| 	time(&cl.last_io); | ||||
| 	cl.ssl = NULL; | ||||
| 	cl.state = ANTD_CLIENT_PLUGIN_EXEC; | ||||
| 	cl.z_status = 0; | ||||
| 	cl.z_level = ANTD_CNONE; | ||||
| 	cl.zstream = NULL; | ||||
| 	//char * index = __s("%s/%s",__plugin__->htdocs,"router.lua"); | ||||
| 	char* cnf = __s("%s%s%s", data->__plugin__->pdir,DIR_SEP, data->__plugin__->name); | ||||
| 	char * apis = __s("%s/%s",cnf,"api.lua"); | ||||
| 	L = luaL_newstate(); | ||||
| 	luaL_openlibs(L); | ||||
| 	//module loader | ||||
| 	//luaL_newlib(L, modules); | ||||
| 	//lua_setglobal(L, "modules"); | ||||
| 	// set up global variable | ||||
| 	// API header | ||||
| 	lua_newtable(L); | ||||
| 	lua_pushstring(L,"name"); | ||||
| 	lua_pushstring(L, data->__plugin__->name); | ||||
| 	lua_settable(L,-3); | ||||
| 	 | ||||
| 	//lua_pushstring(L,"root"); | ||||
| 	//htdocs(rq, buf); | ||||
| 	//lua_pushstring(L, data->__plugin__->htdocs); | ||||
| 	//lua_settable(L,-3); | ||||
| 	 | ||||
| 	lua_pushstring(L,"apiroot"); | ||||
| 	lua_pushstring(L, cnf); | ||||
| 	lua_settable(L,-3); | ||||
|     lua_thread_data_t* data = (lua_thread_data_t*)ptr; | ||||
|     lua_State* L = NULL; | ||||
|     antd_client_t* cl = (antd_client_t*) malloc(sizeof(antd_client_t)); | ||||
|     cl->sock = data->fd; | ||||
|     time(&cl->last_io); | ||||
|     cl->ssl = NULL; | ||||
|     cl->state = ANTD_CLIENT_PLUGIN_EXEC; | ||||
|     cl->z_status = 0; | ||||
|     cl->z_level = ANTD_CNONE; | ||||
|     cl->zstream = NULL; | ||||
|     //char * index = __s("%s/%s",__plugin__->htdocs,"router.lua"); | ||||
|     char* cnf = __s("%s%s%s", data->__plugin__->pdir,DIR_SEP, data->__plugin__->name); | ||||
|     char * apis = __s("%s/%s",cnf,"api.lua"); | ||||
|     L = luaL_newstate(); | ||||
|     luaL_openlibs(L); | ||||
|     //module loader | ||||
|     //luaL_newlib(L, modules); | ||||
|     //lua_setglobal(L, "modules"); | ||||
|     // set up global variable | ||||
|     // API header | ||||
|     lua_newtable(L); | ||||
|     lua_pushstring(L,"name"); | ||||
|     lua_pushstring(L, data->__plugin__->name); | ||||
|     lua_settable(L,-3); | ||||
|      | ||||
|     //lua_pushstring(L,"root"); | ||||
|     //htdocs(rq, buf); | ||||
|     //lua_pushstring(L, data->__plugin__->htdocs); | ||||
|     //lua_settable(L,-3); | ||||
|      | ||||
|     lua_pushstring(L,"apiroot"); | ||||
|     lua_pushstring(L, cnf); | ||||
|     lua_settable(L,-3); | ||||
|  | ||||
| 	lua_pushstring(L,"tmpdir"); | ||||
| 	lua_pushstring(L, data->__plugin__->tmpdir); | ||||
| 	lua_settable(L,-3); | ||||
|     lua_pushstring(L,"tmpdir"); | ||||
|     lua_pushstring(L, data->__plugin__->tmpdir); | ||||
|     lua_settable(L,-3); | ||||
|  | ||||
| 	lua_pushstring(L,"dbpath"); | ||||
| 	lua_pushstring(L, data->__plugin__->dbpath); | ||||
| 	lua_settable(L,-3); | ||||
| 	 | ||||
| 	lua_setglobal(L, "__api__"); | ||||
| 	 | ||||
| 	// Request | ||||
| 	lua_newtable(L); | ||||
| 	lua_pushstring(L,"id"); | ||||
| 	lua_pushlightuserdata(L, &cl); | ||||
| 	//lua_pushnumber(L,client); | ||||
| 	lua_settable(L, -3); | ||||
|     lua_pushstring(L,"dbpath"); | ||||
|     lua_pushstring(L, data->__plugin__->dbpath); | ||||
|     lua_settable(L,-3); | ||||
|      | ||||
|     lua_setglobal(L, "__api__"); | ||||
|      | ||||
|     // Request | ||||
|     lua_newtable(L); | ||||
|     lua_pushstring(L,"id"); | ||||
|     lua_pushlightuserdata(L, cl); | ||||
|     //lua_pushnumber(L,client); | ||||
|     lua_settable(L, -3); | ||||
|  | ||||
| 	lua_pushstring(L,"socket"); | ||||
| 	lua_pushnumber(L, cl.sock); | ||||
| 	//lua_pushnumber(L,client); | ||||
| 	lua_settable(L, -3); | ||||
|     lua_pushstring(L,"socket"); | ||||
|     lua_pushnumber(L, cl->sock); | ||||
|     //lua_pushnumber(L,client); | ||||
|     lua_settable(L, -3); | ||||
|  | ||||
| 	int flag = 1; | ||||
|  | ||||
| 	if (setsockopt(cl.sock, IPPROTO_TCP, TCP_NODELAY, &(int){1}, sizeof(int)) == -1) | ||||
| 	{ | ||||
| 		ERROR("Unable to set TCP_NODELAY on %d - setsockopt: %s", cl.sock, strerror(errno)); | ||||
| 	} | ||||
| 	//lua_pushstring(L,"request"); | ||||
| 	//push_dict_to_lua(L,rq->request); | ||||
| 	//lua_settable(L, -3); | ||||
| 	lua_setglobal(L, "HTTP_REQUEST"); | ||||
| 	free(ptr); | ||||
| 	// load major apis | ||||
| 	if(is_file(apis)) | ||||
| 		if (luaL_loadfile(L, apis) || lua_pcall(L, 0, 0, 0)) | ||||
| 		{ | ||||
| 			ERROR( "cannot start API file: [%s] %s\n", apis, lua_tostring(L, -1)); | ||||
| 			antd_error(&cl, 503, "Internal server error"); | ||||
| 		} | ||||
| 	 | ||||
| 	/*if (luaL_loadfile(L, index) || lua_pcall(L, 0, 0, 0)) | ||||
| 	{ | ||||
| 		text(client); | ||||
| 		__t(client, "Cannot run router: %s", lua_tostring(L, -1)); | ||||
| 	} | ||||
| 	free(index);*/ | ||||
| 	LOG("LUA handle exit on %d", cl.sock); | ||||
| 	// clear request | ||||
| 	if(L) | ||||
| 		lua_close(L); | ||||
| 	if(cnf) | ||||
| 		free(cnf); | ||||
| 	if(apis) | ||||
| 		free(apis); | ||||
| 	(void) close(cl.sock); | ||||
| 	return 0; | ||||
| 	//lua_close(L); | ||||
|     //lua_pushstring(L,"request"); | ||||
|     //push_dict_to_lua(L,rq->request); | ||||
|     //lua_settable(L, -3); | ||||
|     lua_setglobal(L, "HTTP_REQUEST"); | ||||
|     free(ptr); | ||||
|     // load major apis | ||||
|     if(is_file(apis)) | ||||
|         if (luaL_loadfile(L, apis) || lua_pcall(L, 0, 0, 0)) | ||||
|         { | ||||
|             ERROR("cannot start API file: [%s] %s\n", apis, lua_tostring(L, -1)); | ||||
|         } | ||||
|      | ||||
|     /*if (luaL_loadfile(L, index) || lua_pcall(L, 0, 0, 0)) | ||||
|     { | ||||
|         text(client); | ||||
|         __t(client, "Cannot run router: %s", lua_tostring(L, -1)); | ||||
|     } | ||||
|     free(index);*/ | ||||
|     LOG("LUA handle exit on %d", cl->sock); | ||||
|     // clear request | ||||
|     if(L) | ||||
|         lua_close(L); | ||||
|     if(cnf) | ||||
|         free(cnf); | ||||
|     if(apis) | ||||
|         free(apis); | ||||
|     (void) antd_close(cl); | ||||
|     return 0; | ||||
|     //lua_close(L); | ||||
| } | ||||
|   | ||||
							
								
								
									
										425
									
								
								lua-api.c
									
									
									
									
									
								
							
							
						
						
									
										425
									
								
								lua-api.c
									
									
									
									
									
								
							| @@ -30,19 +30,18 @@ | ||||
| #define PROCESS_TIMEOUT 200u          //100ms | ||||
|  | ||||
| typedef struct { | ||||
| 	plugin_header_t* __plugin__; | ||||
| 	int fd; | ||||
|     plugin_header_t* __plugin__; | ||||
|     int fd; | ||||
| } lua_thread_data_t; | ||||
|  | ||||
| static pid_t pid = 0; | ||||
| static char sock_path[108]; | ||||
|  | ||||
| static int open_unix_socket() | ||||
| { | ||||
|     struct sockaddr_un address; | ||||
|     address.sun_family = AF_UNIX; | ||||
| 	char path[sizeof(address.sun_path)]; | ||||
| 	(void)snprintf(path, sizeof(address.sun_path), "%s/%s", __plugin__.tmpdir, SOCKET_NAME); | ||||
|     (void) strncpy(address.sun_path, path, sizeof(address.sun_path)); | ||||
|     (void) strncpy(address.sun_path, sock_path, sizeof(address.sun_path)); | ||||
|     int fd = socket(AF_UNIX, SOCK_STREAM, 0); | ||||
|     if(fd == -1) | ||||
|     { | ||||
| @@ -54,20 +53,16 @@ static int open_unix_socket() | ||||
|         ERROR( "Unable to connect to socket '%s': %s", address.sun_path, strerror(errno)); | ||||
|         return -1; | ||||
|     } | ||||
|     LOG( "Socket %s is created successfully", path); | ||||
|     LOG( "Socket %s is created successfully", sock_path); | ||||
|     return fd; | ||||
| } | ||||
|  | ||||
| static int mk_socket() | ||||
| { | ||||
|     struct sockaddr_un address; | ||||
| 	char path[sizeof(address.sun_path)]; | ||||
| 	(void)snprintf(path, sizeof(address.sun_path), "%s/%s", __plugin__.tmpdir, SOCKET_NAME); | ||||
|     address.sun_family = AF_UNIX; | ||||
|     // create the socket | ||||
|     (void)snprintf(path, sizeof(address.sun_path), "%s/%s", __plugin__.tmpdir, SOCKET_NAME); | ||||
|  | ||||
|     (void)strncpy(address.sun_path, path, sizeof(address.sun_path)); | ||||
|     (void)strncpy(address.sun_path, sock_path, sizeof(address.sun_path)); | ||||
|     int fd = socket(AF_UNIX, SOCK_STREAM, 0); | ||||
|     if (fd == -1) | ||||
|     { | ||||
| @@ -82,231 +77,247 @@ static int mk_socket() | ||||
|     // mark the socket as passive mode | ||||
|     if (listen(fd, 500) == -1) | ||||
|     { | ||||
|         ERROR("Unable to listen to socket: %d (%s): %s", fd, path, strerror(errno)); | ||||
|         ERROR("Unable to listen to socket: %d (%s): %s", fd, sock_path, strerror(errno)); | ||||
|         return -1; | ||||
|     } | ||||
|     LOG("Socket %s is created successfully: %d", path, fd); | ||||
|     LOG("Socket %s is created successfully: %d", sock_path, fd); | ||||
|     return fd; | ||||
| } | ||||
|  | ||||
| static void lua_serve() | ||||
| { | ||||
| 	void* core = NULL; | ||||
| 	void* lua_handle = NULL; | ||||
| 	void *(*handle_fn)(void*); | ||||
| 	char path[BUFFLEN]; | ||||
| 	char* error; | ||||
| 	(void)snprintf(path, BUFFLEN, "%s/lua/core.so", __plugin__.pdir); | ||||
| 	core = dlopen(path, RTLD_NOW| RTLD_GLOBAL); | ||||
| 	if(!core) | ||||
| 	{ | ||||
| 		ERROR("Cannot load Lua core: %s", dlerror()); | ||||
| 		return; | ||||
| 	} | ||||
| 	LOG("Lua core loaded"); | ||||
| 	// now load the handle | ||||
| 	(void)snprintf(path, BUFFLEN, "%s/lua/handle.so", __plugin__.pdir); | ||||
| 	lua_handle = dlopen(path, RTLD_LAZY); | ||||
| 	if(!lua_handle) | ||||
| 	{ | ||||
| 		ERROR("Cannot load lua_handle: %s", dlerror()); | ||||
| 		return; | ||||
| 	} | ||||
| 	// find the fn | ||||
| 	handle_fn = (void *(*)(void*))dlsym(lua_handle, LUA_HDL_FN); | ||||
| 	if ((error = dlerror()) != NULL) | ||||
| 	{ | ||||
| 		ERROR("Problem when finding %s method from handle : %s", LUA_HDL_FN, error); | ||||
| 		handle_fn = NULL; | ||||
| 		return; | ||||
| 	} | ||||
| 	int socket = mk_socket(); | ||||
| 	if(socket != -1) | ||||
| 	{ | ||||
| 		int fd; | ||||
| 		if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) == -1) | ||||
|     void* core = NULL; | ||||
|     void* lua_handle = NULL; | ||||
|     void *(*handle_fn)(void*); | ||||
|     char path[BUFFLEN]; | ||||
|     char* error; | ||||
|     (void)snprintf(path, BUFFLEN, "%s/lua/core.so", __plugin__.pdir); | ||||
|     core = dlopen(path, RTLD_NOW| RTLD_GLOBAL); | ||||
|     if(!core) | ||||
|     { | ||||
|         ERROR("Cannot load Lua core: %s", dlerror()); | ||||
|         return; | ||||
|     } | ||||
|     // now load the handle | ||||
|     (void)snprintf(path, BUFFLEN, "%s/lua/handle.so", __plugin__.pdir); | ||||
|     lua_handle = dlopen(path, RTLD_LAZY); | ||||
|     if(!lua_handle) | ||||
|     { | ||||
|         ERROR("Cannot load lua_handle: %s", dlerror()); | ||||
|         return; | ||||
|     } | ||||
|     // find the fn | ||||
|     handle_fn = (void *(*)(void*))dlsym(lua_handle, LUA_HDL_FN); | ||||
|     if ((error = dlerror()) != NULL) | ||||
|     { | ||||
|         ERROR("Problem when finding %s method from handle : %s", LUA_HDL_FN, error); | ||||
|         handle_fn = NULL; | ||||
|         return; | ||||
|     } | ||||
|     int socket = mk_socket(); | ||||
|     if(socket != -1) | ||||
|     { | ||||
|         int fd; | ||||
|         if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) == -1) | ||||
|         { | ||||
|             ERROR("Unable to set reuse address on %d - setsockopt: %s", socket, strerror(errno)); | ||||
|         } | ||||
|         LOG("LUA server online"); | ||||
| 		/*set log level*/ | ||||
| 		const char * enable_debug = getenv("ANTD_DEBUG"); | ||||
| 		int log_level = LOG_ERR; | ||||
| 		if(enable_debug) | ||||
| 		{ | ||||
| 			ERROR("Unable to set reuse address on %d - setsockopt: %s", socket, strerror(errno)); | ||||
| 			if(atoi(enable_debug)) | ||||
| 			{ | ||||
| 				LOG("LUA Debug is enabled"); | ||||
| 				log_level = LOG_NOTICE; | ||||
| 			} | ||||
| 		} | ||||
| 		while((fd = accept(socket, NULL, NULL)) > 0) | ||||
| 		{ | ||||
| 			pthread_t thread; | ||||
| 			lua_thread_data_t* data = (lua_thread_data_t*)malloc(sizeof(lua_thread_data_t)); | ||||
| 			data->__plugin__ = &__plugin__; | ||||
| 			data->fd = fd; | ||||
| 			set_nonblock(fd); | ||||
| 			if (pthread_create(&thread, NULL, (void *(*)(void*))handle_fn, (void *)data) != 0) | ||||
| 			{ | ||||
| 				ERROR("pthread_create: cannot create lua thread: %s", strerror(errno)); | ||||
| 				(void)close(fd); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				LOG("Serve thread created for %d", fd); | ||||
| 				pthread_detach(thread); | ||||
| 			} | ||||
| 		setlogmask(LOG_UPTO(log_level)); | ||||
|         while((fd = accept(socket, NULL, NULL)) > 0) | ||||
|         { | ||||
|             pthread_t thread; | ||||
|             lua_thread_data_t* data = (lua_thread_data_t*)malloc(sizeof(lua_thread_data_t)); | ||||
|             data->__plugin__ = &__plugin__; | ||||
|             data->fd = fd; | ||||
|             set_nonblock(fd); | ||||
|             if (pthread_create(&thread, NULL, (void *(*)(void*))handle_fn, (void *)data) != 0) | ||||
|             { | ||||
|                 ERROR("pthread_create: cannot create lua thread: %s", strerror(errno)); | ||||
|                 (void)close(fd); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 LOG("Serve thread created for %d", fd); | ||||
|                 pthread_detach(thread); | ||||
|             } | ||||
|  | ||||
| 		} | ||||
| 		if (fd < 0) | ||||
| 		{ | ||||
| 			ERROR("Unable to accept the new connection: %s", strerror(errno)); | ||||
| 		} | ||||
| 	} | ||||
| 	if(core) | ||||
| 		(void)dlclose(core); | ||||
| 	if(lua_handle) | ||||
| 		(void)dlclose(lua_handle); | ||||
| 	LOG("lua_serve: stop serve due to error"); | ||||
|         } | ||||
|         if (fd < 0) | ||||
|         { | ||||
|             ERROR("Unable to accept the new connection: %s", strerror(errno)); | ||||
|         } | ||||
|     } | ||||
|     if(core) | ||||
|         (void)dlclose(core); | ||||
|     if(lua_handle) | ||||
|         (void)dlclose(lua_handle); | ||||
|     LOG("lua_serve: stop serve due to error"); | ||||
| } | ||||
|  | ||||
| void init() | ||||
| { | ||||
| 	use_raw_body(); | ||||
| 	pid = fork(); | ||||
| 	if (pid == 0) | ||||
| 	 (void)snprintf(sock_path, sizeof(sock_path), "%s/%s", __plugin__.tmpdir, SOCKET_NAME); | ||||
|     LOG("Lua socket will be stored in %s", sock_path); | ||||
|     pid = fork(); | ||||
|     if (pid == 0) | ||||
|     { | ||||
| 		// child | ||||
| 		lua_serve(); | ||||
| 	} | ||||
| 	// parent | ||||
| 	LOG("Lua module initialized"); | ||||
|         // child | ||||
|         lua_serve(); | ||||
|     } | ||||
|     LOG("Lua module initialized"); | ||||
| } | ||||
|  | ||||
| static void push_dict_to_socket(antd_client_t* cl, char* name, char* parent_name, dictionary_t d) | ||||
| { | ||||
| 	antd_send(cl,name, strlen(name)); | ||||
| 	antd_send(cl,"\n", 1); | ||||
| 	chain_t as; | ||||
| 	if(d) | ||||
| 		for_each_assoc(as, d) | ||||
| 		{ | ||||
| 			if(EQU(as->key,"COOKIE") || EQU(as->key,"REQUEST_HEADER") || EQU(as->key,"REQUEST_DATA") ) | ||||
| 				push_dict_to_socket(cl, as->key, name, (dictionary_t)as->value); | ||||
| 			else if(as->value) | ||||
| 			{ | ||||
| 				antd_send(cl,as->key, strlen(as->key)); | ||||
| 				antd_send(cl,"\n", 1); | ||||
| 				antd_send(cl,as->value, strlen(as->value)); | ||||
| 				antd_send(cl,"\n", 1); | ||||
| 			} | ||||
| 		} | ||||
| 	antd_send(cl,parent_name, strlen(parent_name)); | ||||
| 	antd_send(cl,"\n", 1); | ||||
|     antd_send(cl,name, strlen(name)); | ||||
|     antd_send(cl,"\n", 1); | ||||
|     chain_t as; | ||||
|     if(d) | ||||
|         for_each_assoc(as, d) | ||||
|         { | ||||
|             if(EQU(as->key,"COOKIE") || EQU(as->key,"REQUEST_HEADER") || EQU(as->key,"REQUEST_DATA") ) | ||||
|                 push_dict_to_socket(cl, as->key, name, (dictionary_t)as->value); | ||||
|             else if(as->value) | ||||
|             { | ||||
|                 antd_send(cl,as->key, strlen(as->key)); | ||||
|                 antd_send(cl,"\n", 1); | ||||
|                 antd_send(cl,as->value, strlen(as->value)); | ||||
|                 antd_send(cl,"\n", 1); | ||||
|             } | ||||
|         } | ||||
|     antd_send(cl,parent_name, strlen(parent_name)); | ||||
|     antd_send(cl,"\n", 1); | ||||
| } | ||||
|  | ||||
| static void *process(void *data) | ||||
| { | ||||
| 	fd_set fd_in; | ||||
| 	antd_request_t *rq = (antd_request_t *)data; | ||||
| 	antd_client_t* cl = (antd_client_t* ) dvalue(rq->request, "LUA_CL_DATA"); | ||||
| 	struct timeval timeout; | ||||
| 	timeout.tv_sec = 0; | ||||
| 	timeout.tv_usec = PROCESS_TIMEOUT; | ||||
| 	FD_ZERO(&fd_in); | ||||
| 	FD_SET(rq->client->sock, &fd_in); | ||||
| 	FD_SET(cl->sock, &fd_in); | ||||
| 	int max_fdm = rq->client->sock > cl->sock ? rq->client->sock : cl->sock; | ||||
| 	int rc = select(max_fdm + 1, &fd_in, NULL, NULL, &timeout); | ||||
| 	antd_task_t* task; | ||||
| 	uint8_t buff[BUFFLEN]; | ||||
| 	int ret; | ||||
| 	switch (rc) | ||||
| 	{ | ||||
| 		case -1: | ||||
| 			ERROR("Error on select(): %s", strerror(errno)); | ||||
| 			close(cl->sock); | ||||
| 			return antd_create_task(NULL, data, NULL, rq->client->last_io); | ||||
| 		case 0: | ||||
| 			// time out | ||||
| 			task = antd_create_task(process, (void *)rq, NULL, time(NULL)); | ||||
| 			//antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); | ||||
| 			//antd_task_bind_event(task, cl->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); | ||||
| 			return task; | ||||
| 		// we have data | ||||
| 		default: | ||||
| 			// If data is on webserver | ||||
| 			if (FD_ISSET(rq->client->sock, &fd_in)) | ||||
| 			{ | ||||
| 				while((ret = antd_recv_upto(rq->client,buff, BUFFLEN)) > 0) | ||||
| 				{ | ||||
| 					LOG("Receive %d bytes from antd ", ret); | ||||
| 					// write data to the other side | ||||
| 					if(antd_send(cl,buff, ret) != ret) | ||||
| 					{ | ||||
| 						ERROR("Error atnd_send(): %s", strerror(errno)); | ||||
| 						close(cl->sock); | ||||
| 						return antd_create_task(NULL, data, NULL, rq->client->last_io); | ||||
| 					} | ||||
| 				} | ||||
| 				if(ret <= 0) | ||||
| 				{ | ||||
| 					ERROR("Error antd_recv_upto() on %d: %s",rq->client->sock,  strerror(errno)); | ||||
| 					close(cl->sock); | ||||
| 					return antd_create_task(NULL, data, NULL, rq->client->last_io); | ||||
| 				} | ||||
| 			} | ||||
| 			else if(FD_ISSET(cl->sock, &fd_in)) | ||||
| 			{ | ||||
| 				while((ret = antd_recv_upto(cl,buff, BUFFLEN)) > 0) | ||||
| 				{ | ||||
| 					LOG("Receive %d bytes from LUA %d", ret, cl->sock); | ||||
| 					// write data to the other side | ||||
| 					if(antd_send(rq->client,buff, ret) != ret) | ||||
| 					{ | ||||
| 						ERROR("Error atnd_send(): %s", strerror(errno)); | ||||
| 						close(cl->sock); | ||||
| 						return antd_create_task(NULL, data, NULL, rq->client->last_io); | ||||
| 					} | ||||
| 				} | ||||
| 				if(ret < 0) | ||||
| 				{ | ||||
| 					ERROR("Error antd_recv_upto() on %d: %s", cl->sock, strerror(errno)); | ||||
| 					close(cl->sock); | ||||
| 					return antd_create_task(NULL, data, NULL, rq->client->last_io); | ||||
| 				} | ||||
| 			} | ||||
| 			task = antd_create_task(process, (void *)rq, NULL, time(NULL)); | ||||
| 			antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); | ||||
| 			antd_task_bind_event(task, cl->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); | ||||
| 			return task; | ||||
| 	} | ||||
|     fd_set fd_in; | ||||
|     antd_request_t *rq = (antd_request_t *)data; | ||||
|     antd_client_t* cl = (antd_client_t* ) dvalue(rq->request, "LUA_CL_DATA"); | ||||
|     struct timeval timeout; | ||||
|     timeout.tv_sec = 0; | ||||
|     timeout.tv_usec = PROCESS_TIMEOUT; | ||||
|     FD_ZERO(&fd_in); | ||||
|     FD_SET(rq->client->sock, &fd_in); | ||||
|     FD_SET(cl->sock, &fd_in); | ||||
|     int max_fdm = rq->client->sock > cl->sock ? rq->client->sock : cl->sock; | ||||
|     int rc = select(max_fdm + 1, &fd_in, NULL, NULL, &timeout); | ||||
|     antd_task_t* task; | ||||
|     uint8_t buff[BUFFLEN]; | ||||
|     int ret; | ||||
|     switch (rc) | ||||
|     { | ||||
|         case -1: | ||||
|             ERROR("Error on select(): %s", strerror(errno)); | ||||
|             antd_close(cl); | ||||
| 			dput(rq->request, "LUA_CL_DATA", NULL); | ||||
|             return antd_create_task(NULL, data, NULL, rq->client->last_io); | ||||
|         case 0: | ||||
|             // time out | ||||
|             task = antd_create_task(process, (void *)rq, NULL, time(NULL)); | ||||
|             //antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); | ||||
|             //antd_task_bind_event(task, cl->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); | ||||
|             return task; | ||||
|         // we have data | ||||
|         default: | ||||
|             // If data is on webserver | ||||
|             if (FD_ISSET(rq->client->sock, &fd_in)) | ||||
|             { | ||||
|                 while((ret = antd_recv_upto(rq->client,buff, BUFFLEN)) > 0) | ||||
|                 { | ||||
|                     // write data to the other side | ||||
|                     if(antd_send(cl,buff, ret) != ret) | ||||
|                     { | ||||
|                         ERROR("Error on atnd_send(): %s", strerror(errno)); | ||||
|                         antd_close(cl); | ||||
| 						dput(rq->request, "LUA_CL_DATA", NULL); | ||||
|                         return antd_create_task(NULL, data, NULL, rq->client->last_io); | ||||
|                     } | ||||
|                 } | ||||
|                 if(ret < 0) | ||||
|                 { | ||||
|                     LOG("antd_recv_upto() on %d: %s",rq->client->sock,  strerror(errno)); | ||||
|                     antd_close(cl); | ||||
| 					dput(rq->request, "LUA_CL_DATA", NULL); | ||||
|                     return antd_create_task(NULL, data, NULL, rq->client->last_io); | ||||
|                 } | ||||
|             } | ||||
|             else if(FD_ISSET(cl->sock, &fd_in)) | ||||
|             { | ||||
|                 while((ret = antd_recv_upto(cl,buff, BUFFLEN)) > 0) | ||||
|                 { | ||||
|                     // write data to the other side | ||||
|                     if(antd_send(rq->client,buff, ret) != ret) | ||||
|                     { | ||||
|                         ERROR("Error atnd_send(): %s", strerror(errno)); | ||||
|                         antd_close(cl); | ||||
| 						dput(rq->request, "LUA_CL_DATA", NULL); | ||||
|                         return antd_create_task(NULL, data, NULL, rq->client->last_io); | ||||
|                     } | ||||
|                 } | ||||
|                 if(ret < 0) | ||||
|                 { | ||||
|                     LOG("antd_recv_upto() on %d: %s", cl->sock, strerror(errno)); | ||||
|                     antd_close(cl); | ||||
| 					dput(rq->request, "LUA_CL_DATA", NULL); | ||||
|                     return antd_create_task(NULL, data, NULL, rq->client->last_io); | ||||
|                 } | ||||
|             } | ||||
|             task = antd_create_task(process, (void *)rq, NULL, time(NULL)); | ||||
|             antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); | ||||
|             antd_task_bind_event(task, cl->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); | ||||
|             return task; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void* handle(void* data) | ||||
| { | ||||
| 	antd_request_t *rq = (antd_request_t *)data; | ||||
| 	// connect to socket | ||||
| 	int fd = open_unix_socket(); | ||||
| 	if(fd < 0) | ||||
| 	{ | ||||
| 		antd_error(rq->client, 503, "Service unavailable"); | ||||
|     antd_request_t *rq = (antd_request_t *)data; | ||||
|     // connect to socket | ||||
|     int fd = open_unix_socket(); | ||||
|     if(fd < 0) | ||||
|     { | ||||
|         antd_error(rq->client, 503, "Service unavailable"); | ||||
|         return antd_create_task(NULL, data, NULL, rq->client->last_io); | ||||
| 	} | ||||
| 	LOG("Connected to lua server at %d", fd); | ||||
| 	set_nonblock(fd); | ||||
| 	// write all header to lua | ||||
| 	antd_client_t* cl = (antd_client_t*) malloc(sizeof(antd_client_t)); | ||||
| 	(void)memset(cl, 0, sizeof(antd_client_t)); | ||||
| 	cl->sock = fd; | ||||
| 	time(&cl->last_io); | ||||
| 	cl->ssl = NULL; | ||||
| 	cl->state = ANTD_CLIENT_PLUGIN_EXEC; | ||||
| 	cl->z_status = 0; | ||||
| 	cl->z_level = ANTD_CNONE; | ||||
| 	cl->zstream = NULL; | ||||
| 	push_dict_to_socket(cl, "request","HTTP_REQUEST", rq->request); | ||||
| 	antd_send(cl,"\r\n", 2); | ||||
| 	dput(rq->request, "LUA_CL_DATA", cl); | ||||
| 	antd_task_t* task = antd_create_task(process, (void *)rq, NULL, time(NULL)); | ||||
| 	antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); | ||||
| 	antd_task_bind_event(task, fd, 0, TASK_EVT_ON_READABLE); | ||||
| 	return task; | ||||
|     } | ||||
|     LOG("Connected to lua server at %d", fd); | ||||
|     set_nonblock(fd); | ||||
|     // write all header to lua | ||||
|     antd_client_t* cl = (antd_client_t*) malloc(sizeof(antd_client_t)); | ||||
|     (void)memset(cl, 0, sizeof(antd_client_t)); | ||||
|     cl->sock = fd; | ||||
|     time(&cl->last_io); | ||||
|     cl->ssl = NULL; | ||||
|     cl->state = ANTD_CLIENT_PLUGIN_EXEC; | ||||
|     cl->z_status = 0; | ||||
|     cl->z_level = ANTD_CNONE; | ||||
|     cl->zstream = NULL; | ||||
| 	rq->client->z_level = ANTD_CNONE; | ||||
|     push_dict_to_socket(cl, "request","HTTP_REQUEST", rq->request); | ||||
|     antd_send(cl,"\r\n", 2); | ||||
|     dput(rq->request, "LUA_CL_DATA", cl); | ||||
|     antd_task_t* task = antd_create_task(process, (void *)rq, NULL, time(NULL)); | ||||
|     antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); | ||||
|     antd_task_bind_event(task, fd, 0, TASK_EVT_ON_READABLE); | ||||
|     return task; | ||||
| } | ||||
| void destroy() | ||||
| { | ||||
| 	if(pid > 0) | ||||
| 	{ | ||||
| 		kill(pid, SIGKILL); | ||||
| 	} | ||||
| 	LOG("Exit LUA Handle"); | ||||
|     if(pid > 0) | ||||
|     { | ||||
|         kill(pid, SIGHUP); | ||||
|     } | ||||
|     LOG("Exit LUA Handle"); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user