citadel学习笔记4——git版本XMPP模块之token.def

阅读citadel的代码,后来吧,有时候就是比较喜欢追新。就将citadel的最新版本给下下来了。也就是其git上的版本。还是有不少的收获。其XMPP模块也进行了重构,从代码上看,更加容易进行扩展等一系列的操作了。

首先,当然是先把代码都给clone下来。(我此次git的版本为commit 6050cb23108ee10dafcceb65b9cafab51c013ae0)

git clone git://git.citadel.org/appl/gitroot/citadel.git

这是把citadel上的所有工程代码都给clone下来。

cd citadel
ll
总用量 48
drwxrwxr-x  2 ping ping  4096  6月  5 12:34 buildbot
drwxrwxr-x 19 ping ping 12288  6月 12 16:35 citadel
drwxrwxr-x  3 ping ping  4096  6月  5 12:34 contrib
drwxrwxr-x  4 ping ping  4096  6月  5 12:34 ctdlphp
drwxrwxr-x  3 ping ping  4096  6月  5 12:34 ctdlsalearn
drwxrwxr-x  3 ping ping  4096  6月  5 12:34 ctdlsh
drwxrwxr-x  9 ping ping  4096  6月  9 10:22 libcitadel
-rwxrwxr-x  1 ping ping  4016  6月  5 12:34 releaseversion.sh
drwxrwxr-x  6 ping ping  4096  6月  5 12:34 textclient
drwxrwxr-x 11 ping ping  4096  6月  9 18:54 webcit

内容还不少的。其中服务端的话,是citadel那个目录。大概看了下,XMPP模块的话,已经被细分成多个模块了。下文将以XMPP模块为主,进行说明。

新的xmpp模块由原来的单个xmpp模块划分成了xmpp+xmpp_message+xmpp_presence+xmpp_queue+xmpp_xmacros。其中比较重要的就是xmpp_xmacros,这个模块,算是做了一个宏模板。也因为添加了该模块,出现了一个比较奇葩的定义——token.def,这个说是头文件吧,又不像,但是却又当头文件来引用。说起这个,我以前一个同事,在引用头文件的时候,引用了某个.c当做头文件,并且能够编译也可以执行。真是把一直用.h做头文件的习惯给打破了。这是后话了。token.def文件的内容如下:

#define NAMESPACE_iq "jabber:client"
TOKEN(iq,
      {
              STRPROP(iq, type);
              STRPROP(iq, id);
              STRPROP(iq, from);
              STRPROP(iq, to);
      })


#define NAMESPACE_piq "bub"

TOKEN(piq,
      {
              STRPROP(piq, type);
              STRPROP(piq, id);
              STRPROP(piq, from);
              STRPROP(piq, to);
      })

#define NAMESPACE_message "jabber:client"
TOKEN(message,
        {
                STRPROP(message, to);
                STRPROP(message, type);
                STRPROP(message, id);
                PAYLOAD(message, body);
        })


// <message type='chat' id='purplef5a7ed34' to='testuser@blarg.potzblitz.outgesourced.org'><active xmlns='http://jabber.org/protocol/chatstates'/><body>gci</body></message>

// <iq type="result" id="unsolicited_2"><query xmlns="jabber:iq:roster"><item subscription="both" jid="willi@potzblitz.outgesourced.org" name="testuser"><group>potzblitz</group></item></query></iq><presence>testuser@blarg.potzblitz.outgesourced.org to="willi@potzblitz.outgesourced.org/potzblitz"</presence><message type="chat" to="willi@potzblitz.outgesourced.org/potzblitz" from="testuser@blarg.potzblitz.outgesourced.org"><body>rgilgci</body></message>

再看看其被引用的地方:

ping@GE60-Kubuntu ~/source/citadel-git/citadel (git)-[master] % grep -rn "token.def" *
modules/xmpp/xmpp_xmacros.c:60:#include "token.def"
modules/xmpp/xmpp_xmacros.c:78:#include "token.def"
modules/xmpp/xmpp_xmacros.c:90:#include "token.def"
modules/xmpp/xmpp_xmacros.c:120:#include "token.def"
modules/xmpp/xmpp_xmacros.h:11:#include "token.def"
modules/xmpp/xmpp_xmacros.h:24:#include "token.def"
modules/xmpp/xmpp_xmacros.h:36:#include "token.def"

