Exemple #1
0
/** Frees a hdr_field list.
 * WARNING: frees only ->parsed and ->next*/
void free_hdr_field_lst(struct hdr_field* hf)
{
	struct hdr_field* foo;

	while(hf) {
		foo=hf;
		hf=hf->next;
		clean_hdr_field(foo);
		pkg_free(foo);
	}
}
Exemple #2
0
static int mc_compact_cb(char** buf_p, void* param, int type, int* olen)
{
	int i;
	int msg_total_len;
	int rtpmap_val=0, rtpmap_len;
	int new_body_len;
	int hdr_len;

	str msg_start;
	str new_buf;

	char *buf=*buf_p;
	char *buf_cpy;
	char *end=buf+*olen;

	struct hdr_field *hf;
	struct hdr_field** hdr_mask;
	struct mc_cmpct_args* args;

	body_frag_p frg;
	body_frag_p frg_head;
	body_frag_p temp;

	mc_param_p wh_param;
	mc_whitelist_p wh_list;


	args = (struct mc_cmpct_args*)param;

	wh_param = args->wh_param;
	wh_list  = args->wh_list;

	hdr_mask = pkg_malloc(HDR_EOH_T * sizeof(struct hdr_field*));

	if (!hdr_mask)
		goto memerr;

	memset(hdr_mask, 0, HDR_EOH_T * sizeof(struct hdr_field*));

	mc_parse_first_line( &msg_start, &buf);

	msg_total_len = msg_start.len;

	/* Start to parse the headers and print them*/
	while (1) {
		hf = pkg_malloc(sizeof(struct hdr_field));
		if (hf == NULL) {
			LM_ERR("no more pkg mem\n");
			goto memerr;
		}
		memset(hf, 0, sizeof(struct hdr_field));
		hf->type=HDR_ERROR_T;
		buf=get_hdr_field(buf, end, hf);

		if (hf->type == HDR_ERROR_T) {
			goto free_mem;
		}

		if (hf->type == HDR_EOH_T) {
			pkg_free(hf);
			break;
		}

		if (mc_is_in_whitelist(hf, wh_list)) {
			if (hdr_mask[hf->type]) {
				/* If hdr already found or hdr of type other */
				if (append_hf2lst(&hdr_mask[hf->type], hf,
							&msg_total_len)) {
					LM_ERR("Cannot append hdr to lst\n");
					return -1;
				}
			} else {
				unsigned char c;

				/* Get the compact form of the header */
				if (hf->type != HDR_OTHER_T &&
					(c=get_compact_form(hf)) != NO_FORM) {

					hf->name.s = COMPACT_FORMS+c;
					hf->name.len = 1;
				}

				/* update the len of the new buffer */
				msg_total_len += hf->name.len + DELIM_LEN;
				msg_total_len += hf->body.len + CRLF_LEN;

				hdr_mask[hf->type] = hf;
			}
		} else {
			clean_hdr_field(hf);
		}

		hf = 0;
	}

	hdr_len = msg_total_len;

	buf_cpy = buf+CRLF_LEN;
	frg = frg_head = pkg_malloc(sizeof(body_frag_t));
	if (!frg)
		goto memerr;

	frg->begin = 0;
	frg->end = CRLF_LEN;
	frg->next = NULL;

	/* parse the body and extract fragments */
	while (buf_cpy != end) {
		while (*buf_cpy == ' ' || *buf_cpy == '\t')
				(buf_cpy++, frg->end++);

		if (*buf_cpy != 'a') {
			/* Jump over the entire row*/
			goto row_jump;
		}
		else if (strncmp(buf_cpy, "a=rtpmap:", 9))
			goto row_jump;
		/* found rtpmap */
		else {
			buf_cpy += 9;
			frg->end--; /* already on 'a' char */
			rtpmap_len = rtpmap_val = 0;

			while (*buf_cpy >= '0' && *buf_cpy <= '9') {
				rtpmap_val = rtpmap_val*10 + (*buf_cpy - '0');
				(buf_cpy++, rtpmap_len++);
			}

			if (rtpmap_val < 98) {
				msg_total_len += frg->end - frg->begin + 1;
				frg->next = pkg_malloc(sizeof(body_frag_t));
				if (!frg->next)
					goto memerr;

				frg = frg->next;
				frg->next = NULL;

				/* find the next line and set the start of the next fragment */
				while (*buf_cpy != '\n') buf_cpy++;
				buf_cpy++;

				frg->end = frg->begin = buf_cpy - buf;
				continue;
			} else {
				/*currently on \n before rtpmap. Need to jump over \nrtpmap:RT_VAL */
				frg->end += 9 + rtpmap_len + 1;
			}
		}

		row_jump:
			while (*buf_cpy != '\n') {
				if (*buf_cpy == '\0') {
					LM_ERR("BUG! Message body not containing '\\n' in the end\n");
					return -1;
				}
				(buf_cpy++, frg->end++);
			}
		(buf_cpy++, frg->end++);
	}

	int foo;

	/* not storing '\0' at the end of the message */
	(buf_cpy--, frg->end--);

	msg_total_len += frg->end - frg->begin + 1;

	new_body_len = msg_total_len - hdr_len;

	/* creating the new content length */
	hf = pkg_malloc(sizeof(struct hdr_field));
	if (hf == NULL)
		goto memerr;
	memset(hf, 0, sizeof(struct hdr_field));

	hf->type = HDR_CONTENTLENGTH_T;
	hf->name.s = COMPACT_FORMS + get_compact_form(hf);
	hf->name.len = 1;

	if (new_body_len <= CRLF_LEN)
		new_body_len = 0;

	hf->body.len = mc_ndigits(new_body_len);
	hf->body.s = int2str( new_body_len, &foo);
	if (hf->body.s == 0) {
		LM_ERR("failed to convert int to string\n");
		goto memerr;
	}

	/*
	 * If body is empty Content-Type is not necessary anymore
	 * But only if Content-Type exists
	 */
	if (hdr_mask[HDR_CONTENTTYPE_T] && new_body_len == 0) {
		clean_hdr_field(hdr_mask[HDR_CONTENTTYPE_T]);
		hdr_mask[HDR_CONTENTTYPE_T] = NULL;
	}

	msg_total_len += hf->name.len + DELIM_LEN + hf->body.len + CRLF_LEN;
	hdr_mask[hf->type] = hf;

	/* build the new buffer */
	if (wrap_realloc(&buf_out, msg_total_len))
		goto free_mem;

	new_buf.s = buf_out.s;
	new_buf.len = 0;

	/* Copy the beginning of the message */
	wrap_copy_and_update( &new_buf.s, msg_start.s, msg_start.len,
							&new_buf.len);

	/* Copy all the headers */
	for (i = HDR_VIA_T; i <= HDR_EOH_T; i++) {
		/* Just to put headers of type other after
			all the other headers */
		if (i == HDR_EOH_T)
			i = HDR_OTHER_T;
again:
		if (hdr_mask[i]) {
			/* Compact form name so the header have
				to be built */
			if (LOWER_CASE(hdr_mask[i]->name.s)) {
				/* Copy the name of the header */
				wrap_copy_and_update(&new_buf.s,
					hdr_mask[i]->name.s,
					hdr_mask[i]->name.len, &new_buf.len);

				/* Copy the ': ' delimiter*/
				wrap_copy_and_update(&new_buf.s, DELIM,
						DELIM_LEN, &new_buf.len);
				/* Copy the first field of the header*/
				wrap_copy_and_update(&new_buf.s,
					hdr_mask[i]->body.s,
					hdr_mask[i]->body.len, &new_buf.len);
			/* Normal form header so it can be copied in one step */
			} else {
				wrap_copy_and_update(
					&new_buf.s,
					hdr_mask[i]->name.s,
					/* Possible siblings. No CRLF yet */
					hdr_mask[i]->len - CRLF_LEN,
					&new_buf.len
				);
			}

			/* Copy the rest of the header fields(siblings)
							if they exist */
			struct hdr_field* temp = hdr_mask[i]->sibling,
								*hdr_field;
			while (temp) {
				/* Put ', ' delimiter before header body*/
				wrap_copy_and_update(&new_buf.s, ATTR_DELIM,
						ATTR_DELIM_LEN, &new_buf.len);

				/* Append the header content */
				wrap_copy_and_update(&new_buf.s, temp->body.s,
						temp->body.len, &new_buf.len);

				hdr_field = temp->sibling;
				clean_hdr_field(temp);
				temp = hdr_field;
			}

			/* Copy CRLF to the end of the header */
			wrap_copy_and_update(&new_buf.s, CRLF, CRLF_LEN,
								&new_buf.len);

			if (hdr_mask[i]->next) {
				/* If more other headers, put all of them in
					the new buffer and free every allocated
					member */
				temp = hdr_mask[i];
				hdr_mask[i] = hdr_mask[i]->next;
				clean_hdr_field(temp);

				goto again;
			} else {
				/* if it is not an OTHER_HDR or it is the last
					one in OTHER_HDR list */
				pkg_free(hdr_mask[i]);
				hdr_mask[i] = 0;
			}
		}

		if (i == HDR_OTHER_T)
			break;
	}
	/* Copy the body of the message */
	frg = frg_head;
	while (frg) {
		temp = frg;
		wrap_copy_and_update( &new_buf.s, buf + frg->begin,
					frg->end-frg->begin+1, &new_buf.len);
		frg = frg->next;
		pkg_free(temp);
	}

	switch (type) {
		case TM_CB:
			*buf_p = shm_malloc(new_buf.len);
			if (*buf_p == NULL) {
				LM_ERR("no more sh mem\n");
				goto free_mem;
			}
			break;
		case PROCESSING_CB:
			*buf_p = pkg_malloc(new_buf.len);
			if (*buf_p == NULL) {
				LM_ERR("no more pkg mem\n");
				goto free_mem;
			}
			break;
		default:
			LM_ERR("invalid type\n");
			goto free_mem;
	}

	memcpy(*buf_p, new_buf.s, new_buf.len);
	*olen = new_buf.len;

	/* Free the vector */
	pkg_free(hdr_mask);

	/* Free the whitelist if pvs */
	if (wh_param && wh_param->type == WH_TYPE_PVS)
		free_whitelist(&wh_list);

	return 0;
memerr:
	LM_ERR("No more pkg mem\n");
free_mem:
	free_hdr_mask(hdr_mask);
	free_whitelist(&wh_list);
	return -1;
}
Exemple #3
0
/* Continues the SIP request processing previously saved by
 * t_suspend(). The script does not continue from the same
 * point, but a separate route block is executed instead.
 *
 * Return value:
 * 	0  - success
 * 	<0 - failure
 */
