#include #include #include #include #include #include "tsg_rule_internal.h" #include "tsg_gtp_signaling.h" MESA_htable_handle g_gtp_signaling_hash_handle=NULL; enum SIGNALING_ORIGIN { SIGNALING_ORIGIN_NO=0, SIGNALING_ORIGIN_HASH=1, SIGNALING_ORIGIN_REDIS=2, }; static int is_gtp_tunnel(const struct streaminfo *a_stream) { int ret=0; unsigned short is_tunnel=0; int size=sizeof(unsigned short); ret=MESA_get_stream_opt(a_stream, MSO_STREAM_TUNNEL_TYPE, (void *)&is_tunnel, &size); if(ret>=0 && is_tunnel==STREAM_TUNNEL_GPRS_TUNNEL) { return 1; } return 0; } static int get_gtp_teid(const struct streaminfo *a_stream, unsigned int *uplink, unsigned int *downlink) { const struct streaminfo *p=a_stream; while(p) { if(p->addr.addrtype==ADDR_TYPE_GPRS_TUNNEL) { *uplink=ntohl(p->addr.gtp->teid_c2s); *downlink=ntohl(p->addr.gtp->teid_s2c); return 1; } p=p->pfather; } return 0; } static int copy_one_field(char **dst, char *src, int src_len) { if(src!=NULL && src_len>0) { *dst=(char *)calloc(1, src_len+1); memcpy(*dst, src, src_len); return 1; } return 0; } static long copy_user_info(void *data, const uchar *key, uint size, void *user_arg) { int num=0; struct gtp_signaling_field *signal=(struct gtp_signaling_field *)data; struct umts_user_info *user_info=(struct umts_user_info *)user_arg; if(signal!=NULL) { num+=copy_one_field(&(user_info->apn), (char *)(signal->ie_unit[GTP_FIELD_APN].value), signal->ie_unit[GTP_FIELD_APN].len); num+=copy_one_field(&(user_info->imsi), (char *)(signal->ie_unit[GTP_FIELD_IMSI].value), signal->ie_unit[GTP_FIELD_IMSI].len); num+=copy_one_field(&(user_info->imei), (char *)(signal->ie_unit[GTP_FIELD_IMEI].value), signal->ie_unit[GTP_FIELD_IMEI].len); num+=copy_one_field(&(user_info->msisdn), (char *)(signal->ie_unit[GTP_FIELD_MSISDN].value), signal->ie_unit[GTP_FIELD_MSISDN].len); } return num; } unsigned int gtp_c_key2index(const MESA_htable_handle table, const uchar * key, uint size) { if(size==sizeof(unsigned int)) { return *(unsigned int *)key; } return 0; } void free_gtp_signaling_field(void *data) { int i=0; struct gtp_signaling_field *signal=(struct gtp_signaling_field *)data; if(data==NULL) { return ; } for(i=0; iie_unit[i].value!=NULL) { free(signal->ie_unit[i].value); signal->ie_unit[i].value=NULL; } } free(data); data=NULL; return ; } void tsg_free_gtp_signaling_field(void *data) { if(data!=NULL) { free_gtp_signaling_field(data); data=NULL; } } static int get_umts_user_info_form_hash(struct umts_user_info **user_info, unsigned int teid, int thread_seq) { long cb_ret=0; struct umts_user_info tmp_user_info={0}; MESA_htable_search_cb(g_gtp_signaling_hash_handle, (unsigned char *)&(teid), sizeof(unsigned int), copy_user_info, (void *)&tmp_user_info, &cb_ret); if(cb_ret>0) { tmp_user_info.ref_cnt=1; *user_info=(struct umts_user_info *)calloc(1, sizeof(struct umts_user_info)); memcpy(*user_info, &tmp_user_info, sizeof(struct umts_user_info)); return 1; } return 0; } static int get_umts_user_info_form_redis(struct umts_user_info **user_info, unsigned int teid, int thread_seq) { (*user_info) = tsg_get_umts_user_info_form_redis(g_tsg_maat_feather, (long long)teid); if((*user_info)!=NULL) { return 1; } return 0; } int session_runtine_attribute_get_umts_user_info(const struct streaminfo *a_stream, struct umts_user_info **user_info) { int ret=0; unsigned int uplink=0,downlink=0; if(g_tsg_para.scan_signaling_switch==SIGNALING_ORIGIN_NO) { return 0; } if(*user_info!=NULL) { return 1; } ret=is_gtp_tunnel(a_stream); if(ret==0) { return 0; } ret=get_gtp_teid(a_stream, &uplink, &downlink); if(ret==0) { return 0; } switch(g_tsg_para.scan_signaling_switch) { case SIGNALING_ORIGIN_HASH: ret=get_umts_user_info_form_hash(user_info, uplink, a_stream->threadnum); if(ret==1) { return 1; } ret=get_umts_user_info_form_hash(user_info, downlink, a_stream->threadnum); if(ret==1) { return 1; } break; case SIGNALING_ORIGIN_REDIS: ret=get_umts_user_info_form_redis(user_info, uplink, a_stream->threadnum); if(ret==1) { return 1; } ret=get_umts_user_info_form_redis(user_info, downlink, a_stream->threadnum); if(ret==1) { return 1; } break; default: break; } return 0; } int tsg_gtp_signaling_hash_init(const char* conffile, void *logger) { MESA_load_profile_int_def(conffile, "GTP_SIGNALING", "HASH_TIMEOUT", &g_tsg_para.hash_timeout, 300); MESA_load_profile_int_def(conffile, "GTP_SIGNALING", "HASH_THREAD_SAFE", &g_tsg_para.hash_thread_safe, 128); MESA_load_profile_int_def(conffile, "GTP_SIGNALING", "HASH_SLOT_SIZE", &g_tsg_para.hash_slot_size, 1024*1024*32); MESA_htable_create_args_t args; memset(&args, 0, sizeof(args)); args.thread_safe=g_tsg_para.hash_thread_safe; args.recursive=1; args.max_elem_num=0; args.data_free=free_gtp_signaling_field; args.eliminate_type=HASH_ELIMINATE_ALGO_LRU; args.expire_time=g_tsg_para.hash_timeout; args.hash_slot_size=g_tsg_para.hash_slot_size; args.key2index=gtp_c_key2index; g_gtp_signaling_hash_handle=MESA_htable_create(&args, sizeof(MESA_htable_create_args_t)); if(g_gtp_signaling_hash_handle==NULL) { MESA_handle_runtime_log(logger, RLOG_LV_FATAL, "GTP_SIGNALING", "MESA_htable_create failed"); return -1; } char signaling_origin[32]={0}; MESA_load_profile_string_def(conffile, "GTP_SIGNALING", "SIGNALING_ORIGIN", signaling_origin, sizeof(signaling_origin), "HASH"); int length=strlen(signaling_origin); if(length==2 && (strncasecmp("NO", signaling_origin, 2)==0)) { g_tsg_para.scan_signaling_switch=SIGNALING_ORIGIN_NO; } else if(length==4 && (strncasecmp("HASH", signaling_origin, 4)==0)) { g_tsg_para.scan_signaling_switch=SIGNALING_ORIGIN_HASH; } else if(length==5 && (strncasecmp("REDIS", signaling_origin, 5)==0)) { g_tsg_para.scan_signaling_switch=SIGNALING_ORIGIN_REDIS; } return 0; }