从.c开始看吧,也就是从xmpp_xmacros.c开始吧,该文件代码并不多,把与token.def相关的贴出来:

#define STRPROP(STRUCTNAME, NAME)                                       \
        if (StrLength(pdata->NAME) > 0)                                 \
        {                                                               \
        XPut(#NAME, sizeof(#NAME) - 1);                                 \
        XPut("=\"", 2);                                                 \
        XPutProp(SKEY(pdata->NAME));                                    \
        XPut("\" ", 2);                                                 \
        }

#define PAYLOAD(STRUCTNAME, NAME)                                       \
        XPrint(#NAME, sizeof(#NAME) -1,                                 \
               XCLOSED,                                                 \
               TYPE_BODYSTR, SKEY(pdata->NAME),                         \
               TYPE_ARGEND);

#define THENAMESPACE(STRUCTNAME, NAME)                                  \
        XPut(#NAME, sizeof(#NAME) - 1);                                 \
        XPut("=\"", 2);                                                 \
        XPutProp(NAMESPACE_##STRUCTNAME,                                \
                 sizeof(NAMESPACE_##STRUCTNAME)-1);                     \
        XPut("\" ", 2);                                                 

#define TOKEN(NAME, STRUCT)                                             \
        void serialize_##NAME(TheToken_##NAME *pdata, int Close)        \
        {                                                               \
        XPUT("<");                                                      \
        XPut(#NAME, sizeof(#NAME));                                     \
        XPUT(" ");                                                      \
        STRUCT ;                                                        \
        XPUT(">");                                                      \
        if (Close)                                                      \
        {                                                               \
                XPut("</", 2);                                          \
                XPut(#NAME, sizeof(#NAME));                             \
                XPut(">", 1);                                           \
        }                                                               \
        }

#include "token.def"
#undef STRPROP
#undef PAYLOAD
#undef TOKEN


#define STRPROP(STRUCTNAME, NAME)                                       \
        FreeStrBuf(&pdata->NAME);

#define PAYLOAD(STRUCTNAME, NAME)                                       \
        FreeStrBuf(&pdata->NAME);

#define TOKEN(NAME, STRUCT)                                             \
        void free_buf_##NAME(TheToken_##NAME *pdata)                    \
        {                                                               \
                STRUCT ;                                                \
        }

#include "token.def"
#undef STRPROP
#undef PAYLOAD
#undef TOKEN

#define TOKEN(NAME, STRUCT)                                             \
        void free_##NAME(TheToken_##NAME *pdata)                        \
        {                                                               \
                free_buf_##NAME(pdata);                                 \
                free(pdata);                                            \
        }

#include "token.def"
#undef STRPROP
#undef TOKEN

说白了,就是通过每次对STRPROP,PAYLOAD及TOKEN这三个宏定义进行重构,就定义出不同的函数出来。很巧妙的利用宏定义。也正是这样,所以就起了个很奇葩的后缀.def,以IQ这个定义来展开,首次展开的内容应该是这样的:

/* 首次定义TOKEN是生成serialize_iq这个函数 */
void serialize_iq(TheToken_iq *pdata, int Close) /* ## 表示前后两个单词拼接在一起,##NAME展开 */
{
    XPUT("<");
    XPut("iq", sizeof("iq"));        /* # 则是变成字符串了,#NAME展开 */
    XPUT(" ");      
    /* STRUCT ;  这个的话,在iq这个定义里面对应了:
    {
        STRPROP(message, to);
        STRPROP(message, type);
        STRPROP(message, id);
        PAYLOAD(message, body);
    } ,展开略为复杂 */
    { /* 从这里开始展开 */
        if (StrLength(pdata->type) > 0)  /* NAME展开为type */
        {
            XPut("type", sizeof("type") - 1);
            XPut("=\"", 2);                             
            XPutProp(SKEY(pdata->type));
            XPut("\" ", 2);
        }
        if (StrLength(pdata->id) > 0)  /* NAME展开为id */
        {
            XPut("id", sizeof("id") - 1);
            XPut("=\"", 2);                             
            XPutProp(SKEY(pdata->id));
            XPut("\" ", 2);
        }
        if (StrLength(pdata->from) > 0)  /* NAME展开为from */
        {
            XPut("type", sizeof("from") - 1);
            XPut("=\"", 2);                             
            XPutProp(SKEY(pdata->from));
            XPut("\" ", 2);
        }
        if (StrLength(pdata->to) > 0)  /* NAME展开为to */
        {
            XPut("to", sizeof("to") - 1);
            XPut("=\"", 2);                             
            XPutProp(SKEY(pdata->to));
            XPut("\" ", 2);
        }
    } /* 展开到这里结束 */
    XPUT(">");      
    if (Close)       {
        XPut("</", 2);
        XPut("iq", sizeof("iq")); /* 这里有 #NAME 展开 */
        XPut(">", 1);   
    }
}

之后调用了#undef,将所有之前的宏定义都消除了。再次重新定义,重新定义的,则是生成了free_buf系列函数:

void free_buf_iq(TheToken_iq *pdata) /* ##NAME 展开为 iq */
{                
    /* STRUCT ; 展开为如下 */
    {/* 从这里开始展开 */
        FreeStrBuf(&pdata->type); /* STRPROP(iq, type); */
        FreeStrBuf(&pdata->id);   /* STRPROP(iq, id); */
        FreeStrBuf(&pdata->from); /* STRPROP(iq, from); */
        FreeStrBuf(&pdata->to);   /* STRPROP(iq, to); */
    } /* 到这里展开结束 */
}

最后还有一个,就是free_系列的函数了:

void free_iq(TheToken_iq *pdata)  /* ##NAME 展开为 iq */
{                                                              
    free_buf_iq(pdata);       
    free(pdata);                 
}

还有就是在函数CTDL_MODULE_INIT(xmpp_xmacros)里面还展开一次:

char *ctdl_module_xmpp_xmacros_init (int threading)
{
    if (!threading) {
        {
            long offsettype = offsetof(TheToken_iq, type);
            long offsetid = offsetof(TheToken_iq, id);
            long offsetfrom = offsetof(TheToken_iq, from);
            long offsetto = offsetof(TheToken_iq, to);
            
            XMPP_RegisterTokenProperty(NAMESPACE_iq, sizeof(NAMESPACE_iq), "iq", sizeof("iq")-1, "type", sizeof("type")-1, GetToken_iq, offsettype);
            XMPP_RegisterTokenProperty(NAMESPACE_iq, sizeof(NAMESPACE_iq), "iq", sizeof("iq")-1, "id", sizeof("id")-1, GetToken_iq, offsetid);
            XMPP_RegisterTokenProperty(NAMESPACE_iq, sizeof(NAMESPACE_iq), "iq", sizeof("iq")-1, "from", sizeof("from")-1, GetToken_iq, offsetfrom);
            XMPP_RegisterTokenProperty(NAMESPACE_iq, sizeof(NAMESPACE_iq), "iq", sizeof("iq")-1, "to", sizeof("to")-1, GetToken_iq, offsetto);
        }
        {
            long offsettype = offsetof(TheToken_piq, type);
            long offsetid = offsetof(TheToken_piq, id);
            long offsetfrom = offsetof(TheToken_piq, from);
            long offsetto = offsetof(TheToken_piq, to);
            
            XMPP_RegisterTokenProperty(NAMESPACE_piq, sizeof(NAMESPACE_piq), "piq", sizeof("piq")-1, "type", sizeof("type")-1, GetToken_piq, offsettype);
            XMPP_RegisterTokenProperty(NAMESPACE_piq, sizeof(NAMESPACE_piq), "piq", sizeof("piq")-1, "id", sizeof("id")-1, GetToken_piq, offsetid);
            XMPP_RegisterTokenProperty(NAMESPACE_piq, sizeof(NAMESPACE_piq), "piq", sizeof("piq")-1, "from", sizeof("from")-1, GetToken_piq, offsetfrom);
            XMPP_RegisterTokenProperty(NAMESPACE_piq, sizeof(NAMESPACE_piq), "piq", sizeof("piq")-1, "to", sizeof("to")-1, GetToken_piq, offsetto);
        }
        {
            long offsetto = offsetof(TheToken_piq, to);
            long offsettype = offsetof(TheToken_piq, type);
            long offsetid = offsetof(TheToken_piq, id);
            long offsetbody = offsetof(TheToken_piq, body);
            
            XMPP_RegisterTokenProperty(NAMESPACE_message, sizeof(NAMESPACE_message), "message", sizeof("message")-1, "to", sizeof("to")-1, GetToken_message, offsetto);
            XMPP_RegisterTokenProperty(NAMESPACE_message, sizeof(NAMESPACE_message), "message", sizeof("message")-1, "type", sizeof("type")-1, GetToken_message, offsettype);
            XMPP_RegisterTokenProperty(NAMESPACE_message, sizeof(NAMESPACE_message), "message", sizeof("message")-1, "id", sizeof("id")-1, GetToken_message, offsetid);
            XMPP_RegisterTokenProperty(NAMESPACE_message, sizeof(NAMESPACE_message), "message", sizeof("message")-1, NULL, 0, GetToken_piq, offsetto);
        }
    }
    return "xmpp_xmacros";
}

也就是说,在这个.c里面,通过宏的方式,把其定义的给展开成了一系列的函数及实现。而在头文件xmpp_xmacros.h中,测试变成了声明,还是以iq为例。

头文件内容如下:

/*
 * define the structures for one token each
 * typename: TheToken_<Tokenname>
 */
#define PAYLOAD(STRUCTNAME, NAME) StrBuf *NAME;int encoding_##NAME;
#define STRPROP(STRUCTNAME, NAME) StrBuf *NAME;
#define TOKEN(NAME, STRUCT) typedef struct __##NAME	\
	STRUCT						\
	TheToken_##NAME;
#include "token.def"
#undef STRPROP
#undef PAYLOAD
#undef TOKEN


/*
 * forward declarations for freeing the members of one struct instance
 # name: free_buf_<Tokenname>
 */

#define TOKEN(NAME, STRUCT)						\
	void free_buf_##NAME(TheToken_##NAME *pdata);
#include "token.def"
#undef STRPROP
#undef PAYLOAD
#undef TOKEN

/*
 * forward declarations, freeing structs and member. 
 * name: free_<Tokenname>
 */
#define TOKEN(NAME, STRUCT)						\
	void free_##NAME(TheToken_##NAME *pdata);

#include "token.def"
#undef STRPROP
#undef PAYLOAD
#undef TOKEN

展开后对应为(竟然少了serialize_iq函数的定义。。。。好吧,可能是二妈生的):

typedef struct __iq {
    StrBuf *type;
    StrBuf *id;
    StrBuf *from;
    StrBuf *to;
} TheToken_iq;

void free_buf_iq(TheToken_iq *pdata);
void free_iq(TheToken_iq *pdata);

从上面的工作量来看,和对应的简短的代码,就可以看出该宏定义的优点了,将重复的工作简单化,让编译器去瞎忙活就行了(累死我了,展开这些)。从现有重构的代码上来看,用到的其实就只有TheToken_iq及TheToken_message,那个TheToken_piq还没有看到有哪里有用到(和iq参数一样)。这样也就方便我们扩展了,因为XMPP其实是支持非常多的扩展的,总不能每次需要一个节的时候,你总要写一大票的代码,通过token.def,就可以扩展的时候,只是做这么一个工作:

#define NAMESPACE_iq "jabber:client"
TOKEN(iq,
      {
	      STRPROP(iq, type);
	      STRPROP(iq, id);
	      STRPROP(iq, from);
	      STRPROP(iq, to);
      })

既快捷又方便。并不需要知道其再哪里有了什么样的实现。好了,taken.def就先说到这里了。XMPP模块还有很多的改动,如XPUT,原先的输出并不是使用该函数的。更多内容,下次的文章再进一步补充。

 

转载请注明: 转载自elkPi.com

本文链接地址: citadel学习笔记4——git版本XMPP模块之token.def

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

Scroll to top