int t_continue(unsigned int hash_index, unsigned int label,
		struct action *route)
{
	struct cell	*t;
	struct sip_msg	faked_req;
	struct cancel_info cancel_data;
	int	branch;
	struct ua_client *uac =NULL;
	int	ret;
	int cb_type;
	int msg_status;
	int last_uac_status;
	int reply_status;
	int do_put_on_wait;
	struct hdr_field *hdr, *prev = 0, *tmp = 0;

	if (t_lookup_ident(&t, hash_index, label) < 0) {
		LM_ERR("transaction not found\n");
		return -1;
	}

	if (!(t->flags & T_ASYNC_SUSPENDED)) {
		LM_WARN("transaction is not suspended [%u:%u]\n", hash_index, label);
		return -2;
	}

	if (t->flags & T_CANCELED) {
		t->flags &= ~T_ASYNC_SUSPENDED;
		/* The transaction has already been canceled,
		 * needless to continue */
		UNREF(t); /* t_unref would kill the transaction */
		/* reset T as we have no working T anymore */
		set_t(T_UNDEFINED, T_BR_UNDEFINED);
		return 1;
	}

	/* The transaction has to be locked to protect it
	 * form calling t_continue() multiple times simultaneously */
	LOCK_ASYNC_CONTINUE(t);

