Beispiel #1
0
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;
}
Beispiel #2
0
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;
}