Jabberd2源代码分析: SX

    技术2022-05-19  48

    SX模块提供了Jabberd2的插件机制。在代码的关键部位为了扩展方便设置执行点,如果在此执行点上设置了“插件”,则按照注册插件的顺序执行这些注册的函数。

     

    Jabberd2定义了一下结构体:

     

     

    /** a plugin */ struct _sx_plugin_st { sx_env_t env; /* unique id so that plugins can find each other */ int magic; /* 在sx_env_t中plugins数组中的索引 */ int index; /* 如果插件中需要保存一些自定义数据,可以保存在这里 */ void *private; /* pre-run init */ void (*new)(sx_t s, sx_plugin_t p); /* conn being freed */ void (*free)(sx_t s, sx_plugin_t p); /* client init */ void (*client)(sx_t s, sx_plugin_t p); /* server init */ void (*server)(sx_t s, sx_plugin_t p); /* return -2 == failed (permanent), -1 == failed (temporary), 0 == handled, 1 == pass */ int (*wio)(sx_t s, sx_plugin_t p, sx_buf_t buf); /* before being written */ int (*rio)(sx_t s, sx_plugin_t p, sx_buf_t buf); /* after being read */ /* return 0 == handled, 1 == pass */ int (*wnad)(sx_t s, sx_plugin_t p, nad_t nad, int elem); /* before being written */ int (*rnad)(sx_t s, sx_plugin_t p, nad_t nad); /* after being read */ void (*header)(sx_t s, sx_plugin_t p, sx_buf_t buf); /* before header req/res write */ void (*stream)(sx_t s, sx_plugin_t p); /* after-stream init */ void (*features)(sx_t s, sx_plugin_t p, nad_t nad); /* offer features */ /* return 0 == handled, 1 == pass */ int (*process)(sx_t s, sx_plugin_t p, nad_t nad); /* process completed nads */ void (*unload)(sx_plugin_t p); /* plugin unloading */ }; struct _sx_env_st { struct *plugins; int nplugins; };

     

    sx_env_t用于保存Jabberd2中所有的插件。使用sx_env_new分配一个sx_env_t结构体变量。

     

    sx_plugin_t用来保存具体的插件信息,其中包含一些函数指针,这些函数会在设定的位置调用。

     

     

    函数:sx_plugin_t sx_env_plugin(sx_env_t env, sx_plugin_init_t init, ...)

    返回一个sx_plugin_t结构体,在 sx_env_plugin函数中会调用传入的init函数。 然后将动态分配sx_plugin_t变量加入到sx_env_t中。

    一般情况下传入的init函数都是初始化sx_plugin_t结构体中的函数指针。

     

     

     

    ======

    插件:

    1,client ssl

    2,  router ssl

    3,  compression

    4,  stanza ack

    5,  user ip address

    6,  sasl

    7,  bind 

     

     

     

    /** things that can happen */

    typedef enum {

        event_WANT_READ,        /* we want read actions */

        event_WANT_WRITE,       /* we want write actions */

        event_READ,             /* read some stuff for me */

        event_WRITE,            /* write this to the fd */

        event_STREAM,           /* stream is ready to go */

        event_OPEN,             /* normal operation */

        event_PACKET,           /* got a packet */

        event_CLOSED,           /* its over */

        event_ERROR             /* something's wrong */

    } sx_event_t;

     

    sx中定义的事件

     

    sx_t sx_new(sx_env_t env, int tag, sx_callback_t cb, void *arg)

    分配一个sx_t结构体

     

    void sx_client_init(sx_t s, unsigned int flags, char *ns, char *to, char *from, char *version)主动连接另一个服务器的时候,调用这个函数 。

    在c2s中当连接到router后,调用sx_client_init函数。

    在该函数中:

    1, 调用插件中void (*client)(sx_t s, sx_plugin_t p)函数

    2, 构造stream

    3, 调用插件中void (*header)(sx_t s, sx_plugin_t p, sx_buf_t buf)函数 

    4, 将构造好的stream字符串加入到wbufq中,然后设置event_WANT_WRITE

     

    int __sx_event(const char *file, int line, sx_t s, sx_event_t e, void *data)

    参数中file, line是用来调试用的。

     

    这里会调用传入sx_new函数的cb回调函数。

     

    void sx_kill(sx_t s)

    关闭socket

     

    int sx_can_write(sx_t s)

    mio中当事件action_WRITE被设置表明有数据需要发送,这时会调用这个函数。

    在函数中会调用插件函数int (*wio)(sx_t s, sx_plugin_t p, sx_buf_t buf); 如果确实有数据要写,则设置事件event_WRITE。如果数据一次行全部发送完毕,调用sx_buffer_new设置的回调函数;如果只发送了部分数据,则需要重新设置发送标志,以及设置下一次发送剩余数据的起始位置和大小。

     

     

    int sx_can_read(sx_t s)

    mio中当事件action_READ被设置表明有数据需要读取,这时会调用这个函数。

    调用回调函数读取数据,读到数据后,如果设置了rio插件,则将数据传入给插件处理,最后交由_sx_process_read处理读到的数据。

     

     

    void _sx_process_read(sx_t s, sx_buf_t buf)

    解析XML数据

    解析成功后,做必要的错误检查。如果没有错误发生,设置event_PACKET标志,交由回调函数处理。

     

    =======================================

    c2s中重要的两个回调函数:

    int c2s_router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg)

    调用sx_new函数时设置的回调函数

    该回调函数实现了针对sx_event定义的事件

    event_WANT_READ

    设置mio读事件

     

    event_WANT_WRITE

    设置mio写事件

     

    event_PACKET

    读到一个XML Stanza后设置event_PACKET 事件,由回调函数继续处理。

     


    最新回复(0)