	t->flags |= T_ASYNC_CONTINUE;   /* we can now know anywhere in kamailio
					 * that we are executing post a suspend */

	/* which route block type were we in when we were suspended */
	cb_type =  FAILURE_CB_TYPE;;
	switch (t->async_backup.backup_route) {
		case REQUEST_ROUTE:
			cb_type = FAILURE_CB_TYPE;
			break;
		case FAILURE_ROUTE:
			cb_type = FAILURE_CB_TYPE;
			break;
		case TM_ONREPLY_ROUTE:
			cb_type = ONREPLY_CB_TYPE;
			break;
		case BRANCH_ROUTE:
			cb_type = FAILURE_CB_TYPE;
			break;
	}

	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
		branch = t->async_backup.blind_uac;	/* get the branch of the blind UAC setup 
			* during suspend */
		if (branch >= 0) {
			stop_rb_timers(&t->uac[branch].request);
 
			if (t->uac[branch].last_received != 0) {
				/* Either t_continue() has already been
				* called or the branch has already timed out.
				* Needless to continue. */
				t->flags &= ~T_ASYNC_SUSPENDED;
				UNLOCK_ASYNC_CONTINUE(t);
				UNREF(t); /* t_unref would kill the transaction */
				return 1;
			}

			/* Set last_received to something >= 200,
			 * the actual value does not matter, the branch
			 * will never be picked up for response forwarding.
			 * If last_received is lower than 200,
			 * then the branch may tried to be cancelled later,
			 * for example when t_reply() is called from
			 * a failure route => deadlock, because both
			 * of them need the reply lock to be held. */
			t->uac[branch].last_received=500;
			uac = &t->uac[branch];
		}
		/* else
			Not a huge problem, fr timer will fire, but CANCEL
			will not be sent. last_received will be set to 408. */

