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
tango-tfe/plugin/protocol/http2/src/http2_plugin.cpp

220 lines
5.8 KiB
C++
Raw Normal View History

/*************************************************************************
> File Name: detect_http2_plugin.cpp
> Author:
> Mail:
> Created Time: 20180911 153854
************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <event.h>
#include <tfe_stream.h>
#include <tfe_utils.h>
#include <tfe_plugin.h>
#include <tfe_proxy.h>
#include <malloc.h>
#include <http2_stream.h>
#include <http2_common.h>
#include <MESA/MESA_prof_load.h>
/* Magic Header : PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n */
static const uint8_t kMagicHello[] = {
0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54,
0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a,
0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a
};
#define get_u_int8_t(X,O) (*(u_int8_t *)(((u_int8_t *)X) + O))
#define TFE_BASIC_CFG "conf/tfe/tfe.conf"
#define MAGIC_FRAME_LENGTH 24
#define SET_FRAME_LENGTH 9
struct event_timer_ctx
{
Http2Plugin *plugin;
unsigned int thread_id;
};
void load_logging_conf(const char *config)
{
RTLogInit2Data *logging_sc_lid = logger();
2020-09-24 17:47:35 +08:00
logging_sc_lid->handle = MESA_create_runtime_log_handle("http2", RLOG_LV_DEBUG);
if(logging_sc_lid->handle == NULL){
TFE_LOG_ERROR(logging_sc_lid->handle, "Create log runtime_log_handle error, init failed!");
}
return;
}
2019-05-24 19:06:43 +08:00
UNUSED static void http2_plugin_timer_gc_cb(evutil_socket_t fd, short what, void * arg)
{
struct tfe_h2_stream *h2_stream_info = (struct tfe_h2_stream *)arg;
sess_data_ctx_fini(h2_stream_info, NULL, h2_stream_info->thread_id);
// Although this function is not called now,
// there is a potential bug in memory leaks where it is called.
// A better practice is to free the memory in the sess_data_ctx_fini() function.
free(h2_stream_info);
h2_stream_info = NULL;
}
static int
http2_plugin_init(struct tfe_proxy * proxy)
{
2019-05-24 19:06:43 +08:00
UNUSED Http2Plugin *plugin = http2_plugin();
unsigned int thread_nu = tfe_proxy_get_work_thread_count();
load_logging_conf(TFE_BASIC_CFG);
for (unsigned int thread_id = 0; thread_id < thread_nu; thread_id++){
#if 0
struct tfe_session_info_t h2_stream_info = plugin->h2_stream_info[thread_id];
TAILQ_INIT(&(h2_stream_info.list));
h2_stream_info.thread_id = thread_id;
h2_stream_info.as_client = 0;
struct event_base * ev_base = tfe_proxy_get_work_thread_evbase(thread_id);
struct timeval timer = {0, 500 * 1000};
struct event * event = event_new(ev_base, -1, EV_PERSIST, http2_plugin_timer_gc_cb, &h2_stream_info);
if (unlikely(event == NULL)){
TFE_LOG_ERROR(logger()->handle, "Create timer error, init failed!");
}
evtimer_add(event, &timer);
plugin->event[thread_id] = event;
#endif
}
return 0;
}
static void
http2_plugin_deinit(struct tfe_proxy * proxy)
{
return;
}
static int
http2_stream_open(const struct tfe_stream *stream, unsigned int thread_id,
enum tfe_conn_dir dir, void ** pme)
{
struct stream_tap_info_t *tapinfo = ALLOC(struct stream_tap_info_t, 1);
assert(tapinfo);
memset(tapinfo, 0, sizeof(struct stream_tap_info_t));
tapinfo->preempted = 0;
tapinfo->h2_stream_info = tfe_session_info_init();
*pme = (void *)tapinfo;
return 0;
}
/*setting frame: 00 00 06 04 00 00 00 00 00 00 04**/
static int
search_up_stream_data(const unsigned char * data, size_t len)
{
uint8_t indetifier = 0;
if ((get_u_int8_t(data, 3) != 0x4) && (get_u_int8_t(data, 4) != 0) && (get_u_int8_t(data, 9) != 0))
{
return 0;
}
indetifier = get_u_int8_t(data, 10);
if (indetifier < NGHTTP2_SETTINGS_HEADER_TABLE_SIZE || indetifier > NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE)
{
return 0;
}
return 1;
}
static enum tfe_stream_action
http2_stream_data(const struct tfe_stream * stream, unsigned int thread_id,
enum tfe_conn_dir dir, const unsigned char * data, size_t len, void ** pme)
{
static unsigned int defer_bytes = 0;
struct stream_tap_info_t *tapinfo = (struct stream_tap_info_t *)(*pme);
if (tapinfo->preempted == 0){
if (dir == CONN_DIR_UPSTREAM){
if (len < SET_FRAME_LENGTH){
defer_bytes = SET_FRAME_LENGTH;
tfe_stream_action_set_opt(stream, ACTION_OPT_DEFER_BYTES, (void *) &defer_bytes, sizeof(defer_bytes));
return ACTION_DEFER_DATA;
}
if (search_up_stream_data(data, len)){
}else{
goto detach;
}
}
if (dir == CONN_DIR_DOWNSTREAM){
/* Protocol Identification, we need 24 bytes at least to tell it is HTTP2 or not */
if (len < MAGIC_FRAME_LENGTH){
defer_bytes = MAGIC_FRAME_LENGTH;
tfe_stream_action_set_opt(stream, ACTION_OPT_DEFER_BYTES, (void *) &defer_bytes, sizeof(defer_bytes));
return ACTION_DEFER_DATA;
}
if (memcmp(data, kMagicHello, MAGIC_FRAME_LENGTH) != 0){
goto finish;
}
}
if (tfe_stream_preempt(stream) != 0)
goto detach;
tapinfo->preempted = 1;
}
return (dir == CONN_DIR_DOWNSTREAM) ? detect_down_stream_protocol(tapinfo->h2_stream_info, stream, thread_id,
data, len) : detect_up_stream_protocol(tapinfo->h2_stream_info, stream, thread_id, data, len);
detach:
tfe_stream_detach(stream);
finish:
return ACTION_FORWARD_DATA;
}
static void
http2_stream_close(const struct tfe_stream * stream, unsigned int thread_id,
enum tfe_stream_close_reason reason, void ** pme)
{
struct stream_tap_info_t *tapinfo = (struct stream_tap_info_t *)(*pme);
sess_data_ctx_fini(tapinfo->h2_stream_info, stream, thread_id);
free(tapinfo->h2_stream_info);
tapinfo->h2_stream_info = NULL;
free(tapinfo);
tapinfo = NULL;
*pme = NULL;
return;
}
static struct tfe_plugin __nghttp2_plugin_info =
{
.symbol = "HTTP2",
.type = TFE_PLUGIN_TYPE_PROTOCOL,
.on_init = http2_plugin_init,
.on_deinit = http2_plugin_deinit,
.on_open = http2_stream_open,
.on_data = http2_stream_data,
.on_close = http2_stream_close
};
TFE_PLUGIN_REGISTER(HTTP2, __nghttp2_plugin_info)