Partysip的插件技术研究

本文详细介绍了Partysip框架中的插件加载过程及如何制作符合框架要求的插件,包括所需定义的全局变量、回调函数及其作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Partysip的插件技术研究
之Partysip框架优化方案

 

介绍:

       本文是《Partysip框架优化计划》的一部分,着重研究Partysip插件技术,并在此基础上尝试优化。

       整体上说Partysip虽然没有使用OO的思想去设计,但是还是尽量“封装”独立的函数操作,所以研究和理解还是比较方便,对于每个声明结构体都会有一组相关的函数对其操作,这些操作大部分是名字上的差异,其执行操作是对结构体内变量赋值,修改操作,以及结构体的init和free操作,试想如果Partysip采用OO设计思想进行设计,将是非常容易理解。

       对于Partysip插件,我们是按照程序启动时引入插件的过程来理解,并逐步理解插件的实现和调用,在文章最后给出实现一个插件所需要完成的基本操作。现在假设我们已经具有插件,这里我们所说的插件其实就是按照Partysip框架格式定义的动态链接库(dll)。

插件的加载过程

       Partysip中插件加载在main.c文件中的main_load_plugins()函数内实现,在加载Partysip的插件之前,Partysip框架已经做了一些初始化,关于这方面的知识,以后会再讲。在main_load_plugins函数内,大部分代码我们不用考虑,加载插件的主要函数是psp_plugin_load函数,通过循环调用psp_plugin_load函数实现对所有插件的加载,该函数在psp_plugin.h文件内声明,在psp_plugin.c文件内定义。

关于插件操作其他函数也是在这两个文件内声明和定义,后面将详细介绍psp_plugin.h内的函数。在psp_plugin_load函数调用ppl_dso_load函数(在ppldso.h文件内定义),在ppl_dso_load函数内调用系统函数LoadLibraryEx加载动态链接库,这样我们就把插件“插入”Partysip中,这和在程序中引入一个其他dll是没有区别的。Partysip经过诸多转换后,会把dll的句柄保存在ppl_dso_handle_t类型的结构体内,在XXX_plugin(XXX是插件的名称,每个插件都有这样的一个全局结构体)结构体内有一个ppl_dso_handle_t类型指针指向这个变量,最后资源释放时也是通过ppl_dso_handle_t这个结构体进行资源释放,释放时是通过全局结构XXX_plugin来释放的,这个结构体在psp_plugin_take_ownership函数内注册,Partysip在加载控件,主要通过XXX_plugin这个结构体,调用plugin_init函数,关于这个函数的作用以后会提到。

       加载动态链接库dll(插件)成功后,我们回到psp_plugin_load函数,这个函数内声明两个重要变量

1dso_handle,变量类型为ppl_dso_handle_t,他的原型为

struct ppl_dso_handle_t
{

        void *handle;
        const char *errormsg;

};

是用来记录加载dll的句柄和错误信息的(如果加载失败)。

