struct usr_avp *clone_avp_list(struct usr_avp *old) { struct usr_avp *a; int_str val; if (!old) return NULL; /* create a copy of the old AVP */ get_avp_val( old, &val ); a = new_avp( old->flags, old->id, val); if (a==NULL) { LM_ERR("cloning failed, trunking the list\n"); return NULL; } a->next = clone_avp_list(old->next); return a; }
int notify_ebr_subscriptions( ebr_event *ev, evi_params_t *params) { ebr_subscription *sub, *sub_next, *sub_prev; ebr_filter *filter; ebr_ipc_job *job; evi_param_t *e_param; int matches; char *s; struct usr_avp *avps=(void*)-1; unsigned int my_time; LM_DBG("notification received for event %.*s, checking subscriptions\n", ev->event_name.len, ev->event_name.s); my_time = get_ticks(); lock_get( &(ev->lock) ); /* check the EBR subscription on this event and apply the filters */ sub_prev = NULL; for ( sub=ev->subs ; sub ; sub_prev=sub, sub=sub_next?sub_next:(sub?sub->next:NULL) ) { /* discard expired NOTIFY subscriptions */ if (sub->flags&EBR_SUBS_TYPE_NOTY && sub->expire<my_time) { LM_DBG("subscription type [NOTIFY]from process %d(pid %d) on " "event <%.*s> expired at %d\n", sub->proc_no, pt[sub->proc_no].pid, sub->event->event_name.len, sub->event->event_name.s, sub->expire ); /* remove the subscription */ sub_next = sub->next; /* unlink it */ if (sub_prev) sub_prev->next = sub_next; else ev->subs = sub_next; /* free it */ free_ebr_subscription(sub); /* do not count us as prev, as we are removed */ sub = sub_prev; continue; } /* run the filters */ matches = 1; sub_next = NULL; for ( filter=sub->filters ; matches && filter ; filter=filter->next ) { /* look for the evi param with the same name */ for ( e_param=params->first ; e_param ; e_param=e_param->next ) { if (e_param->name.len==filter->key.len && strncasecmp(e_param->name.s,filter->key.s,filter->key.len)==0){ /* name matches, let's see the value */ LM_DBG("key <%.*s> found, checking value \n", filter->key.len, filter->key.s); if (filter->val.len==0) { /* a "no value" matches anything */ } else { if (e_param->flags&EVI_INT_VAL) { s=int2str((unsigned long)e_param->val.n, NULL); if (s==NULL) { LM_ERR("failed to covert int EVI param to " "string, EBR filter failed\n"); matches = 0; } else { /* the output of int2str is NULL terminated */ if (fnmatch( filter->val.s, s, 0)!=0) matches = 0; } } else if (e_param->flags&EVI_STR_VAL) { s=(char*)pkg_malloc(e_param->val.s.len+1); if (s==NULL) { LM_ERR("failed to allocate PKG fnmatch " "buffer, EBR filter failed\n"); matches = 0; } else { memcpy(s,e_param->val.s.s,e_param->val.s.len); s[e_param->val.s.len] = 0; if (fnmatch( filter->val.s, s, 0)!=0) matches = 0; pkg_free(s); } } else { LM_ERR("non-string EVI params are not supported " "yet\n"); matches = 0; } } break; } /* a filter not matching any EVI params is simply ignored */ } /* end EVI param iterator */ } /* end EBR filter iterator */ /* did the EVI event match the EBR filters for this subscription ? */ if (matches) { LM_DBG("subscription type [%s]from process %d(pid %d) matched " "event, generating notification via IPC\n", (sub->flags&EBR_SUBS_TYPE_WAIT)?"WAIT":"NOTIFY", sub->proc_no, pt[sub->proc_no].pid); /* convert the EVI params into AVP (only once) */ if (avps==(void*)-1) { avps = pack_evi_params_as_avp_list(params); } /* pack the EVI params to be attached to the IPC job */ job =(ebr_ipc_job*)shm_malloc( sizeof(ebr_ipc_job) ); if (job==NULL) { LM_ERR("failed to allocated new IPC job, skipping..\n"); continue; /* with the next subscription */ } job->ev = ev; job->avps = clone_avp_list( avps ); job->data = sub->data; job->flags = sub->flags; job->tm = sub->tm; if (sub->flags&EBR_SUBS_TYPE_NOTY) { /* dispatch the event notification via IPC to the right * process. Key question - which one is the "right" process ? * - the current processs * - the process which performed the subscription * Let's give it to ourselves for the moment */ if (ipc_send_job( process_no, ebr_ipc_type , (void*)job)<0) { LM_ERR("failed to send job via IPC, skipping...\n"); shm_free(job); } } else { /* sent the event notification via IPC to resume on the * subscribing process */ if (ipc_send_job( sub->proc_no, ebr_ipc_type , (void*)job)<0) { LM_ERR("failed to send job via IPC, skipping...\n"); shm_free(job); } /* remove the subscription, as it can be triggered only * one time */ sub_next = sub->next; /* unlink it */ if (sub_prev) sub_prev->next = sub_next; else ev->subs = sub_next; /* free it */ free_ebr_subscription(sub); /* do not count us as prev, as we are removed */ sub = sub_prev; } } } /* end EBR subscription iterator */ lock_release( &(ev->lock) ); if (avps!=(void*)-1) destroy_avp_list( &avps ); return 0; }