/* Register a new hook callback */ int fd_hook_register ( uint32_t type_mask, 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), void *regdata, struct fd_hook_data_hdl *data_hdl, struct fd_hook_hdl ** handler ) { struct fd_hook_hdl * newhdl = NULL; int i; TRACE_ENTRY("%x %p %p %p %p", type_mask, fd_hook_cb, regdata, data_hdl, handler); CHECK_PARAMS( fd_hook_cb && handler ); CHECK_MALLOC( newhdl = malloc(sizeof(struct fd_hook_hdl)) ); memset(newhdl, 0, sizeof(struct fd_hook_hdl)); newhdl->fd_hook_cb = fd_hook_cb; newhdl->regdata = regdata; newhdl->data_hdl = data_hdl; for (i=0; i <= HOOK_LAST; i++) { fd_list_init(&newhdl->chain[i], newhdl); if (type_mask & (1<<i)) { CHECK_POSIX( pthread_rwlock_wrlock(&HS_array[i].rwlock) ); fd_list_insert_before( &HS_array[i].sentinel, &newhdl->chain[i]); CHECK_POSIX( pthread_rwlock_unlock(&HS_array[i].rwlock) ); } } *handler = newhdl; return 0; }
/* Return the location of the permsgdata area corresponding to this handle, after eventually having created it. Return NULL in case of failure */ static struct fd_hook_permsgdata * get_or_create_pmd(struct fd_msg_pmdl *pmdl, struct fd_hook_data_hdl * h) { struct fd_hook_permsgdata * ret = NULL; struct fd_list * li; CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), ); if (pmdl->sentinel.o == NULL) { pmdl->sentinel.o = pmdl_free; } /* Search in the list for an item with the same handle. The list is ordered by this handle */ for (li=pmdl->sentinel.next; li != &pmdl->sentinel; li = li->next) { struct pmd_list_item * pli = (struct pmd_list_item *) li; if (pli->hdl == h) ret = &pli->pmd; if (pli->hdl >= h) break; } if (!ret) { /* we need to create a new one and insert before li */ struct pmd_list_item * pli; CHECK_MALLOC_DO( pli = malloc(sizeof_pmd(h)), ); if (pli) { memset(pli, 0, sizeof_pmd(h)); fd_list_init(&pli->chain, pli); pli->hdl = h; ret = &pli->pmd; if (h->pmd_init_cb) { (*h->pmd_init_cb)(ret); } fd_list_insert_before(li, &pli->chain); } } CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), ); return ret; }
/* Add a new peer entry */ int fd_peer_add ( struct peer_info * info, const char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data ) { struct fd_peer *p = NULL; struct fd_list * li, *li_inf; int ret = 0; TRACE_ENTRY("%p %p %p %p", info, orig_dbg, cb, cb_data); CHECK_PARAMS(info && info->pi_diamid); if (info->config.pic_realm) { if (!fd_os_is_valid_DiameterIdentity((os0_t)info->config.pic_realm, strlen(info->config.pic_realm))) { TRACE_DEBUG(INFO, "'%s' is not a valid DiameterIdentity.", info->config.pic_realm); return EINVAL; } } /* Create a structure to contain the new peer information */ CHECK_FCT( fd_peer_alloc(&p) ); /* Copy the informations from the parameters received */ p->p_hdr.info.pi_diamid = info->pi_diamid; CHECK_FCT( fd_os_validate_DiameterIdentity(&p->p_hdr.info.pi_diamid, &p->p_hdr.info.pi_diamidlen, 1) ); memcpy( &p->p_hdr.info.config, &info->config, sizeof(p->p_hdr.info.config) ); /* Duplicate the strings if provided */ if (info->config.pic_realm) { CHECK_MALLOC( p->p_hdr.info.config.pic_realm = strdup(info->config.pic_realm) ); } if (info->config.pic_priority) { CHECK_MALLOC( p->p_hdr.info.config.pic_priority = strdup(info->config.pic_priority) ); } /* Move the list of endpoints into the peer */ if (info->pi_endpoints.next) while (!FD_IS_LIST_EMPTY( &info->pi_endpoints ) ) { li = info->pi_endpoints.next; fd_list_unlink(li); fd_list_insert_before(&p->p_hdr.info.pi_endpoints, li); } /* The internal data */ if (orig_dbg) { CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) ); } else { CHECK_MALLOC( p->p_dbgorig = strdup("unspecified") ); } p->p_cb = cb; p->p_cb_data = cb_data; /* Ok, now check if we don't already have an entry with the same Diameter Id, and insert this one */ CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) ); li_inf = &fd_g_peers; for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) { struct fd_peer * next = (struct fd_peer *)li; int cont; int cmp = fd_os_almostcasesrch( p->p_hdr.info.pi_diamid, p->p_hdr.info.pi_diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen, &cont ); if (cmp > 0) li_inf = li; /* it will come after this element, for sure */ if (cmp == 0) { ret = EEXIST; /* we have a duplicate */ break; } if (!cont) break; } /* We can insert the new peer object */ if (! ret) do { /* Update expiry list */ CHECK_FCT_DO( ret = fd_p_expi_update( p ), break ); /* Insert the new element in the list */ fd_list_insert_after( li_inf, &p->p_hdr.chain ); } while (0); CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) ); if (ret) { CHECK_FCT( fd_peer_free(&p) ); } else { CHECK_FCT( fd_psm_begin(p) ); } return ret; }