2:sym,变量类型为ppl_dso_handle_sym_t,他的原型是typedef void *ppl_dso_handle_sym_t;,这个类型更多是基于将来扩展考虑而这样定义的。当加载dll后用dso_handle记录加载dll的句柄信息和错误信息。然后通过调用ppl_dso_sym函数,获取dll中的特定结构体的指针(我们做插件时,必须创建一个这样的全局结构体变量,结构体变量名必须为插件名+ _plugin,比如UDP插件中声明udp_plugin结构体)。结构体指针的类型为psp_plugin_t。这个结构体的主要作用是记录插件的相关信息,我们在后面还将详细介绍这个结构体。获取这个结构指针后,再次分别调用ppl_dso_sym (&sym, dso_handle, "plugin_init"),ppl_dso_sym (&sym, dso_handle, "plugin_start"),ppl_dso_sym (&sym, dso_handle, "plugin_release"),分别获取加载插件中的plugin_init,plugin_start,plugin_release三个函数地址(后面我们将详细介绍其作用),通过这个函数(*plug)->plugin_init (name_config)调用插件的plugin_init函数,这个函数内做插件的相关注册操作,具体操作参考下边的函数讲解。以上各个过程中如果出现错误,马上调用ppl_dso_unload函数,通过FreeLibrary函数释放插件。在Partysip,Osip中,函数返回值为0,表示执行函数成功,-1表示失败。

    3:关于线程,在《Partysip框架优化计划》一文中提到,Partysip会为每个插件创建一个线程的观点是不正确的。经过仔细分析Partysip框架,Partysip会创建三个线程(启动参数中包含i选项,i表示为interface,用户界面的意思,主界面线程,加上这个线程Partysip一共创建4个线程。如果Osip库采用多线程方式编译,osip至少还会创建4个线程)。这三个线程分别为mythread_resolv,mythread_tlp,mythread_sfp。这三个线程分别监听三个管道,Partysip为了通用向并没有使用windows下的CreatePipe等函数,而是创建了从10500开始的三个TCP端口,当有消息到来时(比如q,退出)通过这几个端口来传输。关闭这三个线程的作用。

制作插件

Partysip插件就是满足Partysip框架要求的动态链接库(dll),满足Partysip框架的插件至少要满足一下五点

1:插件内定义全局变量XXX_plugin(XXX为插件名称),此变量类型为psp_plugin_t。

这个结构体原型为

struct psp_plugin_t

{
        int plug_id;// 加载后的插件ID
        char *name; // 插件名字
        char *version; // 插件版本
        char *description; // 插件描述信息   

#define PLUGIN_TLP 0x01
#define PLUGIN_IMP 0x02
#define PLUGIN_UAP 0x04
#define PLUGIN_SFP 0x16
        int flag;
        /*... */
        int owners;         /* number of attached plugins */
        ppl_dso_handle_t *dso_handle; // 加载插件后的插件句柄
        int (*plugin_init) (); // 以下为三个回调函数,分别执行初始化,开始,释放数据操作。
        int (*plugin_start) ();
        int (*plugin_release) ();
};

这个结构体的作用是记录Partysip插件的相关信息,比如插件的名字,插件的ID,插件的版本,插件的描述信息,插件的三个回调函数,插件的句柄等。变量XXX_plugin中的一些成员变量会在插件加载的Partysip框架中修改。比如owners,dso_handle,plugin_init等,下面是UDP插件udp_plugin的例子

psp_plugin_t PSP_PLUGIN_DECLARE_DATA udp_plugin = {
  0,                /* uninitialized */
  "Udp plugin",
  "0.5.1",
  "plugin for receiving and sending UDP message",
  PLUGIN_TLP,
  0,                /* number of owners is always 0 at the begining */
  NULL,             /* future place for the dso_handle */
  &plugin_init,
  &plugin_start,
  &plugin_release
};

2:声明plugin_init 函数,其声明原型为
PSP_PLUGIN_DECLARE (int) plugin_init (char *name_config),
PSP_PLUGIN_DECLARE是一个宏,声明为
#define PSP_PLUGIN_DECLARE(type) __declspec(dllimport) type __stdcall
表示plugin_init为一个导出函数。名字,函数参数,返回值不能修改。

Plugin_int函数的主要作用是,初始化插件内部的一些操作,变量的申请,系统参数的获取操作,系统资源的获取,还有一个重要作用就是,注册回调函数(hook机制),涉及到回调函数执行的优先级别等信息。参数name_config传递配置文件路径的字符串,这个函数在加载完成插件后调用。

3:声明plugin_start函数,函数原型为PSP_PLUGIN_DECLARE (int) plugin_start ()
调用完成plugin_init之后,在合适的位置执行此函数,这个函数目前只是作为保留函数使用,一般都是只是return -1;

 

4:声明plugin_release 函数,函数原型为PSP_PLUGIN_DECLARE (int) plugin_release ()
函数的作用,主要用于卸载插件时,调用这个函数,释放由plugin_init中申请的内存空间,关闭系统资源等。

