协议的注冊与维护——ndpi源代码分析
在前面的文章中,我们对ndpi中的example做了源代码分析。这一次我们将尽可能深入的了解ndpi内部的结构和运作。我们将带着以下三个目的(问题)去阅读ndpi的源代码。
1、ndpi内部是怎么样注冊和维护须要检測的协议呢?
2、ndpi在初始化的过程中。做了怎么样的工作?
3、ndpi在底层的实现中详细又是使用如何的数据结构?
注:这里限于篇幅。本文章指针对使用中的初始化部分进行源代码分析。主体的分析函数和详细的各个协议将在后面的文中陆续介绍。假设有不对或者理解不到位的地方,欢迎大家一起讨论。
一、索引
在上文介绍的example(pcapReader)中给了我们一个很实用的导航。
就是setupDetection这个函数,他里面基本包括了我们初始化ndpi所用到的经常使用函数。
在接下来的源代码分析中,我们以这个函数为索引。逐步地窥探ndpi的内部。详细例如以下:
在上面的函数中。主要是前面的11行的操作。11行后面的操作主要是针对pcapReader本身的应用须要(事实上上面我们已经标注了简单的凝视)。接下来我们将分为两个阶段进行介绍。
注:二、三中标题的选取仅仅是由于比重关系。上面源代码中的宏等我们都将在以下进行介绍
二、ndpi_init_detection_module
这部分我们将介绍第8行中的初始化函数ndpi_init_detection_module,上方第3行中的定义等都将在第三部分系统地进行介绍。ndpi_init_detection_module的实现是在ndpi_main.c文件里。这个函数的工作并非维护协议。而是更加底层的參数的初始化。函数结束的时候将返回ndpi_detection_module_struct类型指针。这个类型将贯穿整个初始化过程。提供存放參数的容器以及设置的数据。以下我们将一一进行介绍:
函数原型:
struct ndpi_detection_module_struct *ndpi_init_detection_module(u_int32_t ticks_per_second,
void* (*__ndpi_malloc)(unsigned long size),
void (*__ndpi_free)(void *ptr),
ndpi_debug_function_ptr ndpi_debug_printf)
1、内存管理函数的初始化
_ndpi_malloc = __ndpi_malloc;
_ndpi_free = __ndpi_free;
这里的__ndpi_malloc和__ndpi_free就是我们自定义的函数。而这里等号左边的_ndpi_malloc和_ndpi_free并非指变量。这里是一个ndi内部封装好的函数指针。
在ndpi_main.c中定义,详细例如以下:
2、debug函数的初始化
这里使用ndpi_debug_printf函数的有两处地方,第一处就是楼下3步中申请内存时的错误处理。第二处就是在debug函数的传入。跟第1步类似。可是这里的debug信息输出函数并非在ndpi_main.c中声明,而是在ndpi_detection_module_struct结构内部。结构内部声明了ndpi_debug_printf的函数指针。具体见源码,这里不再列出。
3、ndpi_detection_module_struct指针的创建和初始化
这里事实上就是ndpi_detection_module_struct指针的声明和通过malloc的内存申请。
这里的ndpi_detection_module_struct将在函数最后return回去。
4、协议映射图的初始化
NDPI_BITMASK_RESET(ndpi_str->detection_bitmask);
这一部分主要是通过宏NDPI_BITMASK_RESET和结构体(ndpi_detection_module_struct)内部的detection_bitmask来共同实现。detection_bitmask事实上就是一个u_int32_t的数组,NDPI_BITMASK_RESET则是在ndpi_macros.h头文件里定义用来维护注冊协议的宏之中的一个。在底层事实上就是通过menset将detection_bitmask数组置0实现。
这里正如我们大题目那样。是文章的核心内容。将在第三部分。系统地进行介绍。
5、redis初始化
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对很多其它,包含string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。函数中通过结构体(ndpi_detection_module_struct)的redis变量进行了简单的初始化( ndpi_str->redis
= NULL;)。这里不作具体介绍。这一部分定义在ndpi_credis.h和ndpi_credis.c中。
6、协议timeout值的初始化
在本函数中,用了比較大的篇幅进行timeout的初始化。这里事实上没什么好解释的,各个应用层软件的timeout值。
7、AC算法的初始化
AC算法是指Aho-corasick自己主动机算法。包括在ndpi_main.h的头文件#include<ahocorasick.h>中。事实上在ndpi中对ahocorasick在ahocorasick.c中进行了封装和实现。
回归到这里,主要是通过ac_automata_init函数进行初始化。这里的初始化也不涉及算法本身,仅仅是创建并初始化结构体AC_AUTIMATA_T并传递回结构体(ndpi_detection_module_struct)。
8、Lru内存管理的初始化
ndpi_init_lru_cache(&ndpi_str->skypeCache, 4096);
这里又是一个深深的坑,内存管理。可是单单ndpi_init_lru_cache实现的功能也不是非常复杂。大家能够去看看。在ndpi_cache.c中进行实现。
9、多线程的初始化
这里是多线程的初始化。pthread_mutex_init()函数是以动态方式创建相互排斥锁的。參数attr指定了新建相互排斥锁的属性。
假设參数attr为空,则使用默认的相互排斥锁属性。默认属性为高速相互排斥锁 。相互排斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的相互排斥锁加锁时表现不同。
10、默认port的初始化
ndpi_init_protocol_defaults(ndpi_str);
这里ndpi_str是我们前几步初始化过后的结构体(ndpi_detection_module_struct)。ndpi_init_protocol_defaults函数的主要作用是维护一个二叉树型结构,用来记录各个协议的默认port。
这个函数里面的反复性比較高,我们粘一段比較有代表性的程序段来一起解释一下:
这里牵涉了两个函数。就是ndpi_build_default_ports和ndpi_set_proto_defaults。ndpi_build_default_ports操作比較简单不作具体介绍,他这里仅仅是把參数中的端口号传递进去ports_a/ports_b并返回。这里主要介绍ndpi_set_proto_defaults函数的实现流程。
注:上面(10)所述函数均在ndpi_main.h中进行实现
三、ndpi_set_protocol_detection_bitmask2
在讲这个函数之前,我们先介绍一下这个函数所用到的參数是什么来历。
也就是前面的宏定义和变量。
1、NDPI_PROTOCOL_BITMASKall
事实上第一次看到这个语句的时候,第一反应还以是一个宏定义。可是事实上这里NDPI_PROTOCOL_BITMASK代表的是一个变量类型,而all则是一个定义处理的实例(变量)。具体的定义在ndpi_macros.h中,例如以下:
看完上面的定义,不难发现NDPI_PROTOCOL_BITMASK类型说白了就是一个u_int32_t的数组。
我们在继续看看数组的大小NDPI_NUM_FDS_BITS又是怎么计算出来:
这里提出了一系列疑问?为什么要(((x)+((y)-1))/(y))?还有这样定义的目的是什么?
依据我的理解。这里维护协议映射的数据结构是上面提到的ndpi_protocol_bitmask_struct(u_int32_t的数组)。对于数组的每个位置比方fds_bits[1],这u_int32_t一共同拥有4字节。
也就事32位。每位代表这一个协议的映射。这一点不仅能够从上面的定义看出。在接下来的第2部分将更明显地能够看到这是一个类似hash的映射结构。然后回到为什么要(((x)+((y)-1))/(y))的问题,这里的y事实上就是32。所以这里这样计算数组是为了得出一个恰好满足能存放协议映射的数组大小(当然数组的位数不是所有应用与映射。毕竟会有一点空间的浪费)
2、NDPI_BITMASK_SET_ALL(all)
这个宏的主要作用非常显而易见,就是把映射中所以的应用都进行设置。可是这仅仅是比較表面的理解。
在ndpi_macros.h中,ndpi提供了非常健全的映射设置函数。
例如以下:
注:那我们使用时假设仅仅想注冊个别应用的检測该怎么办?能够通过NDPI_BITMASK_ADD宏进行加入。协议相应的hash数在ndpi_protocols_osdpi.h中进行了定义。
这里限于篇幅不再列出。
3、ndpi_set_protocol_detection_bitmask2(ndpi_struct,&all)
这个能够说是检測协议注冊的核心函数。和第2部分中的10一样,这里的反复率也是比較高的。可是參杂着一些协议之间的依赖关系。所以我们以下列一个典型的代码段。一起看看它到底完毕的是什么工作。
到这里为止,初始化的分析基本已经完毕了。
转载请著明:http://blog.csdn.net/grublinux/article/details/37670619
另外本篇博文的子妹篇pcapReader——源代码分析非常荣幸的參加了博客大赛,假设您认为对您有帮助。请支持我吧。投票地址:http://vote.blog.csdn.net/Article/Details?articleid=31603915
协议的注冊与维护——ndpi源代码分析的更多相关文章
- 基于Servlet、JSP、JDBC、MySQL的一个简单的用户注冊模块(附完整源代码)
近期看老罗视频,做了一个简单的用户注冊系统.用户通过网页(JSP)输入用户名.真名和password,Servlet接收后通过JDBC将信息保存到MySQL中.尽管是个简单的不能再简单的东西,但麻雀虽 ...
- Android Binder分析二:Natvie Service的注冊
这一章我们通过MediaPlayerService的注冊来说明怎样在Native层通过binder向ServiceManager注冊一个service,以及client怎样通过binder向Servi ...
- MyEclipse-6.5注冊码生成器源代码
打开MyEclipse新建一个Javaproject,然后新建类,粘贴例如以下代码,就可以生成MyEclipse的注冊码 import java.io.BufferedReader; import j ...
- 【spring源代码分析】--Bean的解析与注冊
接着上一节继续分析,DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法: protected void parseBeanDefini ...
- 从注冊流程 分析怎样安全退出多个Activity 多种方式(附DEMO)
前言 因为一个同学问到我怎样依照一个流程走好之后回到首页.我曾经看到过4个解决方式,后来发现有做个记录和总结的必要,就写了这篇博文. (之前看小强也写过一篇,这里通过自身的分析完整的总结一下下面6种方 ...
- 关于jdbc注冊驱动的那点事
看到非常多人写jdbc连接工具类的时候,都会写到Class.forName()去显示载入类,一写错点点就会抛出ClassNotFoundException,关于显示载入类,究竟会不会产生作用呢? 參考 ...
- Dubbo框架应用之(三)--Zookeeper注冊中心、管理控制台的安装及解说
我是在linux下使用dubbo-2.3.3以上版本号的zookeeper注冊中心客户端. Zookeeper是Apache Hadoop的子项目,强度相对较好,建议生产环境使用该注冊中心. Dubb ...
- Android插件化开发之解决OpenAtlas组件在宿主的注冊问题
OpenAtlas有一个问题,就是四大组件必须在Manifest文件里进行注冊,那么就必定带来一个问题,插件中的组件都要反复在宿主中注冊.像Service,ContentProvider等组件眼下没有 ...
- 一个简单RPC框架是怎样炼成的(VI)——引入服务注冊机制
开局篇我们说了.RPC框架的四个核心内容 RPC数据的传输. RPC消息 协议 RPC服务注冊 RPC消息处理 接下来处理RPC服务的注冊机制.所谓注冊机制,就是Server须要声明支持哪些rpc方法 ...
随机推荐
- js request学习
SP的内置对象在JSP页面中无须声明就可以直接使用,其内置对象常用的有Request,response,session,application,out,config,pageCOntext reque ...
- Appium+python自动化-环境搭建
一.前言 本文是在windows10 X64系统下搭建appium,流程如下: 1.安装jdk1.8+python3.6 (64位) 2.安装node.js 3.安装Appium-desktop 4 ...
- Leetcode 354.俄罗斯套娃信封问题
俄罗斯套娃信封问题 给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现.当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样. 请计 ...
- iOS第三方网络图片加载- SDWebImage笔记(转)
SDWebImage托管在github上.https://github.com/rs/SDWebImage 这个类库提供一个UIImageView类别以支持加载来自网络的远程图片.具有缓存管理.异步下 ...
- 【Luogu】P1155双栈排序(二分图)
题目链接在此 此题一开始写了个深搜,过了30%的数据,也就是n<=10的那一段.... 然后看了题解发现这是个二分图的判断. 我们先举例子找到不能放进一个栈里的规律.设有数列[2,3,1,4] ...
- BZOJ 2438 [中山市选2011]杀人游戏 ——期望DP
发现每一次死亡的几率相等,所以只需要判断最少问多少人即可. 并且环上的点任意询问都可以. 所以直接Tarjan缩点,然后计算入度为0的点的数目. 但是还有一些情况的时候会减少一次询问,比如说:$1-& ...
- BS4(BeautifulSoup4)的使用--find_all()篇
可以直接参考 BS4文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#find-all 注意的是: 1.有些 ...
- 洛谷 P 3371 单元最短路
题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三 ...
- Android 网络编程之HttpURLConnection运用
Android 网络编程之HttpURLConnection 利用HttpURLConnection对象,我们可以从网络中获取网页数据. 01 URL url = new URL("http ...
- echarts 图表用例
参考博客:http://blog.csdn.net/verne_feng/article/details/51731653 http://echarts.baidu.com/echarts2/doc/ ...