Navigation


Changeset 1098:f38d77f9cfd3 in freeDiameter for libfdcore


Ignore:
Timestamp:
May 9, 2013, 12:59:34 PM (11 years ago)
Author:
Sebastien Decugis <sdecugis@freediameter.net>
Branch:
default
Phase:
public
Message:

Initial implementation of the hook mechanism

Location:
libfdcore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • libfdcore/cnxctx.c

    r1084 r1098  
    736736                }
    737737               
     738                // fd_msg_log(....)
     739               
    738740                /* We have received a complete message, pass it to the daemon */
    739741                CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
  • libfdcore/core.c

    r1085 r1098  
    187187       
    188188        /* Initialize some modules */
     189        CHECK_FCT( fd_hooks_init()  );
    189190        CHECK_FCT( fd_queues_init() );
    190191        CHECK_FCT( fd_msg_init()    );
  • libfdcore/fdcore-internal.h

    r1085 r1098  
    363363#define FD_CNX_ORDERED          (1 << 0)        /* All messages sent with this flag set will be delivered in the same order. No guarantee on other messages */
    364364
     365/* Internal calls of the hook mechanism */
     366void   fd_hook_call(enum fd_hook_type type, struct msg * msg, struct fd_peer * peer, void * other, struct fd_msg_pmdl * pmdl);
     367void   fd_hook_associate(struct msg * msg, struct fd_msg_pmdl * pmdl);
     368int    fd_hooks_init(void);
    365369#endif /* _FDCORE_INTERNAL_H */
  • libfdcore/hooks.c

    r1077 r1098  
    3636#include "fdcore-internal.h"
    3737
    38 struct fd_hook_hdl;
    39 struct fd_hook_data_hdl;
    40 
     38/* Structures for the fd_hook_data_hdl management */
     39static struct fd_hook_data_hdl {
     40        size_t  pmd_size;
     41        void  (*pmd_init_cb)(struct fd_hook_permsgdata *);
     42        void  (*pmd_fini_cb)(struct fd_hook_permsgdata *);
     43} HDH_array[FD_HOOK_HANDLE_LIMIT];
     44static int max_index = 0;
     45static pthread_mutex_t HDH_lock = PTHREAD_MUTEX_INITIALIZER;
     46
     47/* The structure linked from the msg structure list */
     48struct pmd_list_item {
     49        struct fd_list  chain;          /* this list is ordered by hdl */
     50        struct fd_hook_data_hdl * hdl;
     51        struct fd_hook_permsgdata { } pmd; /* this data belongs to the extension; we only know the size of it */
     52};
     53
     54#define sizeof_pmd(hdl) (((size_t)&((struct pmd_list_item *)0)->pmd) + hdl->pmd_size)
     55
     56/* Now a hook registered by an extension */
     57struct fd_hook_hdl {
     58        struct fd_list chain[HOOK_PEER_LAST+1];
     59        void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata);
     60        void  *regdata;
     61        struct fd_hook_data_hdl *data_hdl;
     62};
     63
     64/* Array of those hooks */
     65struct {
     66        struct fd_list sentinel;
     67        pthread_rwlock_t rwlock;
     68} HS_array[HOOK_PEER_LAST+1];
     69
     70/* Initialize the array of sentinels for the hooks */
     71int fd_hooks_init(void)
     72{
     73        int i;
     74        for (i=0; i <= HOOK_PEER_LAST; i++) {
     75                fd_list_init(&HS_array[i].sentinel, NULL);
     76                CHECK_POSIX( pthread_rwlock_init(&HS_array[i].rwlock, NULL) );
     77        }
     78        return 0;
     79}
     80
     81/* Get a slot in the array */
    4182int fd_hook_data_register(
    42         struct fd_hook_permsgdata * (*permsgdata_new_cb)     (void),
    43         void (*permsgdata_destroy_cb) (struct fd_hook_permsgdata *),
    44         struct fd_hook_data_hdl **    new_handle
    45 )
    46 {
    47         return ENOTSUP;
    48 }
    49 
    50 int fd_hook_register (  enum fd_hook_type type,
    51                         void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, void * regdata),
    52                         void * regdata,
     83        size_t permsgdata_size,
     84        void (*permsgdata_init_cb) (struct fd_hook_permsgdata *),
     85        void (*permsgdata_fini_cb) (struct fd_hook_permsgdata *),
     86        struct fd_hook_data_hdl **new_handle)
     87{
     88        int ret = ENOSPC, idx;
     89        TRACE_ENTRY("%zd %p %p %p", permsgdata_size, permsgdata_init_cb, permsgdata_fini_cb, new_handle);
     90       
     91        CHECK_PARAMS( permsgdata_size && new_handle );
     92       
     93        CHECK_POSIX( pthread_mutex_lock(&HDH_lock) );
     94        if (max_index < FD_HOOK_HANDLE_LIMIT) {
     95                idx = max_index++;
     96                ret = 0;
     97        }
     98        CHECK_POSIX( pthread_mutex_unlock(&HDH_lock) );
     99       
     100        if (ret == 0) {
     101                HDH_array[idx].pmd_size = permsgdata_size;
     102                HDH_array[idx].pmd_init_cb = permsgdata_init_cb;
     103                HDH_array[idx].pmd_fini_cb = permsgdata_fini_cb;
     104                *new_handle = &HDH_array[idx];
     105        }
     106       
     107        return ret;
     108}
     109
     110/* Register a new hook callback */
     111int fd_hook_register (  uint32_t type_mask,
     112                        void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata),
     113                        void  *regdata,
    53114                        struct fd_hook_data_hdl *data_hdl,
    54115                        struct fd_hook_hdl ** handler )
    55116{
    56         return ENOTSUP;
    57 }
    58 
    59 
     117        struct fd_hook_hdl * newhdl = NULL;
     118        int i;
     119       
     120        TRACE_ENTRY("%x %p %p %p %p", type_mask, fd_hook_cb, regdata, data_hdl, handler);
     121       
     122        CHECK_PARAMS( fd_hook_cb && handler );
     123       
     124        CHECK_MALLOC( newhdl = malloc(sizeof(struct fd_hook_hdl)) );
     125        memset(newhdl, 0, sizeof(struct fd_hook_hdl));
     126       
     127        newhdl->fd_hook_cb = fd_hook_cb;
     128        newhdl->regdata = regdata;
     129        newhdl->data_hdl = data_hdl;
     130       
     131        for (i=0; i <= HOOK_PEER_LAST; i++) {
     132                fd_list_init(&newhdl->chain[i], newhdl);
     133                if (type_mask & (1<<i)) {
     134                        CHECK_POSIX( pthread_rwlock_wrlock(&HS_array[i].rwlock) );
     135                        fd_list_insert_before( &HS_array[i].sentinel, &newhdl->chain[i]);
     136                        CHECK_POSIX( pthread_rwlock_unlock(&HS_array[i].rwlock) );
     137                }
     138        }
     139       
     140        *handler = newhdl;
     141        return 0;
     142}
     143
     144/* free this hook callback */
    60145int fd_hook_unregister( struct fd_hook_hdl * handler )
    61146{
    62         return ENOTSUP;
    63 }
    64 
     147        int i;
     148        TRACE_ENTRY("%p", handler);
     149        CHECK_PARAMS( handler );
     150       
     151        for (i=0; i <= HOOK_PEER_LAST; i++) {
     152                if ( ! FD_IS_LIST_EMPTY(&handler->chain[i])) {
     153                        CHECK_POSIX( pthread_rwlock_wrlock(&HS_array[i].rwlock) );
     154                        fd_list_unlink(&handler->chain[i]);
     155                        CHECK_POSIX( pthread_rwlock_unlock(&HS_array[i].rwlock) );
     156                }
     157        }
     158       
     159        free(handler);
     160       
     161        return 0;
     162}
     163
     164/* callback for the libfdproto to free the data associated with a message */
     165static void pmdl_free(struct fd_msg_pmdl *pmdl)
     166{
     167        /* destroy all the items in the list */
     168        while (!FD_IS_LIST_EMPTY(&pmdl->sentinel)) {
     169                struct pmd_list_item * li = (struct pmd_list_item *)(pmdl->sentinel.next);
     170                if (li->hdl->pmd_fini_cb) {
     171                        (*li->hdl->pmd_fini_cb)(&li->pmd);
     172                }
     173                fd_list_unlink(&li->chain);
     174                free(li);
     175        }
     176        CHECK_POSIX_DO( pthread_mutex_destroy(&pmdl->lock), );
     177        pmdl->sentinel.o = NULL;
     178}
     179
     180/* Save the list of pmd into the message structure, as well as the callback to free this list */
     181void   fd_hook_associate(struct msg * msg, struct fd_msg_pmdl * pmdl)
     182{
     183        struct fd_msg_pmdl * in_msg;
     184       
     185        CHECK_PARAMS_DO( msg && pmdl, return );
     186        in_msg = fd_msg_pmdl_get(msg);
     187        ASSERT(in_msg && (in_msg->sentinel.o == NULL)); /* error / already initialized ??? */
     188        fd_list_init(&in_msg->sentinel, pmdl_free);
     189        CHECK_POSIX_DO( pthread_mutex_init(&in_msg->lock, NULL), );
     190        /* Now move all items from the pmdl pointer into the initialized list */
     191        CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
     192        fd_list_move_end(&in_msg->sentinel, &pmdl->sentinel);
     193        CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
     194        pmdl_free(pmdl);
     195        /* We're done */
     196}
     197
     198/* Return the location of the permsgdata area corresponding to this handle, after eventually having created it. Return NULL in case of failure */
     199static struct fd_hook_permsgdata * get_or_create_pmd(struct fd_msg_pmdl *pmdl, struct fd_hook_hdl * h)
     200{
     201        struct fd_hook_permsgdata * ret = NULL;
     202        struct fd_list * li;
     203        CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
     204       
     205        /* Search in the list for an item with the same handle. The list is ordered by this handle */
     206        for (li=pmdl->sentinel.next; li != &pmdl->sentinel; li = li->next) {
     207                struct pmd_list_item * pli = (struct pmd_list_item *) li;
     208                if (pli->hdl == h->data_hdl)
     209                        ret = &pli->pmd;
     210                if (pli->hdl >= h->data_hdl)
     211                        break;
     212        }
     213        if (!ret) {
     214                /* we need to create a new one and insert before li */
     215                struct pmd_list_item * pli;
     216                CHECK_MALLOC_DO( pli = malloc(sizeof_pmd(h->data_hdl)), );
     217                if (pli) {
     218                        memset(pli, 0, sizeof_pmd(h->data_hdl));
     219                        fd_list_init(&pli->chain, pli);
     220                        pli->hdl = h->data_hdl;
     221                        ret = &pli->pmd;
     222                        if (h->data_hdl->pmd_init_cb) {
     223                                (*h->data_hdl->pmd_init_cb)(ret);
     224                        }
     225                        fd_list_insert_before(li, &pli->chain);
     226                }
     227        }
     228       
     229        CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
     230        return ret;
     231}
     232
     233
     234/* The function that does the work of calling the extension's callbacks and also managing the permessagedata structures */
     235void   fd_hook_call(enum fd_hook_type type, struct msg * msg, struct fd_peer * peer, void * other, struct fd_msg_pmdl * pmdl)
     236{
     237        struct fd_list * li;
     238        ASSERT(type <= HOOK_PEER_LAST);
     239       
     240        /* lock the list of hooks for this type */
     241        CHECK_POSIX_DO( pthread_rwlock_rdlock(&HS_array[type].rwlock), );
     242       
     243        /* for each registered hook */
     244        for (li = HS_array[type].sentinel.next; li != &HS_array[type].sentinel; li = li->next) {
     245                struct fd_hook_hdl * h = (struct fd_hook_hdl *)li->o;
     246                struct fd_hook_permsgdata * pmd = NULL;
     247               
     248                /* do we need to handle pmd ? */
     249                if (h->data_hdl && pmdl) {
     250                        pmd = get_or_create_pmd(pmdl, h);
     251                }
     252               
     253                /* Now, call this callback */
     254                (*h->fd_hook_cb)(type, msg, &peer->p_hdr, other, pmd, h->regdata);
     255        }
     256       
     257        /* done */
     258        CHECK_POSIX_DO( pthread_rwlock_unlock(&HS_array[type].rwlock), );
     259}
Note: See TracChangeset for help on using the changeset viewer.