5:声明注册hook函数
插件中hook函数执行顺序(psp_plug)

/** run this hook first, before ANYTHING */
#define PSP_HOOK_REALLY_FIRST   (-10)
/** run this hook first */
#define PSP_HOOK_FIRST      0
/** run this hook somewhere */
#define PSP_HOOK_MIDDLE     10
/** run this hook after every other hook which is defined*/
#define PSP_HOOK_LAST       20
/** run this hook last, after EVERYTHING */
#define PSP_HOOK_REALLY_LAST    30
#define PSP_HOOK_FINAL      40
 

/* How to call plugins:
   1: detect which method or response code is used
   2: call the list of method in the PSP_HOOK_REALLY_FIRST list
   3: call the list of method in the PSP_HOOK_FIRST
   4: ...
   5: ... 

   So: For performance reason, this list should be ready to use:
   table[0] for any REQUEST (other than INVITE)
   table[1] for INVITE
   table[2] for REGISTER
   table[3] for BYE
   ... 

   table[1] contains all the hook related to INVITE:
   for irp:
*/

 

/* HOW PLUGINS ARE IMPLEMENTED:
   1: The core layer is asked to load a plugin named "$name"
   2: Do a dlopen of the shared library
   3: Do dlsym to access some methods:
       plugin_configure
       -> used to init internal state of plugin
       -> plugin store its "func_tab" in the *_plugin structure
       ....
*/

小结:

    以上这些只是基于Partysip框架的基本了解,由于刚接触Partysip难免有错误,或者理解偏差的地方,欢迎大家指出。 

部分缩写词说明(部分)

缩写

原组成词

说明

备注

psp

Partysip

psp是Partysip缩写

 

tlp

Transport layer Processing

tlp传输层处理

Transport layer Processing
(传输层处理)

sfp

State Full Processing

sfp全状态处理

State Full Processing

(全状态处理)

ict

Invite Client Transaction

ict客户端邀请事务

Invite Client Transaction

(邀请客户端事务)

nict

Non-Invite Client Transaction

Nict非客户端要求事务

Non Invite Client Transaction(非邀请客户端事务)

ist

Invite Server Transaction

Ist服务器端要求事务

Invite Server Transaction
(邀请服务器端事务)

nist

Non Invite Server Transaction

Nist非服务器端要求事务

Non Invite Server Transaction(非邀请服务器端事务)

snd

Send

 

 

inc

 

 

 

rcv

receive

 

 



转自:http://blog.youkuaiyun.com/ugg/article/details/1522503

