CWMP開源代碼研究6——libcwmp動態庫開發

原創做品,轉載請註明出處,嚴禁非法轉載。若有錯誤,請留言!css

email:40879506@qq.comhtml

  爲了使程序具備通用性,便於擴展和維護。採用了"模塊"插入的思想。將設備業務相關的實現以動態庫的形式加載進來。java

  在上篇文章已經介紹了CWMP的程序處理流程。本篇主要分析一下在CWMP core的程序裏如何加載lib庫。。好比如何實現調用so庫函數, 實現ACS URL解析, CPE get/set函數怎麼被調用,怎樣添加/刪除/更新 obj對象等。
git

一. 加載lib庫github

  1) 打開動態鏈接庫bootstrap

  還記得上節咱們定義的cwmp進程上下文結構體cwmp_context,使用dlopen以指定的模式打開動態庫文件,並返回設備library的handle。架構

    //打開設備handle
    cwmp_ctx->handle_lib = dlopen(cwmp_ctx->dev_info.dev_lib, RTLD_LAZY);socket

  2) 調用設備相關函數ide

  上節已經介紹了相關設備函數,並定義在device.xml。根據xml定義的tag頭取得函數名稱,並賦給CWMP進程上下文。好比模塊化

  cwmp_ctx->dev_info.func_bootstrap = dlsym(cwmp_ctx->handle_lib, attr_value);
  cwmp_ctx->dev_info.func_init = dlsym(cwmp_ctx->handle_lib, attr_value);

  cwmp_ctx->dev_info.func_get_listenport = dlsym(cwmp_ctx->handle_lib, attr_value);

  cwmp_ctx->dev_info.func_get_auth = dlsym(cwmp_ctx->handle_lib, attr_value); 

  cwmp_ctx->dev_info.func_url_dns_resolve= dlsym(cwmp_ctx->handle_lib, attr_value);

  ......

二. 設備相關初始化 

 1 //用於須要平臺一開始初始化
 2 void dev_init(trf_param_t* param, callback_reg_func_t func, pthread_mutex_t *pmutex_param, LogFunc log_func)
 3 {
 4     pthread_t       thd;
 5     monitor_info_t  *info = NULL;
 6 
 7     //init local  pointer
 8     cwmplog_func = log_func;
 9     g_reg_func = func;
10     g_root_param = param;
11     g_pmutex_param = pmutex_param;
12         
13     info = (monitor_info_t *)malloc_check(sizeof(monitor_info_t));
14     info->func = func;
15     info->param = param;
16     // info->log_func = log_func;
17     
18     closeinout();
19 
20     //初始化CPE 與ACS 鏈接狀態
21    CpeSetValue(NULL, "0", "cpeagent.tr069.acs_status");
22 
23     /*
24         1. define user-defined event code in the  device.xml.
25     */
26     inform_bind(func);
27 
28     // monitor_socket_event 線程函數用於與其餘程序或進程指定的socket進行通訊
29     // 好比源碼目錄下的sendSocket/client.c  程序,可用於測試或其餘
30     // CWMP_SOCK "/opt/cwmp.sock"
31     // pthread_create(&thd, NULL, monitor_socket_event, (void*)info);
32     return;
33 }
View Code

主要完成初始化操做:將內存中的根節點參數位置賦給動態庫中的全局變量g_root_param指針,以及初始化信號量,日誌記錄函數,以及FUNC回調函數。    inform_bind(func)函數實現用戶自定義的<EventCode>事件,好比電信運營商自定義了X CT-COM BIND事件類型,只用上報正確才能進行工單下發業務。

dev_bootstrap主要用來判斷是不是首次鏈接ACS,若是是把0 BOOTSTRAP和1 BOOT加入Inform事件中,不然把1 BOOT加入Inform事件中。