		/* We should not reset kr here to 0 as it's quite possible before continuing the dev. has correctly set the
		 * kr by, for example, sending a transactional reply in code - resetting here will cause a dirty log message
		 * "WARNING: script writer didn't release transaction" to appear in log files. TODO: maybe we need to add 
		 * a special kr for async?
		 * reset_kr();
		 */

		/* fake the request and the environment, like in failure_route */
		if (!fake_req(&faked_req, t->uas.request, 0 /* extra flags */, uac)) {
			LM_ERR("building fake_req failed\n");
			ret = -1;
			goto kill_trans;
		}
		faked_env( t, &faked_req, 1);

		/* execute the pre/post -script callbacks based on original route block */
		if (exec_pre_script_cb(&faked_req, cb_type)>0) {
			if (run_top_route(route, &faked_req, 0)<0)
				LM_ERR("failure inside run_top_route\n");
			exec_post_script_cb(&faked_req, cb_type);
		}

		/* TODO: save_msg_lumps should clone the lumps to shm mem */

		/* restore original environment and free the fake msg */
		faked_env( t, 0, 1);
		free_faked_req(&faked_req, t);

		/* update the flags */
		t->uas.request->flags = faked_req.flags;

		if (t->uas.status < 200) {
			/* No final reply has been sent yet.
			* Check whether or not there is any pending branch.
			*/
			for (	branch = 0;
				branch < t->nr_of_outgoings;
				branch++
			) {
				if (t->uac[branch].last_received < 200)
					break;
			}

			if (branch == t->nr_of_outgoings) {
			/* There is not any open branch so there is
			* no chance that a final response will be received. */
				ret = 0;
				goto kill_trans;
			}
		}

	} else {
		branch = t->async_backup.backup_branch;

		init_cancel_info(&cancel_data);

		LM_DBG("continuing from a suspended reply"
				" - resetting the suspend branch flag\n");

		if (t->uac[branch].reply) {
		t->uac[branch].reply->msg_flags &= ~FL_RPL_SUSPENDED;
                } else {
			LM_WARN("no reply in t_continue for branch. not much we can do\n");
			return 0;
		}
                
		if (t->uas.request) t->uas.request->msg_flags&= ~FL_RPL_SUSPENDED;

		faked_env( t, t->uac[branch].reply, 1);

		if (exec_pre_script_cb(t->uac[branch].reply, cb_type)>0) {
			if (run_top_route(route, t->uac[branch].reply, 0)<0){
				LOG(L_ERR, "ERROR: t_continue_reply: Error in run_top_route\n");
			}
			exec_post_script_cb(t->uac[branch].reply, cb_type);
		}

		LM_DBG("restoring previous environment");
		faked_env( t, 0, 1);

		/*lock transaction replies - will be unlocked when reply is relayed*/
		LOCK_REPLIES( t );
		if ( is_local(t) ) {
			LM_DBG("t is local - sending reply with status code: [%d]\n",
					t->uac[branch].reply->first_line.u.reply.statuscode);
			reply_status = local_reply( t, t->uac[branch].reply, branch,
					t->uac[branch].reply->first_line.u.reply.statuscode,
					&cancel_data );
			if (reply_status == RPS_COMPLETED) {
				/* no more UAC FR/RETR (if I received a 2xx, there may
				* be still pending branches ...
				*/
				cleanup_uac_timers( t );
				if (is_invite(t)) cancel_uacs(t, &cancel_data, F_CANCEL_B_KILL);
				/* There is no need to call set_final_timer because we know
				* that the transaction is local */
				put_on_wait(t);
			}else if (unlikely(cancel_data.cancel_bitmap)){
				/* cancel everything, even non-INVITEs (e.g in case of 6xx), use
				* cancel_b_method for canceling unreplied branches */
				cancel_uacs(t, &cancel_data, cfg_get(tm,tm_cfg, cancel_b_flags));
			}

		} else {
			LM_DBG("t is not local - relaying reply with status code: [%d]\n",
					t->uac[branch].reply->first_line.u.reply.statuscode);
			do_put_on_wait = 0;
			if(t->uac[branch].reply->first_line.u.reply.statuscode>=200){
				do_put_on_wait = 1;
			}
			reply_status=relay_reply( t, t->uac[branch].reply, branch,
					t->uac[branch].reply->first_line.u.reply.statuscode,
					&cancel_data, do_put_on_wait );
			if (reply_status == RPS_COMPLETED) {
				/* no more UAC FR/RETR (if I received a 2xx, there may
				be still pending branches ...
				*/
				cleanup_uac_timers( t );
				/* 2xx is a special case: we can have a COMPLETED request
				* with branches still open => we have to cancel them */
				if (is_invite(t) && cancel_data.cancel_bitmap) 
					cancel_uacs( t, &cancel_data,  F_CANCEL_B_KILL);
				/* FR for negative INVITES, WAIT anything else */
				/* Call to set_final_timer is embedded in relay_reply to avoid
				* race conditions when reply is sent out and an ACK to stop
				* retransmissions comes before retransmission timer is set.*/
			}else if (unlikely(cancel_data.cancel_bitmap)){
				/* cancel everything, even non-INVITEs (e.g in case of 6xx), use
				* cancel_b_method for canceling unreplied branches */
				cancel_uacs(t, &cancel_data, cfg_get(tm,tm_cfg, cancel_b_flags));
			}

		}
		t->uac[branch].request.flags|=F_RB_REPLIED;

		if (reply_status==RPS_ERROR){
			goto done;
		}

		/* update FR/RETR timers on provisional replies */

		msg_status=t->uac[branch].reply->REPLY_STATUS;
		last_uac_status=t->uac[branch].last_received;

		if (is_invite(t) && msg_status<200 &&
			( cfg_get(tm, tm_cfg, restart_fr_on_each_reply) ||
			( (last_uac_status<msg_status) &&
			((msg_status>=180) || (last_uac_status==0)) )
		) ) { /* provisional now */
			restart_rb_fr(& t->uac[branch].request, t->fr_inv_timeout);
			t->uac[branch].request.flags|=F_RB_FR_INV; /* mark fr_inv */
		}
            
	}