SIP电话Click2Call。检测网络上的电话号码,并将其转换为sip、tel、callto(点击呼叫链接) SIP PHONE CLICK TO CALL是Chrome的Click2Call浏览器扩展程序。 这个点击通话应用程序非常简单轻巧。 它与Skype的操作非常相似,在安装后,它会在浏览器中读取所有电话号码,并设置它们以供您点击通话。 -与VoIP电话,IP电话系统集成,将呼叫传递到计算机中安装的SIP软件。 只需将URL放在浏览器中,就可以使点击通话电话系统正常工作。 -阅读您正在浏览的任何页面上的html,并将每个电话号码转换为链接到URL“ sip:PHONE-NUMBER”,“ tel:PHONE-NUMBER”或“ callto:PHONE-NUMBER”或您选择的任何特殊协议。 -SipCaller是唯一支持特殊和自定义协议的ClickToCall应用。 可以与任何种类的SoftPhone集成。 只需将您的软件电话设置为协议处理程序,然后在SipCaller应用程序中输入即可。 -支持HTTP GET请求以与自定义VOIP服务器集成。 输入带有$ NUMBER占位符的服务器链接。 要打个电话,只需单击一个电话号码,Click2Call应用程序会将请求发送到您的VOIP服务器。 =====================-更新历史--v2016.5.20:-支持特殊和自定义协议以与任何类型的软电话集成。 -支持带有自定义URL和电话$ NUMBER占位符的HTTP GET请求。 拨打电话的新方法:单击电话号码将http请求发送到您的VOIP服务器。 v2016.4.1:-添加了选项页,单击SipCaller按钮以切换协议-支持所有使用该协议的软件电话:sip,tel,callto v1.5:-检测大多数数字格式-在sip URL中传递+或00,因此适用于全球呼叫v1.3:-检测更多电话号码格式v1.2:-错误修正v1.0:-首次发布待办事项:-实施新的电话号码检测工作流程。 -实施新的工作流程以在大多数网站和CRM平台上工作,例如maps.google.com,gmail,yahoo,outlook.com ... =================== =====-关于作者---由VNProDev团队开发。 我们开发了浏览器插件插件和扩展程序,只是为了娱乐并在我们的空闲时间帮助其他人。 如果您有问题或功能要求,请随时在此处给我们留言或发送电子邮件至support@vnprodev.com-欢迎您! =================== ---使用条款---我们的浏览器扩展服务收集并存储有关特定网页的匿名信息,调试有关扩展如何工作的信息这些网页。 该扩展程序收集的信息完全是匿名的,无法个人识别。 我们使用这些信息来改善扩展程序的工作流程并修复错误。 我们不会将其用于任何商业目的,也不会将其出售给任何第三方公司。 VNProDev.com不需要您向我们提供信息即可使用我们的大多数服务。 因此,您始终可以选择不提供此类信息。 您可以使用浏览器扩展服务中的“选项”菜单来禁止浏览器扩展服务报告匿名信息。 如果支持,则可以在浏览器扩展服务的“选项”菜单中进行配置。 如果您选择使用我们的浏览器扩展服务,则与VNProDev.com有关隐私的任何纠纷均受本通知和我们的使用条款的约束,包括损害赔偿的限制,纠纷的解决以及越南法律的适用。 如果您对VNProDev.com的隐私有任何疑问,请[与我们联系]并提供完整的描述,我们将尽力解决该问题。 我们的业务在不断变化,我们的隐私声明和网站使用条款也将发生变化。 但是,我们信守我们所作的承诺,并且绝不会实质性地改变我们的政策和做法,以使它们在未经受影响的客户同意的情况下,对过去收集的客户信息的保护程度降低。 支持语言:English
再次使网络变得有趣! 收回对数据的控制权和所有权。 加入私人派对!!! 您的朋友邀请您向浏览器添加隐私扩展:-在互联网上的任何地方发送和解密来自您朋友的秘密消息! -阻止科技公司(甚至我们)摆脱大规模的“监视资本主义”。 -赋予您所有权和在线控制所有数据的权限。 -创建您的帖子,好友列表等的可搜索历史记录! 工作原理:1.查看朋友的秘密帖子。 2.尚未安装浏览器扩展。 3.您朋友的帖子会自动被解密! 4.在网络上的任何地方发布您自己的秘密消息! -它使用军事级加密安全性来保护您。 -我们(或其他人)无权访问您的密码或私钥。 50%的隐私:派对模式! -使参加聚会的人很容易看到数据,但对公司和政府来说却很困难。 -通过耗费大量时间的能源消耗来停止监视资本主义和大规模监视。 -假设Facebuck每秒获得10K +个帖子,那么解密每一秒钟的数据将花费1个多小时。 -但是其他派对好友只需半秒钟即可解密您的一条消息。 100%隐私:秘密特工模式! -它要求您验证您的朋友,这是一项额外的工作,但只有他们才能解密。 -其他人看不到您的数据,其他用户看不见,不是技术垄断,也不是政府。 -您不能将其用于非法目的。 如果这样做,政府将窃取您的笔记本电脑进行解密。 -您可以使用它与已验证的朋友,gf / bf,同事等共享私人信息。安装扩展程序即表示您同意使用条款:https://docs.google.com/document/d/1rw_FR8DE1acqfMaBg20EhocGYdHYcYlSoFbpk9r2Ls0 支持语言:English
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值