Inform中帶有以下結構信息:

        <cwmp:Inform>
            <DeviceId xsi:type="cwmp:DeviceIdStruct">
                <Manufacturer>TEST</Manufacturer>
                <OUI>A1B2C4</OUI>
                <ProductClass>TEST_PC</ProductClass>
                <SerialNumber>821281000054321</SerialNumber>
            </DeviceId>
            <Event SOAP-ENC:arrayType="cwmp:EventStruct[2]">
                <EventStruct>
                    <EventCode>1 BOOT</EventCode>
                    <CommandKey></CommandKey>
                </EventStruct>
                <EventStruct>
                    <EventCode>X CT-COM BIND</EventCode>
                    <CommandKey></CommandKey>
                </EventStruct>
            </Event>
            <MaxEnvelopes>1</MaxEnvelopes>
            <CurrentTime>2017-01-09T11:53:00</CurrentTime>
            <RetryCount>0</RetryCount>
            <ParameterList SOAP-ENC:arrayType="cwmp:ParameterValueStruct[10]">
                <ParameterValueStruct>
                    <Name>InternetGatewayDevice.DeviceSummary</Name>
.......

 三. 解析ACS  URL

  同時支持域名和ip地址解析。(放在後續高級部分專門講解)

. 每一個節點RPC Method

  節點結構體以下:

struct trf_param
{
    char                name[PARAM_NAME_LEN+1];     //參數名
    int                 type;                       //參數類型 trf_datatype_e
    int                 writable;                   //是否可寫。0:不可寫,1:可寫,若是object
                                                    //能夠Add,則可寫
    int                 max_instance;               //屬於Object, 最大instance值,-1表示無限制
    int                 notification;               //屬於Parameter,  0:off,1:passive,2:active
    unsigned char       noti_rw;                    //屬於Parameter,  是否能夠設置上報屬性,0 不能夠 1 能夠
    unsigned long       acl;                        /*屬於Parameter, access list */
    TRFGetParamValueFunc    getparamval_func;       //屬於Parameter, 取得參數值函數
    TRFSetParamValueFunc    setparamval_func;       //屬於Parameter, 設置參數值函數
    TRFAddObjectFunc        addobject_func;         //屬於Object, AddObject
    TRFDelObjectFunc        delobject_func;         //屬於Object, DeleteObject
    TRFRefreshFunc          refresh_func;           //屬於Object, 刷新
    struct trf_param    *parent;                    //父節點
    struct trf_param    *child;                     //子節點
    struct trf_param    *nextSibling;               //兄弟節點
};

 

  每一個參數節點擁有本身的屬性和方法,而且經過遞歸方式建立初始化參數樹,把初始化後的結果保存在cwmp_context進程上下文中

  create_param(&cwmp_ctx->param_root, xmldata->doc->root->firstChild);

五. 其餘RPC方法

  本文開頭已經介紹了調用設備相關函數的方法,其中包括除TR069規範中的升級,恢復出廠,Reboot,Download等方法,咱們也能夠經過」插件"的形式實現本身的或者私有廠商定義的方法。

<devlib name="/usr/lib/libcwmp.so"></devlib>
<auth name="dev_get_auth"></auth>
<listenport name="dev_get_listenport"></listenport>
<wanparamname name="dev_get_wanparam_name"></wanparamname>
<bootstrap name="dev_bootstrap"></bootstrap>  
<init name="dev_init"></init>  
<reboot name="dev_reboot"></reboot>
<factoryreset name="dev_factoryreset"></factoryreset>
<download name="dev_download"></download>
<acsstatus name="dev_set_acs_status"></acsstatus>
<urldnsresolve name="dev_url_dns_resolve"></urldnsresolve>
<upload name="dev_upload"></upload>
<cwmpenable name="dev_cwmp_enable"/>

六. 總結

  tr069只是個協議棧,按照規範實現這個協議並不困難,在github上咱們也能夠去找到各類各用的開源程序,有Python寫的,java寫的,C寫的等等。可是,可以從開源程序中找到一個優秀的程序設計架構就如同大海撈針,很困難,更不要說商業用途了。

  至此,已經基本寫完了關於程序設計部分的內容,本篇涉及的代碼比較多,儘可能不深刻代碼,而只是圍繞協議規範和程序模塊化思想分析了部分代碼的實現。

七. 參考

 1)http://www.cnblogs.com/Anker/p/3746802.html

附:遺留問題

  程序開發中在使用dl庫中遇到一個問題,如有心的讀者能解答,歡迎留言告訴我:

  若dlopen打開的庫中不存在線程,或線程不在運行狀態,則調用dlclose時,進程不會死;
  若存在運行時的線程(好比dev_init函數裏的 pthread_create(&thd, NULL, monitor_socket_event, (void*)info);),則dlclose時出現segmentation fault。
  若不調用dlclose則會出現內存漏洞

相關文章
相關標籤/搜索