done:
	UNLOCK_ASYNC_CONTINUE(t);

	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
		/* unref the transaction */
		t_unref(t->uas.request);
	} else {
		tm_ctx_set_branch_index(T_BR_UNDEFINED);        
		/* unref the transaction */
		t_unref(t->uac[branch].reply);
		LOG(L_DBG,"DEBUG: t_continue_reply: Freeing earlier cloned reply\n");

		/* free lumps that were added during reply processing */
		del_nonshm_lump( &(t->uac[branch].reply->add_rm) );
		del_nonshm_lump( &(t->uac[branch].reply->body_lumps) );
		del_nonshm_lump_rpl( &(t->uac[branch].reply->reply_lump) );

		/* free header's parsed structures that were added */
		for( hdr=t->uac[branch].reply->headers ; hdr ; hdr=hdr->next ) {
			if ( hdr->parsed && hdr_allocs_parse(hdr) &&
				(hdr->parsed<(void*)t->uac[branch].reply ||
				hdr->parsed>=(void*)t->uac[branch].end_reply)) {
				clean_hdr_field(hdr);
				hdr->parsed = 0;
			}
		}

		/* now go through hdr_fields themselves and remove the pkg allocated space */
		hdr = t->uac[branch].reply->headers;
		while (hdr) {
			if ( hdr && ((void*)hdr<(void*)t->uac[branch].reply ||
				(void*)hdr>=(void*)t->uac[branch].end_reply)) {
				//this header needs to be freed and removed form the list.
				if (!prev) {
					t->uac[branch].reply->headers = hdr->next;
				} else {
					prev->next = hdr->next;
				}
				tmp = hdr;
				hdr = hdr->next;
				pkg_free(tmp);
			} else {
				prev = hdr;
				hdr = hdr->next;
			}
		}
		sip_msg_free(t->uac[branch].reply);
		t->uac[branch].reply = 0;
	}

	/*This transaction is no longer suspended so unsetting the SUSPEND flag*/
	t->flags &= ~T_ASYNC_SUSPENDED;


	return 0;

