220 lines
5.8 KiB
C++
220 lines
5.8 KiB
C++
/*************************************************************************
|
|
> File Name: detect_http2_plugin.cpp
|
|
> Author:
|
|
> Mail:
|
|
> Created Time: 2018年09月11日 星期二 15时38分54秒
|
|
************************************************************************/
|
|
|
|
#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();
|
|
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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
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)
|
|
|