diff options
Diffstat (limited to 'adapter/http_adapter/src')
| -rw-r--r-- | adapter/http_adapter/src/adapter.cpp | 458 | ||||
| -rw-r--r-- | adapter/http_adapter/src/adapter.h | 112 |
2 files changed, 570 insertions, 0 deletions
diff --git a/adapter/http_adapter/src/adapter.cpp b/adapter/http_adapter/src/adapter.cpp new file mode 100644 index 0000000..94cd70f --- /dev/null +++ b/adapter/http_adapter/src/adapter.cpp @@ -0,0 +1,458 @@ +#include "adapter.h" + +//TODO: +//每个函数都要判断返回值 done +// lua错误处理,比如函数没有注册,resume的返回值判断然后打印错误, 不再resume该协程 done +//压栈之前要check_stack done +//流结束clear_ctx之外还要释放该协程,自动垃圾回收?做实验验证一下 done +//destroy,释放lua_state done +//多线程 m * n个虚拟机(m是线程数量,n是lua插件数量) done +//错误处理,日志, 工程化,日志完备 + +static void* g_logger = NULL; +static std::vector<std::vector<lua_State*>> g_http_lua_states; +extern int g_iThreadNum; + +static void lua_traceback(const char *func_name, lua_State *lua_state, int ret){ + int n = lua_gettop(lua_state); + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "%s error: ret is %d, traceback is: ", func_name, ret); + for(int i = -1; i >= 0 - n; i--){ + std::string type = std::string(lua_typename(lua_state, lua_type(lua_state, i))); + if(type == "string"){ + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "%s", lua_tostring(lua_state, i)); + } + } + lua_pop(lua_state, n); +} + +std::string _inet_ntoa(uint32_t ip) +{ + const char *_ip = inet_ntoa(*(struct in_addr *)&ip); + return std::string(_ip); +} + +//copy from suricata +static int lua_push_string_buffer(lua_State *lua_state, const char *input, size_t input_len) +{ + if (input_len % 4 != 0) { + /* we're using a buffer sized at a multiple of 4 as lua_pushlstring generates + * invalid read errors in valgrind otherwise. Adding in a nul to be sure. + * Buffer size = len + 1 (for nul) + whatever makes it a multiple of 4 */ + size_t buflen = input_len + 1 + ((input_len + 1) % 4); + char buf[buflen]; + memset(buf, 0x00, buflen); + memcpy(buf, input, input_len); + buf[input_len] = '\0'; + /* return value through lua_state, as a luastring */ + lua_pushlstring(lua_state, buf, input_len); + } else { + lua_pushlstring(lua_state, input, input_len); + } + return 1; +} + +static int get_stream_tuple5(lua_State *lua_state){ + lua_getglobal(lua_state, "cur_http_sess_ctx"); + http_sess_ctx *sess_ctx = (http_sess_ctx *)lua_touserdata(lua_state, -1); + lua_pop(lua_state, 1); + if(sess_ctx == NULL){ + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "sess_ctx is null"); + return -1; + } + stream_tuple5& tuple5 = sess_ctx->tuple5; + if(tuple5.parse_done == true){ + lua_newtable(lua_state); + lua_push_string_buffer(lua_state, "ip_version", std::string("ip_version").length()); + lua_push_string_buffer(lua_state, tuple5.ip_version.c_str(), tuple5.ip_version.length()); + lua_settable(lua_state, -3); + lua_push_string_buffer(lua_state, "stream_type", std::string("stream_type").length()); + lua_push_string_buffer(lua_state, tuple5.stream_type.c_str(), tuple5.stream_type.length()); + lua_settable(lua_state, -3); + lua_push_string_buffer(lua_state, "sip", std::string("sip").length()); + lua_push_string_buffer(lua_state, tuple5.sip.c_str(), tuple5.sip.length()); + lua_settable(lua_state, -3); + lua_push_string_buffer(lua_state, "dip", std::string("dip").length()); + lua_push_string_buffer(lua_state, tuple5.dip.c_str(), tuple5.dip.length()); + lua_settable(lua_state, -3); + lua_push_string_buffer(lua_state, "sport", std::string("sport").length()); + lua_pushinteger(lua_state, tuple5.sport); + lua_settable(lua_state, -3); + lua_push_string_buffer(lua_state, "dport", std::string("dport").length()); + lua_pushinteger(lua_state, tuple5.dport); + lua_settable(lua_state, -3); + return 0; + } + return -1; +} + +static int _get_stream_info(lua_State *lua_state, int status, lua_KContext yieldk_ctx){ + int ret = get_stream_tuple5(lua_state); + if(ret < 0){ + lua_yieldk(lua_state, 0, 0, _get_stream_info); + } + return 1; +} + +static int get_stream_info(lua_State* lua_state){ + MESA_handle_runtime_log(g_logger, RLOG_LV_DEBUG, LOG_MODULE_NAME, "call get_strem_info"); + return _get_stream_info(lua_state, 0, 0); +} + +static int get_http_header(lua_State *lua_state, int type){ + lua_getglobal(lua_state, "cur_http_sess_ctx"); + http_sess_ctx *sess_ctx = (http_sess_ctx *)lua_touserdata(lua_state, -1); + lua_pop(lua_state, 1); + if(sess_ctx == NULL){ + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "sess_ctx is null"); + return -1; + } + std::unordered_set<std::string> required_regions; + lua_pushnil(lua_state); + while(lua_next(lua_state, -2) != 0){ + required_regions.insert(std::string(lua_tostring(lua_state, -1))); + lua_pop(lua_state, 1); + } + http_header& header = (type == HTTP_TYPE_REQUEST ? sess_ctx->req_header : sess_ctx->resp_header); + if(header.parse_done == true){ + MESA_handle_runtime_log(g_logger, RLOG_LV_DEBUG, LOG_MODULE_NAME, "header parse done"); + lua_newtable(lua_state); + for(auto region : header.std_regions){ + if(required_regions.find("ALL") != required_regions.end() || required_regions.find(region.first) != required_regions.end()){ + lua_push_string_buffer(lua_state, region.first.c_str(), region.first.length()); + lua_push_string_buffer(lua_state, region.second.c_str(), region.second.length()); + lua_settable(lua_state, -3); + } + } + if(!header.other_regions.empty()){ + if(required_regions.find("ALL") != required_regions.end() || required_regions.find("HTTP_OTHER_REGIONS") != required_regions.end()){ + lua_push_string_buffer(lua_state, "HTTP_OTHER_REGIONS", std::string("HTTP_OTHER_REGIONS").length()); + lua_newtable(lua_state); + int i = 1; + for(auto region : header.other_regions){ + lua_push_string_buffer(lua_state, region.c_str(), region.length()); + lua_rawseti(lua_state, -2, i++); + } + lua_settable(lua_state, -3); + } + } + return 0; + } + return -1; +} + +static int _get_http_request_header(lua_State *lua_state, int status, lua_KContext yieldk_ctx){ + MESA_handle_runtime_log(g_logger, RLOG_LV_DEBUG, LOG_MODULE_NAME, "call get_http_request_header"); + int ret = get_http_header(lua_state, HTTP_TYPE_REQUEST); + if(ret < 0){ + lua_yieldk(lua_state, 0, 0, _get_http_request_header); + } + return 1; +} + +static int get_http_request_header(lua_State* lua_state){ + return _get_http_request_header(lua_state, 0, 0); +} + +static int _get_http_response_header(lua_State *lua_state, int status, lua_KContext yieldk_ctx){ + int ret = get_http_header(lua_state, HTTP_TYPE_RESPONSE); + if(ret < 0){ + lua_yieldk(lua_state, 0, 0, _get_http_response_header); + } + return 1; +} + +static int get_http_response_header(lua_State* lua_state){ + return _get_http_response_header(lua_state, 0, 0); +} + +static int get_http_body(lua_State *lua_state, int type){ + MESA_handle_runtime_log(g_logger, RLOG_LV_DEBUG, LOG_MODULE_NAME, "call _get_http_response_body"); + lua_getglobal(lua_state, "cur_http_sess_ctx"); + http_sess_ctx *sess_ctx = (http_sess_ctx *)lua_touserdata(lua_state, -1); + lua_pop(lua_state, 1); + if(sess_ctx == NULL){ + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "sess_ctx is null"); + return -1; + } + http_body& body = (type == HTTP_TYPE_REQUEST? sess_ctx->req_body : sess_ctx->resp_body); + if(body.data_end == true || body.buf != nullptr){ + lua_newtable(lua_state); + lua_push_string_buffer(lua_state, "block_id", std::string("block_id").length()); + lua_pushinteger(lua_state, body.block_id); + lua_settable(lua_state, -3); + lua_push_string_buffer(lua_state, "data_end", std::string("data_end").length()); + lua_pushboolean(lua_state, body.data_end); + lua_settable(lua_state, -3); + lua_push_string_buffer(lua_state, "buf", std::string("buf").length()); + lua_pushlightuserdata(lua_state, body.buf); + lua_settable(lua_state, -3); + lua_push_string_buffer(lua_state, "buflen", std::string("buflen").length()); + lua_pushinteger(lua_state, body.buflen); + lua_settable(lua_state, -3); + body.buf = nullptr; + body.buflen = 0; + return 0; + } + return -1; +} + +static int _get_http_request_body(lua_State *lua_state, int status, lua_KContext yieldk_ctx){ + int ret = get_http_body(lua_state, HTTP_TYPE_REQUEST); + if(ret < 0){ + lua_yieldk(lua_state, 0, 0, _get_http_request_body); + } + return 1; +} + +static int get_http_request_body(lua_State* lua_state){ + return _get_http_request_body(lua_state, 0, 0); +} + +static int _get_http_response_body(lua_State *lua_state, int status, lua_KContext yieldk_ctx){ + int ret = get_http_body(lua_state, HTTP_TYPE_RESPONSE); + if(ret < 0){ + lua_yieldk(lua_state, 0, 0, _get_http_response_body); + } + return 1; +} + +static int get_http_response_body(lua_State* lua_state){ + return _get_http_response_body(lua_state, 0, 0); +} + + +static int load_lua_http_plug(const char *profile, int thread_num){ + const char *section = "main"; + char file_path[LUA_SAPP_PATH_MAX] = ""; + char entry_type[LUA_SAPP_SYMBOL_MAX] = ""; + MESA_load_profile_string_def(profile, section, "file_path", file_path, sizeof(file_path), ""); + MESA_load_profile_string_def(profile, section, "entry_type", entry_type, sizeof(entry_type), ""); + MESA_handle_runtime_log(g_logger, RLOG_LV_INFO, LOG_MODULE_NAME, "MESA_prof_load: profile is %s, section is %s," + "file_path is %s, entry_type is %s\n", profile, section, file_path, entry_type); + if(strncmp(entry_type, "http", LUA_SAPP_SYMBOL_MAX) == 0){ + for(int i = 0; i < thread_num; i++){ + lua_State *lua_state = luaL_newstate(); + if(lua_state == NULL){ + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "failed to LuaL_newstate"); + return -1; + } + luaL_openlibs(lua_state); + int ret = luaL_dofile(lua_state, file_path); + if(ret){ + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "error: ret is %d, file_path is %s\n", ret, file_path); + return -1; + } + lua_register(lua_state, "get_stream_info", get_stream_info); + lua_register(lua_state, "get_http_request_header", get_http_request_header); + lua_register(lua_state, "get_http_response_header", get_http_response_header); + lua_register(lua_state, "get_http_request_body", get_http_request_body); + lua_register(lua_state, "get_http_response_body", get_http_response_body); + g_http_lua_states[i].push_back(lua_state); + } + } + return 0; +} + +static int process_lua_plug_conflist(const char* filename, int thread_num) +{ + char lua_plug_conf_path[LUA_SAPP_PATH_MAX] = {0}; + FILE* fp = fopen(filename, "r"); + if(fp == NULL){ + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "process_conflist() fopen %s error!\n", filename); + return -1; + } + while(feof(fp) == 0){ + if((fgets(lua_plug_conf_path, LUA_SAPP_PATH_MAX, fp)) == NULL){ + fclose(fp); + fp=NULL; + return 0; + } + if(lua_plug_conf_path[0]=='#'){ + continue; + } + int len = strnlen(lua_plug_conf_path, LUA_SAPP_PATH_MAX); + lua_plug_conf_path[len - 1] = '\0'; + int ret = load_lua_http_plug(lua_plug_conf_path, thread_num); + if(ret < 0){ + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "failed to load_lua_plug: conf_path is %s\n", lua_plug_conf_path); + } + } + fclose(fp); + fp=NULL; + return 0; +} + +static http_sess_ctx* init_http_sess_ctx(int thread_seq){ + http_sess_ctx *ctx = new http_sess_ctx(); + for(lua_State *lua_state : g_http_lua_states[thread_seq]){ + lua_State* coroutine = lua_newthread(lua_state); + int ret = lua_checkstack(lua_state, 1); + if(ret != 1){ + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "do not have enough space, ret is %d\n", ret); + continue; + } + ctx->coroutines.push_back(coroutine); + } + return ctx; +} + +static void clear_http_sess_ctx(http_sess_ctx *ctx){ + delete ctx; + ctx = NULL; +} + + +std::string utils_inet_ntoa(uint32_t ip) +{ + const char *_ip = inet_ntoa(*(struct in_addr *)&ip); + return std::string(_ip); +} + +extern "C" uchar http_adapter_http_entry(stSessionInfo* session_info, void **param, int thread_seq, struct streaminfo *a_tcp, void *a_packet){ + uchar ret = PROT_STATE_GIVEME; + http_sess_ctx *ctx = (http_sess_ctx*)*param; + http_infor *a_http = (http_infor *)(session_info->app_info); + bool stream_begin = false; + if(session_info == nullptr){ + return PROT_STATE_DROPME; + } + if(ctx == nullptr){ + ctx = init_http_sess_ctx(thread_seq); + *param = ctx; + stream_begin = true; + } + if(ctx->tuple5.parse_done == false){ + struct stream_tuple4_v4 *tuple4_v4 = a_tcp->addr.tuple4_v4; + ctx->tuple5.ip_version = "IPV4"; + if(a_tcp->type == STREAM_TYPE_TCP){ + ctx->tuple5.stream_type = "TCP"; + } + if(a_tcp->type == STREAM_TYPE_UDP){ + ctx->tuple5.stream_type = "UDP"; + } + ctx->tuple5.sip = utils_inet_ntoa(tuple4_v4->saddr); + ctx->tuple5.dip = utils_inet_ntoa(tuple4_v4->daddr); + ctx->tuple5.sport = ntohs(tuple4_v4->source); + ctx->tuple5.dport = ntohs(tuple4_v4->dest); + ctx->tuple5.parse_done = true; + } + uchar curdir = a_http->curdir; + switch(session_info->prot_flag) + { + case HTTP_STATE: + case HTTP_CONTENT: + break; + case HTTP_UNGZIP_CONTENT: + if(curdir == DIR_C2S){ + ctx->req_body.block_id++; + ctx->req_body.buf = session_info->buf; + ctx->req_body.buflen = session_info->buflen; + } + if(curdir == DIR_S2C){ + ctx->resp_body.block_id++; + ctx->resp_body.buf = session_info->buf; + ctx->resp_body.buflen = session_info->buflen; + } + break; + default: + std::string key(http_proto_flag2region(session_info->prot_flag)); + std::string value((const char*)(session_info->buf), session_info->buflen); + if(curdir == DIR_C2S){ + if(key == "HTTP_OTHER_REGIONS"){ + ctx->req_header.other_regions.insert(value); + } + else{ + ctx->req_header.std_regions.insert({key, value}); + } + } + else{ + if(key == "HTTP_OTHER_REGIONS"){ + ctx->resp_header.other_regions.insert(value); + } + else{ + ctx->resp_header.std_regions.insert({key, value}); + } + } + break; + } + uchar http_state = a_http->http_state; + //header over + if(http_state == HTTP_DATA_BEGIN){ + if(curdir == DIR_C2S){ + ctx->req_header.parse_done = true; + } + if(curdir == DIR_S2C){ + ctx->resp_header.parse_done = true; + } + } + //data over + if(http_state == HTTP_DATA_END){ + if(curdir == DIR_C2S){ + ctx->req_body.data_end = true; + } + if(curdir == DIR_S2C){ + ctx->resp_body.data_end = true; + } + } + //resume coroutine + for(lua_State*& coroutine : ctx->coroutines){ + if(coroutine == nullptr){ + continue; + } + /* + int ret = lua_checkstack(coroutine, 1); + if(ret != 1){ + //do log + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "do not have enough space, ret is %d", ret); + continue; + } + */ + lua_pushlightuserdata(coroutine, (void *)ctx); + lua_setglobal(coroutine, "cur_http_sess_ctx"); + if(stream_begin){ + lua_getglobal(coroutine, "process"); + } + ret = lua_resume(coroutine, NULL, 0); + if(ret == LUA_OK){ + coroutine = nullptr; + continue; + } + if(ret != LUA_YIELD){ + lua_traceback("lua_resume", coroutine, ret); + coroutine = nullptr; + } + } + if(session_info->session_state & SESSION_STATE_CLOSE){ + MESA_handle_runtime_log(g_logger, RLOG_LV_INFO, LOG_MODULE_NAME, "close tcp stream"); + clear_http_sess_ctx(ctx); + *param = NULL; + } + return ret; +} + +extern "C" int http_adapter_init(void){ + g_logger = MESA_create_runtime_log_handle("./log/lua_sapp/http_adapter/http_adapter.log", 10); + if(g_logger == NULL){ + MESA_handle_runtime_log(g_logger, RLOG_LV_FATAL, LOG_MODULE_NAME, "%s init : get log handle error!", HTTP_SERVICE_PLUGNAME); + return -1; + } + int thread_num = g_iThreadNum;; + for(int i = 0; i < thread_num; i++){ + g_http_lua_states.push_back(std::vector<lua_State*>()); + } + + // get all business lua script which register http + const char *conflist_path = "./plug/lua/conflist_lua.inf"; + process_lua_plug_conflist(conflist_path, thread_num); + return 0; +} + +extern "C" void http_adapter_destroy(void){ + for(auto states : g_http_lua_states){ + for(auto state : states){ + lua_close(state); + } + } + return; +} + diff --git a/adapter/http_adapter/src/adapter.h b/adapter/http_adapter/src/adapter.h new file mode 100644 index 0000000..1c4a790 --- /dev/null +++ b/adapter/http_adapter/src/adapter.h @@ -0,0 +1,112 @@ +/* + * HTTP_Service.h + * + * Created on: 2013-8-19 + * Author: lishu + */ + +#ifndef HTTP_SERVICE_H_ +#define HTTP_SERVICE_H_ + +#include <iostream> +#include <string> +#include <vector> +#include <unordered_map> +#include <unordered_set> + +#include <stdio.h> +#include <string.h> +#include <pthread.h> +#include <time.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <ctype.h> +#include <stdlib.h> +#include <regex.h> +#include "stream.h" +#include "http.h" +#include "MESA/MESA_prof_load.h" +#include "MESA/MESA_handle_logger.h" + +extern "C" { + #include "lua.h" + #include "lualib.h" + #include "lauxlib.h" +} +#define HTTP_SERVICE_PLUGNAME "new_http_service.so" +#define LOG_PATH "./log/new_http_service/" + +#define LOG_MODULE_NAME "SAPP_LUA" +#define LUA_SAPP_SYMBOL_MAX 64 +#define LUA_SAPP_PATH_MAX 256 +#define LUA_SAPP_STRING_MAX 2048 +#define LUA_ENTRY_TYPE_NUM 8 +enum lua_entry_type{ + LUA_ENTRY_TYPE_IP = 0, + LUA_ENTRY_TYPE_TCP, + LUA_ENTRY_TYPE_UDP, + LUA_ENTRY_TYPE_HTTP, + LUA_ENTRY_TYPE_TLS, + LUA_ENTRY_TYPE_DNS, + LUA_ENTRY_TYPE_MAIL, + LUA_ENTRY_TYPE_FTP +}; + +enum http_type{ + HTTP_TYPE_REQUEST = 0, + HTTP_TYPE_RESPONSE +}; +class http_header{ +public: + bool parse_done; + std::unordered_map<std::string, std::string> std_regions; + std::unordered_set<std::string> other_regions; + http_header() : parse_done(false){} +}; + +class http_body{ +public: + bool data_end; + int block_id; + void *buf; + int buflen; + http_body() : data_end(false), block_id(-1), buf(nullptr), buflen(0){} +}; + +class stream_tuple5{ +public: + bool parse_done; + std::string ip_version; //IPV4 or IPV6 + std::string stream_type; //TCP or UDP + std::string sip; + std::string dip; + uint16_t sport; + uint16_t dport; + stream_tuple5() : parse_done(false){} +}; + +class http_sess_ctx{ +public: + stream_tuple5 tuple5; + http_header req_header; + http_header resp_header; + http_body req_body; + http_body resp_body; + std::vector<lua_State*> coroutines; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +uchar NEW_HTTP_SERVICE_ENTRY(stSessionInfo* session_info, void **param, int thread_seq, struct streaminfo *a_tcp, void *a_packet); +int NEW_HTTP_SERVICE_INIT(void); +void NEW_HTTP_SERVICE_DESTROY(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HTTP_SERVICE_H_ */ |