kill_trans:
	t->flags &= ~T_ASYNC_SUSPENDED;
	/* The script has hopefully set the error code. If not,
	 * let us reply with a default error. */
	if ((kill_transaction_unsafe(t,
		tm_error ? tm_error : E_UNSPEC)) <=0
	) {
		LOG(L_ERR, "ERROR: t_continue: "
			"reply generation failed\n");
		/* The transaction must be explicitely released,
		 * no more timer is running */
		UNLOCK_ASYNC_CONTINUE(t);
		t_release_transaction(t);
	} else {
		UNLOCK_ASYNC_CONTINUE(t);
	}

	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
		t_unref(t->uas.request);
	} else {
		/* unref the transaction */
		t_unref(t->uac[branch].reply);
	}
	return ret;
}
Exemple #4
0
/* initiate a report if we previously enabled accounting for this t */
static inline void acc_onreply( struct cell* t, struct sip_msg *req,
											struct sip_msg *reply, int code)
{
	str new_uri_bk;
	int br = -1;
	hdr_field_t *hdr;
	sip_msg_t tmsg;
	sip_msg_t *preq;

	/* acc_onreply is bound to TMCB_REPLY which may be called
	   from _reply, like when FR hits; we should not miss this
	   event for missed calls either */
	if (is_invite(t) && code>=300 && is_mc_on(req) )
		on_missed(t, req, reply, code);

	if (!should_acc_reply(req, reply, code))
		return;

	if(_acc_clone_msg==1) {
		memcpy(&tmsg, req, sizeof(sip_msg_t));
		preq = &tmsg;
	} else {
		preq = req;
	}

	/* get winning branch index, if set */
	if (t->relayed_reply_branch>=0) {
		br = t->relayed_reply_branch;
	} else {
		if(code>=300) {
			br = tmb.t_get_picked_branch();
		}
	}

	/* for reply processing, set as new_uri the one from selected branch */
	if (br>=0) {
		new_uri_bk = preq->new_uri;
		preq->new_uri = t->uac[br].uri;
		preq->parsed_uri_ok = 0;
	} else {
		new_uri_bk.len = -1;
		new_uri_bk.s = 0;
	}
	/* set env variables */
	env_set_to( get_rpl_to(t,reply) );
	env_set_code_status( code, reply);

	if ( is_log_acc_on(preq) ) {
		env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
		acc_log_request(preq);
	}
#ifdef SQL_ACC
	if (is_db_acc_on(preq)) {
		if(acc_db_set_table_name(preq, db_table_acc_data, &db_table_acc)<0) {
			LM_ERR("cannot set acc db table name\n");
		} else {
			acc_db_request(preq);
		}
	}
#endif
#ifdef RAD_ACC
	if (is_rad_acc_on(preq))
		acc_rad_request(preq);
#endif
/* DIAMETER */
#ifdef DIAM_ACC
	if (is_diam_acc_on(preq))
		acc_diam_request(preq);
#endif

	/* run extra acc engines */
	acc_run_engines(preq, 0, NULL);

