This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
cuiyiming-lua-sapp/test/new_http_service/adapter.cpp

474 lines
15 KiB
C++
Raw Normal View History

2019-04-17 14:30:11 +08:00
#include "adapter.h"
//TODO:
2019-04-22 14:29:45 +08:00
//每个函数都要判断返回值 done
// lua错误处理比如函数没有注册resume的返回值判断然后打印错误, 不再resume该协程 done
//压栈之前要check_stack done
//流结束clear_ctx之外还要释放该协程自动垃圾回收做实验验证一下 done
//destroy释放lua_state done
//多线程 m * n个虚拟机
//dumpfile改成在线试一下
//错误处理,日志, 工程化,日志完备
2019-04-17 14:30:11 +08:00
static void* g_logger = NULL;
static std::vector<std::vector<lua_plug>> g_lua_plugs(LUA_ENTRY_TYPE_NUM, std::vector<lua_plug>());
2019-04-22 14:29:45 +08:00
static void lua_traceback(const char *func_name, lua_State *lua_state, int ret){
int n = lua_gettop(lua_state);
printf("%s error: ret is %d, traceback is:\n", 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"){
printf("%s\n", 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);
}
2019-04-17 14:30:11 +08:00
//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;
}
2019-04-22 14:29:45 +08:00
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){
//do log
std::cout<<"sess_ctx is null"<<std::endl;
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;
}
2019-04-17 14:30:11 +08:00
2019-04-22 14:29:45 +08:00
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){
//printf("call get_strem_info\n");
return _get_stream_info(lua_state, 0, 0);
}
static int get_http_header(lua_State *lua_state, int type){
2019-04-17 14:30:11 +08:00
lua_getglobal(lua_state, "cur_http_sess_ctx");
http_sess_ctx *sess_ctx = (http_sess_ctx *)lua_touserdata(lua_state, -1);
2019-04-22 14:29:45 +08:00
lua_pop(lua_state, 1);
2019-04-17 14:30:11 +08:00
if(sess_ctx == NULL){
//do log
std::cout<<"sess_ctx is null"<<std::endl;
2019-04-22 14:29:45 +08:00
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){
//printf("header parse done\n");
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);
}
}
2019-04-17 14:30:11 +08:00
return 0;
}
2019-04-22 14:29:45 +08:00
return -1;
}
static int _get_http_request_header(lua_State *lua_state, int status, lua_KContext yieldk_ctx){
//printf("call get_http_request_header\n");
int ret = get_http_header(lua_state, HTTP_TYPE_REQUEST);
if(ret < 0){
lua_yieldk(lua_state, 0, 0, _get_http_request_header);
2019-04-17 14:30:11 +08:00
}
return 1;
}
2019-04-22 14:29:45 +08:00
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);
}
2019-04-17 14:30:11 +08:00
return 1;
}
2019-04-22 14:29:45 +08:00
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){
//printf("call _get_http_response_body\n");
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){
//do log
std::cout<<"sess_ctx is null"<<std::endl;
return -1;
2019-04-17 14:30:11 +08:00
}
2019-04-22 14:29:45 +08:00
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;
2019-04-17 14:30:11 +08:00
}
2019-04-22 14:29:45 +08:00
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);
}
2019-04-17 14:30:11 +08:00
static int load_lua_plug(const char *profile){
std::unordered_map<std::string, int> type_map = {
{"ip", LUA_ENTRY_TYPE_IP},
{"tcp", LUA_ENTRY_TYPE_TCP},
{"udp", LUA_ENTRY_TYPE_UDP},
{"http", LUA_ENTRY_TYPE_HTTP},
{"tls", LUA_ENTRY_TYPE_TLS},
{"dns", LUA_ENTRY_TYPE_DNS},
{"mail", LUA_ENTRY_TYPE_MAIL},
{"ftp", LUA_ENTRY_TYPE_FTP}
2019-04-22 14:29:45 +08:00
};
2019-04-17 14:30:11 +08:00
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), "http");
lua_State *lua_state = luaL_newstate();
2019-04-22 14:29:45 +08:00
if(lua_state == NULL){
printf("failed to LuaL_newstate\n");
return -1;
}
2019-04-17 14:30:11 +08:00
luaL_openlibs(lua_state);
2019-04-22 14:29:45 +08:00
int ret = luaL_dofile(lua_state, file_path);
if(ret){
//log error
printf("error: ret is %d, file_path is %s\n", ret, file_path);
return -1;
}
//TODO: what if not register, rusume handle error
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);
2019-04-17 14:30:11 +08:00
lua_plug plug;
plug.file_path = std::string(file_path);
plug.entry_type = (enum lua_entry_type)type_map[std::string(entry_type)];
plug.lua_state = lua_state;
g_lua_plugs[plug.entry_type].push_back(plug);
return 0;
}
2019-04-22 14:29:45 +08:00
static int process_lua_plug_conflist(const char* filename)
2019-04-17 14:30:11 +08:00
{
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';
2019-04-22 14:29:45 +08:00
int ret = load_lua_plug(lua_plug_conf_path);
if(ret < 0){
printf("failed to load_lua_plug: conf_path is %s\n", lua_plug_conf_path);
}
2019-04-17 14:30:11 +08:00
}
fclose(fp);
fp=NULL;
return 0;
}
static http_sess_ctx* init_http_sess_ctx(){
http_sess_ctx *ctx = new http_sess_ctx();
2019-04-22 14:29:45 +08:00
for(lua_plug plug : g_lua_plugs[LUA_ENTRY_TYPE_HTTP]){
lua_State* lua_state = plug.lua_state;
lua_State* coroutine = lua_newthread(lua_state);
int ret = lua_checkstack(lua_state, 1);
if(ret != 1){
//do log
printf("do not have enough space, ret is %d\n", ret);
break;
}
ctx->coroutines.push_back(coroutine);
}
2019-04-17 14:30:11 +08:00
return ctx;
}
static void clear_http_sess_ctx(http_sess_ctx *ctx){
delete ctx;
ctx = NULL;
}
2019-04-22 14:29:45 +08:00
std::string utils_inet_ntoa(uint32_t ip)
{
const char *_ip = inet_ntoa(*(struct in_addr *)&ip);
return std::string(_ip);
2019-04-17 14:30:11 +08:00
}
uchar NEW_HTTP_SERVICE_ENTRY(stSessionInfo* session_info, void **param, int thread_seq, struct streaminfo *a_tcp, void *a_packet){
2019-04-22 14:29:45 +08:00
uchar ret = PROT_STATE_GIVEME;
2019-04-17 14:30:11 +08:00
http_sess_ctx *ctx = (http_sess_ctx*)*param;
http_infor *a_http = (http_infor *)(session_info->app_info);
2019-04-22 14:29:45 +08:00
bool stream_begin = false;
if(session_info == nullptr){
2019-04-17 14:30:11 +08:00
return PROT_STATE_DROPME;
}
2019-04-22 14:29:45 +08:00
if(ctx == nullptr){
2019-04-17 14:30:11 +08:00
ctx = init_http_sess_ctx();
*param = ctx;
2019-04-22 14:29:45 +08:00
stream_begin = true;
2019-04-17 14:30:11 +08:00
}
2019-04-22 14:29:45 +08:00
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;
}
2019-04-17 14:30:11 +08:00
uchar curdir = a_http->curdir;
switch(session_info->prot_flag)
{
case HTTP_STATE:
case HTTP_CONTENT:
break;
case HTTP_UNGZIP_CONTENT:
2019-04-22 14:29:45 +08:00
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;
}
2019-04-17 14:30:11 +08:00
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){
2019-04-22 14:29:45 +08:00
if(key == "HTTP_OTHER_REGIONS"){
ctx->req_header.other_regions.insert(value);
}
else{
ctx->req_header.std_regions.insert({key, value});
}
2019-04-17 14:30:11 +08:00
}
else{
2019-04-22 14:29:45 +08:00
if(key == "HTTP_OTHER_REGIONS"){
ctx->resp_header.other_regions.insert(value);
}
else{
ctx->resp_header.std_regions.insert({key, value});
}
2019-04-17 14:30:11 +08:00
}
break;
}
uchar http_state = a_http->http_state;
2019-04-22 14:29:45 +08:00
//printf("curdir is %d, http_state is %d\n", curdir, http_state);
//header over
2019-04-17 14:30:11 +08:00
if(http_state == HTTP_DATA_BEGIN){
2019-04-22 14:29:45 +08:00
if(curdir == DIR_C2S){
ctx->req_header.parse_done = true;
}
if(curdir == DIR_S2C){
ctx->resp_header.parse_done = true;
2019-04-17 14:30:11 +08:00
}
}
2019-04-22 14:29:45 +08:00
//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
printf("do not have enough space, ret is %d\n", 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;
}
}
2019-04-17 14:30:11 +08:00
if(session_info->session_state & SESSION_STATE_CLOSE){
2019-04-22 14:29:45 +08:00
//printf("close tcp stream\n");
2019-04-17 14:30:11 +08:00
clear_http_sess_ctx(ctx);
*param = NULL;
}
2019-04-22 14:29:45 +08:00
return ret;
2019-04-17 14:30:11 +08:00
}
int NEW_HTTP_SERVICE_INIT(void)
{
g_logger = MESA_create_runtime_log_handle("./log/http/http_service", 10);
if(g_logger == NULL){
printf("%s init : get log handle error!\n", HTTP_SERVICE_PLUGNAME);
return -1;
}
2019-04-22 14:29:45 +08:00
2019-04-17 14:30:11 +08:00
// get all business lua script which register http
const char *conflist_path = "./plug/lua/conflist_lua.inf";
if(g_lua_plugs[LUA_ENTRY_TYPE_HTTP].size() == 0){
process_lua_plug_conflist(conflist_path);
}
return 0;
}
void NEW_HTTP_SERVICE_DESTROY(void)
{
2019-04-22 14:29:45 +08:00
for(auto plug : g_lua_plugs[LUA_ENTRY_TYPE_HTTP]){
lua_close(plug.lua_state);
}
2019-04-17 14:30:11 +08:00
return ;
}