	if (new_uri_bk.len>=0) {
		req->new_uri = new_uri_bk;
		req->parsed_uri_ok = 0;
	}

	/* free header's parsed structures that were added by resolving acc attributes */
	for( hdr=req->headers ; hdr ; hdr=hdr->next ) {
		if ( hdr->parsed && hdr_allocs_parse(hdr) &&
					(hdr->parsed<(void*)t->uas.request ||
					hdr->parsed>=(void*)t->uas.end_request)) {
			/* header parsed filed doesn't point inside uas.request memory
			 * chunck -> it was added by resolving acc attributes -> free it as pkg */
			DBG("removing hdr->parsed %d\n", hdr->type);
			clean_hdr_field(hdr);
			hdr->parsed = 0;
		}
	}
}
Exemple #5
0
/* initiate a report if we previously enabled accounting for this t */
static void acc_onreply(tm_cell_t *t, sip_msg_t *req, sip_msg_t *reply, int code)
{
	str new_uri_bk;
	int br = -1;
	hdr_field_t *hdr;
	sip_msg_t *cmsg = 0;
	int cmsg_len = 0;
	sip_msg_t *preq = 0;
	void *mstart;
	void *mend;

	/* acc_onreply is bound to TMCB_REPLY which may be called
	   from _reply, like when FR hits; we should not miss this
	   event for missed calls either */
	if (is_invite(t) && code>=300 && is_mc_on(req) )
		on_missed(t, req, reply, code);

	if (!should_acc_reply(req, reply, code))
		return;

	if(_acc_clone_msg==1) {
		/* make a clone so eventual new parsed headers in pkg are not visible
		 * to other processes -- other attributes should be already parsed,
		 * available in the req structure and propagated by cloning */
		cmsg = sip_msg_shm_clone(req, &cmsg_len, 1);
		if(cmsg==NULL) {
			LM_ERR("failed to clone the request - acc aborted\n");
			return;
		}
		mstart = cmsg;
		mend = ((char*)cmsg) + cmsg_len;
		preq = cmsg;
	} else {
		mstart = t->uas.request;
		mend = t->uas.end_request;
		preq = req;
	}

	/* get winning branch index, if set */
	if (t->relayed_reply_branch>=0) {
		br = t->relayed_reply_branch;
	} else {
		if(code>=300) {
			br = tmb.t_get_picked_branch();
		}
	}

	/* for reply processing, set as new_uri the one from selected branch */
	if (br>=0) {
		new_uri_bk = preq->new_uri;
		preq->new_uri = t->uac[br].uri;
		preq->parsed_uri_ok = 0;
	} else {
		new_uri_bk.len = -1;
		new_uri_bk.s = 0;
	}
	/* set env variables */
	env_set_to( get_rpl_to(t,reply) );
	env_set_code_status( code, reply);

	if ( is_log_acc_on(preq) ) {
		env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
		acc_log_request(preq);
	}
#ifdef SQL_ACC
	if (is_db_acc_on(preq)) {
		if(acc_db_set_table_name(preq, db_table_acc_data, &db_table_acc)<0) {
			LM_ERR("cannot set acc db table name\n");
		} else {
			acc_db_request(preq);
		}
	}
#endif

/* DIAMETER */
#ifdef DIAM_ACC
	if (is_diam_acc_on(preq))
		acc_diam_request(preq);
#endif

	/* run extra acc engines */
	acc_run_engines(preq, 0, NULL);

	if (new_uri_bk.len>=0) {
		preq->new_uri = new_uri_bk;
		preq->parsed_uri_ok = 0;
	}

	/* free header's parsed structures that were added by resolving acc attributes */
	for( hdr=preq->headers ; hdr ; hdr=hdr->next ) {
		if (hdr->parsed && hdr_allocs_parse(hdr) &&
					(hdr->parsed<mstart || hdr->parsed>=mend)) {
			/* header parsed filed doesn't point inside cloned request memory
			 * chunck -> it was added by resolving acc attributes -> free it as pkg */
			DBG("removing hdr->parsed %d\n", hdr->type);
			clean_hdr_field(hdr);
			hdr->parsed = 0;
		}
	}
	if(cmsg!=NULL) {
		shm_free(cmsg);
	}
}