示例#1
0
文件: domain.c 项目: 4N7HR4X/kamailio
/*
 * Check if host in Request URI is local
 */
int is_uri_host_local(struct sip_msg* _msg, char* _s1, char* _s2)
{
    str branch;
    qvalue_t q;
    struct sip_uri puri;
    struct attr_list *attrs;
    str did;

    if ( is_route_type(REQUEST_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE) ) {
	if (parse_sip_msg_uri(_msg) < 0) {
	    LM_ERR("error while parsing R-URI\n");
	    return -1;
	}
	return hash_table_lookup(&(_msg->parsed_uri.host), &did, &attrs);
    } else if (is_route_type(FAILURE_ROUTE)) {
	branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0, 0, 0, 0);
	if (branch.s) {
	    if (parse_uri(branch.s, branch.len, &puri) < 0) {
		LM_ERR("error while parsing branch URI\n");
		return -1;
	    }
	    return hash_table_lookup(&(puri.host), &did, &attrs);
	} else {
	    LM_ERR("branch is missing, error in script\n");
	    return -1;
	}
    } else {
	LM_ERR("unsupported route type\n");
	return -1;
    }
}
示例#2
0
/*!
 * \brief Check if host in Request URI has DP-DDDS NAPTRs and if we can connect to them
 * \param _msg SIP message
 * \param _s1 unused
 * \param _s2 unused
 * \return negative on failure, positive on success
 */
int dp_can_connect(struct sip_msg* _msg, char* _s1, char* _s2) {

	static char domainname[MAX_DOMAIN_SIZE];
	str domain;
	int ret;

	if (!is_route_type(REQUEST_ROUTE)) {
		LM_ERR("unsupported route type\n");
		return -1;
	}

	if (parse_sip_msg_uri(_msg) < 0) {
		LM_ERR("failed to parse R-URI\n");
		return -1;
	}

	if (_msg->parsed_uri.host.len >= MAX_DOMAIN_SIZE) {
		LM_ERR("domain buffer to small\n");
		return -1;
	}

	/* copy domain into static buffer as later we sometimes need \0
	 * terminated strings
	 */
	domain.s = (char *) &(domainname[0]);
	domain.len = _msg->parsed_uri.host.len;
	memcpy(domain.s, _msg->parsed_uri.host.s, domain.len);
	domainname[domain.len] = '\0';

	LM_DBG("domain is %.*s.\n", domain.len, ZSW(domain.s));

	ret = dp_can_connect_str(&domain,0);
	LM_DBG("returning %d.\n", ret);
	return(ret);
}
示例#3
0
/*!
 * \brief Unset a dialog profile
 * \param msg SIP message
 * \param value value
 * \param profile dialog profile table
 * \return 1 on success, -1 on failure
 */
int unset_dlg_profile(sip_msg_t *msg, str *value,
		dlg_profile_table_t *profile)
{
	dlg_cell_t *dlg;
	dlg_profile_link_t *linker;
	dlg_profile_link_t *linker_prev;
	dlg_entry_t *d_entry;

	if (is_route_type(REQUEST_ROUTE)) {
		LM_ERR("dialog delete profile cannot be used in request route\n");
		return -1;
	}

	/* get current dialog */
	dlg = dlg_get_msg_dialog(msg);

	if (dlg==NULL) {
		LM_WARN("dialog is NULL for delete profile\n");
		return -1;
	}

	/* check the dialog linkers */
	d_entry = &d_table->entries[dlg->h_entry];
	dlg_lock( d_table, d_entry);
	linker = dlg->profile_links;
	linker_prev = NULL;
	for( ; linker ; linker_prev=linker,linker=linker->next) {
		if (linker->profile==profile) {
			if (profile->has_value==0) {
				goto found;
			} else if (value && value->len==linker->hash_linker.value.len &&
			memcmp(value->s,linker->hash_linker.value.s,value->len)==0){
				goto found;
			}
			/* allow further search - maybe the dialog is inserted twice in
			 * the same profile, but with different values -bogdan
			 */
		}
	}
	atomic_or_int((volatile int*)&dlg->dflags, DLG_FLAG_CHANGED_PROF);
	dlg_unlock( d_table, d_entry);
	dlg_release(dlg);
	return -1;

found:
	/* table still locked */
	/* remove the linker element from dialog */
	if (linker_prev==NULL) {
		dlg->profile_links = linker->next;
	} else {
		linker_prev->next = linker->next;
	}
	linker->next = NULL;
	dlg_unlock( d_table, d_entry);
	/* remove linker from profile table and free it */
	destroy_linkers(linker);
	dlg_release(dlg);
	return 1;
}
示例#4
0
文件: pvapi.c 项目: btriller/kamailio
int pv_set_spec_value(struct sip_msg* msg, pv_spec_p sp, int op,
		pv_value_t *value)
{
	if(sp==NULL || !pv_is_w(sp))
		return 0; /* no op */
	if(pv_alter_context(sp) && is_route_type(LOCAL_ROUTE))
		return 0; /* no op */
	return sp->setf(msg, &sp->pvp, op, value);
}
示例#5
0
文件: isc.c 项目: 4N7HR4X/kamailio
/**
 *	Forwards the message to the application server.
 * - Marks the message
 * - fills routes
 * - replaces dst_uri
 * @param msg - the SIP message
 * @param m  - the isc_match that matched with info about where to forward it 
 * @param mark  - the isc_mark that should be used to mark the message
 * @returns #ISC_RETURN_TRUE if OK, #ISC_RETURN_ERROR if not
 */
int isc_forward(struct sip_msg *msg, isc_match *m, isc_mark *mark) {
	struct cell *t;
	unsigned int hash, label;
	ticks_t fr_timeout, fr_inv_timeout;
	LM_DBG("marking for AS <%.*s>\n", m->server_name.len, m->server_name.s);

	isc_mark_set(msg, m, mark);
	/* change destination so it forwards to the app server */
	if (msg->dst_uri.s)
		pkg_free(msg->dst_uri.s);
	msg->dst_uri.s = pkg_malloc(m->server_name.len);
	if (!msg->dst_uri.s) {
		LM_ERR("error allocating %d bytes\n", m->server_name.len);
		return ISC_RETURN_ERROR;
	}
	msg->dst_uri.len = m->server_name.len;
	memcpy(msg->dst_uri.s, m->server_name.s, m->server_name.len);

	/* append branch if last trigger failed */
	if (is_route_type(FAILURE_ROUTE))
		append_branch(msg, &(msg->first_line.u.request.uri), &(msg->dst_uri), 0, Q_UNSPECIFIED, 0, 0, 0, 0, 0, 0);

	// Determines the tm transaction identifiers.
	// If no transaction, then creates one

	if (isc_tmb.t_get_trans_ident(msg, &hash, &label) < 0) {
		LM_DBG("SIP message without transaction. OK - first request\n");
		if (isc_tmb.t_newtran(msg) < 0)
			LM_INFO("Failed creating SIP transaction\n");
		if (isc_tmb.t_get_trans_ident(msg, &hash, &label) < 0) {
			LM_INFO("SIP message still without transaction\n");
		} else {
			LM_DBG("New SIP message transaction %u %u\n", hash, label);
		}
	} else {
		LM_INFO("Transaction %u %u exists. Retransmission?\n", hash, label);
	}

	/* set the timeout timers to a lower value */

	t = isc_tmb.t_gett();
	fr_timeout = t->fr_timeout;
	fr_inv_timeout = t->fr_inv_timeout;
	t->fr_timeout = S_TO_TICKS(isc_fr_timeout) / 1000;
	t->fr_inv_timeout = S_TO_TICKS(isc_fr_inv_timeout) / 1000;

	/* send it */
	isc_tmb.t_relay(msg, 0, 0);

	/* recover the timeouts */
	t->fr_timeout = fr_timeout;
	t->fr_inv_timeout = fr_inv_timeout;

	LM_INFO(">>       msg was fwded to AS\n");

	return ISC_RETURN_TRUE;
}
示例#6
0
static int dp_update(struct sip_msg * msg, pv_spec_t * src, pv_spec_t * dest,
		str * repl, str * attrs)
{
	int no_change;
	pv_value_t val;

	memset(&val, 0, sizeof(pv_value_t));
	val.flags = PV_VAL_STR;

	no_change = (dest==NULL) || (dest->type == PVT_NONE) || (!repl->s) || (!repl->len);

	if (no_change)
		goto set_attr_pvar;

	val.rs = *repl;

	if(dest->setf(msg, &dest->pvp, (int)EQ_T, &val)<0)
	{
		LM_ERR("setting dst pseudo-variable failed\n");
		return -1;
	}

	if(is_route_type(FAILURE_ROUTE)
			&& (dest->type==PVT_RURI || dest->type==PVT_RURI_USERNAME)) {
	    if (append_branch(msg, 0, 0, 0, Q_UNSPECIFIED, 0, 0, 0, 0, 0, 0) != 1) {
			LM_ERR("append_branch action failed\n");
			return -1;
		}
	}

set_attr_pvar:

	if(!attr_pvar)
		return 0;

	val.rs = *attrs;
	if(attr_pvar->setf(msg, &attr_pvar->pvp, (int)EQ_T, &val)<0)
	{
		LM_ERR("setting attr pseudo-variable failed\n");
		return -1;
	}

	return 0;
}
示例#7
0
/*!
 * \brief Set a dialog profile
 * \param msg SIP message
 * \param value value
 * \param profile dialog profile table
 * \return 0 on success, -1 on failure
 */
int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *profile)
{
	dlg_cell_t *dlg = NULL;
	dlg_profile_link_t *linker;

	/* get current dialog */
	dlg = dlg_get_msg_dialog(msg);

	if (dlg==NULL && !is_route_type(REQUEST_ROUTE)) {
		LM_CRIT("BUG - dialog not found in a non REQUEST route (%d)\n",
			REQUEST_ROUTE);
		return -1;
	}

	/* build new linker */
	linker = (struct dlg_profile_link*)shm_malloc(
		sizeof(struct dlg_profile_link) + (profile->has_value?value->len:0) );
	if (linker==NULL) {
		LM_ERR("no more shm memory\n");
		goto error;
	}
	memset(linker, 0, sizeof(struct dlg_profile_link));

	/* set backpointers to profile and linker (itself) */
	linker->profile = profile;
	linker->hash_linker.linker = linker;

	/* set the value */
	if (profile->has_value) {
		linker->hash_linker.value.s = (char*)(linker+1);
		memcpy( linker->hash_linker.value.s, value->s, value->len);
		linker->hash_linker.value.len = value->len;
	}
	sruid_next_safe(&_dlg_profile_sruid);
	strcpy(linker->hash_linker.puid, _dlg_profile_sruid.uid.s);
	linker->hash_linker.puid_len = _dlg_profile_sruid.uid.len;

	if (dlg!=NULL) {
		/* add linker directly to the dialog and profile */
		link_dlg_profile( linker, dlg);
	} else {
		/* if existing linkers are not from current request, just discard them */
		if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
			current_dlg_msg_id = msg->id;
			current_dlg_msg_pid = msg->pid;
			destroy_linkers(current_pending_linkers);
			current_pending_linkers = NULL;
		}
		/* no dialog yet -> set linker as pending */
		if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
			current_dlg_msg_id = msg->id;
			current_dlg_msg_pid = msg->pid;
			destroy_linkers(current_pending_linkers);
		}

		linker->next = current_pending_linkers;
		current_pending_linkers = linker;
	}

	dlg_release(dlg);
	return 0;
error:
	dlg_release(dlg);
	return -1;
}
示例#8
0
/**
 * writes the uri dest using the flags and rule list of rf_head
 *
 * @param rf_head the head of the route flags list
 * @param flags user defined flags
 * @param dest the returned new destination URI
 * @param msg the sip message
 * @param user the localpart of the uri to be rewritten
 * @param hash_source the SIP header used for hashing
 * @param alg the algorithm used for hashing
 * @param descavp the name of the AVP where the description is stored
 *
 * @return 0 on success, -1 on failure, 1 on empty rule list
 */
static int rewrite_on_rule(struct route_flags *rf_head, flag_t flags, str * dest,
		struct sip_msg * msg, const str * user, const enum hash_source hash_source,
		const enum hash_algorithm alg, gparam_t *descavp) {
	struct route_flags * rf;
	struct route_rule * rr;
	int prob;

	assert(rf_head != NULL);

	LM_DBG("searching for matching routing rules");
	for (rf = rf_head; rf != NULL; rf = rf->next) {
		/* LM_DBG("actual flags %i, searched flags %i, mask %i and match %i", rf->flags, flags, rf->mask, flags&rf->mask); */
		if ((flags&rf->mask) == rf->flags) break;
	}

	if (rf==NULL) {
		LM_INFO("did not find a match for flags %d\n", flags);
		return -1;
	}

	if (rf->rule_list == NULL) {
		LM_INFO("empty rule list\n");
		return 1;
	}

	switch (alg) {
		case alg_crc32:
		{
			static avp_value_t used_dests[MAX_DESTINATIONS];
			static int no_dests = 0;
			avp_value_t cr_new_uri;

			if(rf->dice_max == 0) {
				LM_ERR("invalid dice_max value\n");
				return -1;
			}
			if ((prob = hash_func(msg, hash_source, rf->dice_max)) < 0) {
				LM_ERR("could not hash message with CRC32");
				return -1;
			}

			/* This auto-magically takes the last rule if anything is broken.
			 * Sometimes the hash result is zero. If the first rule is off
			 * (has a probablility of zero) then it has also a dice_to of
			 * zero and the message could not be routed at all if we use
			 * '<' here. Thus the '<=' is necessary.
			 *
			 * cr_uri_already_used is a function that checks that the selected
			 * rule has not been previously used as a failed destinatin
			 */

			for (rr = rf->rule_list;
				rr->next!= NULL && rr->dice_to <= prob ; rr = rr->next) {}

			//LM_DBG("CR: candidate hashed destination is: <%.*s>\n", rr->host.len, rr->host.s);
			if (cr_avoid_failed_dests) {
				if (is_route_type(FAILURE_ROUTE) && (mode == CARRIERROUTE_MODE_DB) ){
					build_used_uris_list(used_dests, &no_dests);

					if (cr_uri_already_used(rr->host, used_dests, no_dests) ) {
						//LM_DBG("CR: selecting new destination !!! \n");
						for (rr = rf->rule_list;
									rr!= NULL && cr_uri_already_used(rr->host, used_dests, no_dests); rr = rr->next) {}
						/* are there any destinations that were not already used? */
						if (rr == NULL) {
							LM_NOTICE("All gateways from this group were already used\n");
							return -1;
						}

						/* this is a hack: we do not take probabilities into consideration if first destination
						 * was previously tried */

						do {
							int rule_no = kam_rand() % rf->rule_num;
							//LM_DBG("CR: trying rule_no=%d \n", rule_no);
							for (rr = rf->rule_list; (rule_no > 0) && (rr->next!=NULL) ; rule_no-- , rr = rr->next) {}
						} while (cr_uri_already_used(rr->host, used_dests, no_dests));
						LM_DBG("CR: candidate selected destination is: <%.*s>\n", rr->host.len, rr->host.s);
					}
				}
			}
			/*This should be regarded as an ELSE branch for the if above
			 * ( status exists for mode == CARRIERROUTE_MODE_FILE */
			if (!rr->status) {
				if (!rr->backup) {
					LM_ERR("all routes are off\n");
					return -1;
				} else {
					if (!rr->backup->rr) {
						LM_ERR("all routes are off\n");
						return -1;
					}
					rr = rr->backup->rr;
				}
			}

			if (cr_avoid_failed_dests) {
				//LM_DBG("CR: destination is: <%.*s>\n", rr->host.len, rr->host.s);
				cr_new_uri.s = rr->host;
				/* insert used destination into avp, in case corresponding request fails and
				 * another destination has to be used; this new destination must not be one
				 * that failed before
				 */

				if (mode == CARRIERROUTE_MODE_DB){
					if ( add_avp( AVP_VAL_STR | AVP_NAME_STR, cr_uris_avp, cr_new_uri) < 0){
						LM_ERR("set AVP failed\n");
						return -1;
					}
					//print_cr_uri_avp();
				}
			}
			break;
		}
		case alg_crc32_nofallback:
			if ((prob = (hash_func(msg, hash_source, rf->max_targets))) < 0) {
				LM_ERR("could not hash message with CRC32");
				return -1;
			}
			/* Instead of search the whole rule_list if there is something broken
			 * this function just tries only a backup rule and otherwise
			 * returns -1. This way we get an error
			 */
			if ((rr = get_rule_by_hash(rf, prob + 1)) == NULL) {
				LM_CRIT("no route found\n");
				return -1;
			}
			break;
		default:
			LM_ERR("invalid hash algorithm\n");
			return -1;
	}
	return actually_rewrite(rr, dest, msg, user, descavp);
}
示例#9
0
/*!
 * \brief Apply DP-DDDS policy to current SIP message
 *
 * Apply DP-DDDS policy to current SIP message. This means
 * build a new destination URI from the policy AVP and export it
 * as AVP. Then in kamailio.cfg this new target AVP can be pushed
 * into the destination URI $duri
 * \param _msg SIP message
 * \param _s1 unused
 * \param _s2 unused
 * \return negative on failure, positive on succes
 */
int dp_apply_policy(struct sip_msg* _msg, char* _s1, char* _s2) {

	str *domain;
	int_str val;
	struct usr_avp *avp;

	char duri[MAX_URI_SIZE];
	str duri_str;
	int len, didsomething;
	char *at; /* pointer to current location inside duri */

	str host;
	int port, proto;
	struct socket_info* si;

	if (!is_route_type(REQUEST_ROUTE)) {
		LM_ERR("unsupported route type\n");
		return -1;
	}

	/*
	 * set the send_socket
	 */

	/* search for send_socket AVP */
	avp = search_first_avp(send_socket_avp_name_str, send_socket_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string send_socket_avp, "
					"return with error ...\n");
			return -1;
		}
		LM_DBG("send_socket_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
		/* parse phostport - AVP str val is asciiz */
		/* FIXME: This code relies on the fact that the string value of an AVP
		 * is zero terminated, which may or may not be true in the future */
		if (parse_phostport(val.s.s, &(host.s), &(host.len), &port, &proto)) {
			LM_ERR("could not parse send_socket, return with error ...\n");
			return -1;
		}
		si = grep_sock_info( &host, (unsigned short) port, (unsigned short) proto);
		if (si) {
			set_force_socket(_msg, si);
		} else {
			LM_WARN("could not find socket for"
					"send_socket '%.*s'\n", val.s.len, ZSW(val.s.s));
		}
	} else {
		LM_DBG("send_socket_avp not found\n");
	}

	/*
	 * set the destination URI
	 */

	didsomething = 0; /* if no AVP is set, there is no need to set the DURI in the end */
	
	if (parse_sip_msg_uri(_msg) < 0) {
		LM_ERR("failed to parse R-URI\n");
		return -1;
	}

	at = (char *)&(duri[0]);
	len = 0;
	if ( (len + 4) >  MAX_URI_SIZE) {
		LM_ERR("duri buffer to small to add uri schema\n");
		return -1;
	}
	memcpy(at, "sip:", 4); at = at + 4; len = len + 4;

	domain = &(_msg->parsed_uri.host);
	LM_DBG("domain is %.*s.\n", domain->len, ZSW(domain->s));

	/* search for prefix and add it to duri buffer */
	avp = search_first_avp(domain_prefix_avp_name_str, domain_prefix_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string domain_prefix_avp, return with error ...\n");
			return -1;
		}
		LM_DBG("domain_prefix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
		if ( (len + val.s.len +1) >  MAX_URI_SIZE) {
			LM_ERR("duri buffer to small to add domain prefix\n");
			return -1;
		}
		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
		*at = '.'; at = at + 1;	/* add . as delimiter between prefix and domain */
		didsomething = 1;
	} else {
		LM_DBG("domain_prefix_avp not found\n");
	}


	/* add domain to duri buffer */
	avp = search_first_avp(domain_replacement_avp_name_str, domain_replacement_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string domain_replacement_avp, return with"
					"error ...\n");
			return -1;
		}
		LM_DBG("domain_replacement_avp found='%.*s'\n",val.s.len, ZSW(val.s.s));
		if ( (len + val.s.len +1) >  MAX_URI_SIZE) {
			LM_ERR("duri buffer to small to add domain replacement\n");
			return -1;
		}
		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
		didsomething = 1;
	} else {
	    LM_DBG("domain_replacement_avp not found, using original domain '"
				"%.*s'\n",domain->len, domain->s);
	    if ( (len + domain->len) >  MAX_URI_SIZE) {
		LM_ERR("duri buffer to small to add domain\n");
		return -1;
	    }
	    memcpy(at, domain->s, domain->len); at = at + domain->len;
	}
	
	/* search for suffix and add it to duri buffer */
	avp = search_first_avp(domain_suffix_avp_name_str, domain_suffix_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string domain_suffix_avp,return with error .."
					"\n");
			return -1;
		}
		LM_DBG("domain_suffix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
		if ( (len + val.s.len + 1) >  MAX_URI_SIZE) {
			LM_ERR("duri buffer to small to add domain suffix\n");
			return -1;
		}
		*at = '.'; at = at + 1;	/* add . as delimiter between domain and suffix */
		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
		didsomething = 1;
	} else {
		LM_DBG("domain_suffix_avp not found\n");
	}

	/* search for port override and add it to duri buffer */
	avp = search_first_avp(port_override_avp_name_str, port_override_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string port_override_avp, return with error ...\n");
			return -1;
		}
		LM_DBG("port_override_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
		/* We do not check if the port is valid */
		if ( (len + val.s.len + 1) >  MAX_URI_SIZE) {
			LM_ERR("duri buffer to small to add domain suffix\n");
			return -1;
		}
		*at = ':'; at = at + 1;	/* add : as delimiter between domain and port */
		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
		didsomething = 1;
	} else {
		LM_DBG("port_override_avp not found, using original port\n");
		if (_msg->parsed_uri.port.len) {
			LM_DBG("port found in RURI, reusing it for DURI\n");
			if ( (len + _msg->parsed_uri.port.len + 1) >  MAX_URI_SIZE) {
				LM_ERR("duri buffer to small to copy port\n");
				return -1;
			}
			*at = ':'; at = at + 1;	
			/* add : as delimiter between domain and port */
			memcpy(at, _msg->parsed_uri.port.s, _msg->parsed_uri.port.len); 
			at = at + _msg->parsed_uri.port.len;
		} else {
			LM_DBG("port not found in RURI, no need to copy it to DURI\n");
		}
	}

	/* search for transport override and add it to duri buffer */
	avp = search_first_avp(transport_override_avp_name_str, transport_override_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string transport_override_avp, "
					"return with error ...\n");
			return -1;
		}
		LM_DBG("transport_override_avp found='%.*s'\n",val.s.len, ZSW(val.s.s));

		if ( (len + val.s.len + 11) >  MAX_URI_SIZE) {
			LM_ERR("duri buffer to small to add transport override\n");
			return -1;
		}
		/* add : as transport parameter to duri; NOTE: no checks if transport parameter is valid  */
		memcpy(at, ";transport=", 11); at = at + 11;
		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
		didsomething = 1;
	} else {
		LM_DBG("transport_override_avp not found, using original transport\n");
		if (_msg->parsed_uri.transport.len) {
			LM_DBG("transport found in RURI, reusing it for DURI\n");
			if ( (len + _msg->parsed_uri.transport.len + 1) >  MAX_URI_SIZE) {
				LM_ERR("duri buffer to small to copy transport\n");
				return -1;
			}
			*at = ';'; at = at + 1; /* add : as delimiter between domain and port */
			memcpy(at, _msg->parsed_uri.transport.s, _msg->parsed_uri.transport.len); at = at + _msg->parsed_uri.transport.len;
		} else {
			LM_DBG("transport not found in RURI, no need to copy it to DURI\n");
		}
	}

	/* write new target DURI into DURI */
	if (didsomething == 0) {
		LM_DBG("no domainpolicy AVP set, no need to push new DURI\n");
		return 2;
	}
	duri_str.s = (char *)&(duri[0]);
	duri_str.len = at - duri_str.s;
	LM_DBG("new DURI is '%.*s'\n",duri_str.len, ZSW(duri_str.s));
	if(set_dst_uri(_msg, &duri_str)<0) {
		LM_ERR("failed to se dst uri\n");
		return -1;
	}
	/* dst_uri changes, so it makes sense to re-use the current uri for
		forking */
	ruri_mark_new(); /* re-use uri for serial forking */

	return 1;
}
示例#10
0
/**
 * Checks if there is a match.
 * Inserts route headers and set the dst_uri
 * @param msg - the message to check
 * @param str1 - the direction of the request orig/term
 * @param str2 - not used
 * @returns #ISC_RETURN_TRUE if found, #ISC_RETURN_FALSE if not, #ISC_RETURN_BREAK on error
 */
int ISC_match_filter(struct sip_msg *msg,char *str1,char *str2)
{
	int k = 0;
	isc_match *m = NULL;
	str s={0,0};
	int ret = ISC_RETURN_FALSE;
	isc_mark new_mark,old_mark;
	
	enum dialog_direction dir = get_dialog_direction(str1);
	
	LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Checking triggers\n",str1);
	
	if (dir==DLG_MOBILE_UNKNOWN) 
		return ISC_RETURN_BREAK;
	
	if (!isc_is_initial_request(msg)) return ISC_RETURN_FALSE;
		
	/* starting or resuming? */
	memset(&old_mark,0,sizeof(isc_mark));
	memset(&new_mark,0,sizeof(isc_mark));
	if (isc_mark_get_from_msg(msg,&old_mark)){		
		LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Message returned s=%d;h=%d;d=%d;a=%.*s\n",
			str1,old_mark.skip,old_mark.handling,old_mark.direction,old_mark.aor.len,old_mark.aor.s);
	}
	else {
		LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Starting triggering\n",str1);				
	}
	
	if (
#ifdef SER_MOD_INTERFACE
	is_route_type(FAILURE_ROUTE)
#else
	*isc_tmb.route_mode==MODE_ONFAILURE
#endif
		){
		LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): failure\n",str1);
		
		/* need to find the handling for the failed trigger */
		if (dir==DLG_MOBILE_ORIGINATING){
			k = isc_get_originating_user(msg,&old_mark,&s);
			if (k){
				k = isc_is_registered(&s);
				if (k==NOT_REGISTERED) {
					ret = ISC_MSG_NOT_FORWARDED;
					goto done;
				}
				new_mark.direction = IFC_ORIGINATING_SESSION;
				LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Orig User <%.*s> [%d]\n",str1,
					s.len,s.s,k);
			} else goto done;
		}
		if (dir==DLG_MOBILE_TERMINATING){
			k = isc_get_terminating_user(msg,&old_mark,&s);
			if (k){
				k = isc_is_registered(&s);
				//LOG(L_DBG,"after isc_is_registered in ISC_match_filter\n");
				if (k==REGISTERED) {
					new_mark.direction = IFC_TERMINATING_SESSION;
				} else {
					new_mark.direction = IFC_TERMINATING_UNREGISTERED;
				}
				LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Term User <%.*s> [%d]\n",str1,
					s.len,s.s,k);
			} else {
				goto done;
			}
		}
		struct cell * t = isc_tmb.t_gett();
		LOG(L_CRIT,"SKIP: %d\n",old_mark.skip);
		int index = old_mark.skip;
		for (k=0;k<t->nr_of_outgoings;k++) {
			m = isc_checker_find(s,new_mark.direction,index,msg,isc_is_registered(&s));
			if (m) {
				index = m->index;
				if (k < t->nr_of_outgoings - 1) isc_free_match(m);
			} else {
				LOG(L_ERR,"ERR:"M_NAME":ISC_match_filter(%s): On failure, previously matched trigger no longer matches?!\n", str1);
				ret = ISC_RETURN_BREAK;
				goto done;
			}
		}
		if (m->default_handling==IFC_SESSION_TERMINATED) {
			/* Terminate the session */
			DBG("DEBUG:"M_NAME":ISC_match_filter(%s): Terminating session.\n", str1);
			isc_tmb.t_reply(msg,IFC_AS_UNAVAILABLE_STATUS_CODE,
				"AS Contacting Failed - iFC terminated dialog");
			LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Responding with %d "
				"to URI: %.*s\n",str1, IFC_AS_UNAVAILABLE_STATUS_CODE,
				msg->first_line.u.request.uri.len,
				msg->first_line.u.request.uri.s);
			isc_free_match(m);
			ret = ISC_RETURN_BREAK;
			goto done;
		}
		
		/* skip the failed triggers (IFC_SESSION_CONTINUED) */
		old_mark.skip = index + 1;
		
		isc_free_match(m);
		isc_mark_drop_route(msg);
	}

	/* originating leg */
	if (dir==DLG_MOBILE_ORIGINATING){
		k = isc_get_originating_user(msg,&old_mark,&s);
		if (k){
			k = isc_is_registered(&s);
			if (k==NOT_REGISTERED) return ISC_MSG_NOT_FORWARDED;
			
			LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Orig User <%.*s> [%d]\n",str1,
				s.len,s.s,k);
			m = isc_checker_find(s,old_mark.direction,old_mark.skip,msg,isc_is_registered(&s));
			if (m){
				new_mark.direction = IFC_ORIGINATING_SESSION;
				new_mark.skip = m->index+1;
				new_mark.handling = m->default_handling;
				new_mark.aor = s;
				ret = isc_forward(msg,m,&new_mark);
				isc_free_match(m);
				goto done;
			}
		}
		goto done;
	}

	/* terminating leg */
	if (dir==DLG_MOBILE_TERMINATING){
		k = isc_get_terminating_user(msg,&old_mark,&s);
		if (k){
			k = isc_is_registered(&s);
			if (k==REGISTERED) {
				new_mark.direction = IFC_TERMINATING_SESSION;
			} else {
				new_mark.direction = IFC_TERMINATING_UNREGISTERED;
			}
			LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Term User <%.*s> [%d]\n",str1,
				s.len,s.s,k);
			
			m = isc_checker_find(s,new_mark.direction,old_mark.skip,msg,isc_is_registered(&s));
			if (m){
				new_mark.skip = m->index+1;
				new_mark.handling = m->default_handling;
				new_mark.aor = s;
				ret = isc_forward(msg,m,&new_mark);
				isc_free_match(m);
				goto done;
			}
		}
		goto done;
	}				
	
done:
	if (old_mark.aor.s) pkg_free(old_mark.aor.s);		
	return ret;
}
示例#11
0
文件: mod.c 项目: gbour/kamailio
/**
 * Checks if there is a match.
 * Inserts route headers and set the dst_uri
 * @param msg - the message to check
 * @param str1 - the direction of the request orig/term
 * @param str2 - not used
 * @returns #ISC_RETURN_TRUE if found, #ISC_RETURN_FALSE if not, #ISC_RETURN_BREAK on error
 */
int isc_match_filter(struct sip_msg *msg, char *str1, udomain_t* d) {
    int k = 0;
    isc_match *m = NULL;
    str s = {0, 0};

    //sometimes s is populated by an ims_getter method cscf_get_terminating_user that alloc memory that must be free-ed at the end
    int free_s = 0;


    int ret = ISC_RETURN_FALSE;
    isc_mark new_mark, old_mark;

    enum dialog_direction dir = get_dialog_direction(str1);

    LM_INFO("Checking triggers\n");

    if (dir == DLG_MOBILE_UNKNOWN)
        return ISC_RETURN_BREAK;

    if (!cscf_is_initial_request(msg))
        return ISC_RETURN_FALSE;

    /* starting or resuming? */
    memset(&old_mark, 0, sizeof (isc_mark));
    memset(&new_mark, 0, sizeof (isc_mark));
    if (isc_mark_get_from_msg(msg, &old_mark)) {
        LM_DBG("Message returned s=%d;h=%d;d=%d;a=%.*s\n", old_mark.skip, old_mark.handling, old_mark.direction, old_mark.aor.len, old_mark.aor.s);
    } else {
        LM_DBG("Starting triggering\n");
    }

    if (is_route_type(FAILURE_ROUTE)) {
        /* need to find the handling for the failed trigger */
        if (dir == DLG_MOBILE_ORIGINATING) {
            k = cscf_get_originating_user(msg, &s);
            if (k) {
                k = isc_is_registered(&s, d);
                if (k == IMPU_NOT_REGISTERED) {
                    ret = ISC_RETURN_FALSE;
                    goto done;
                }
                new_mark.direction = IFC_ORIGINATING_SESSION;
                LM_DBG("Orig User <%.*s> [%d]\n", s.len, s.s, k);
            } else
                goto done;
        }
        if (dir == DLG_MOBILE_TERMINATING) {
            k = cscf_get_terminating_user(msg, &s);
            //sometimes s is populated by an ims_getter method cscf_get_terminating_user that alloc memory that must be free-ed at the end
            free_s = 1;

            if (k) {
                k = isc_is_registered(&s, d);
                //LOG(L_DBG,"after isc_is_registered in ISC_match_filter\n");
                if (k == IMPU_REGISTERED) {
                    new_mark.direction = IFC_TERMINATING_SESSION;
                } else {
                    new_mark.direction = IFC_TERMINATING_UNREGISTERED;
                }
                LM_DBG("Term User <%.*s> [%d]\n", s.len, s.s, k);
            } else {
                goto done;
            }
        }
        struct cell * t = isc_tmb.t_gett();
        LM_CRIT("SKIP: %d\n", old_mark.skip);
        int index = old_mark.skip;
        for (k = 0; k < t->nr_of_outgoings; k++) {
            m = isc_checker_find(s, new_mark.direction, index, msg,
                    isc_is_registered(&s, d), d);
            if (m) {
                index = m->index;
                if (k < t->nr_of_outgoings - 1)
                    isc_free_match(m);
            } else {
                LM_ERR("On failure, previously matched trigger no longer matches?!\n");
                ret = ISC_RETURN_BREAK;
                goto done;
            }
        }
        if (m->default_handling == IFC_SESSION_TERMINATED) {
            /* Terminate the session */
            LM_DBG("Terminating session.\n");
            isc_tmb.t_reply(msg, IFC_AS_UNAVAILABLE_STATUS_CODE, "AS Contacting Failed - iFC terminated dialog");
            LM_DBG("Responding with %d to URI: %.*s\n",
                    IFC_AS_UNAVAILABLE_STATUS_CODE, msg->first_line.u.request.uri.len, msg->first_line.u.request.uri.s);
            isc_free_match(m);
            ret = ISC_RETURN_BREAK;
            goto done;
        }
        /* skip the failed triggers (IFC_SESSION_CONTINUED) */
        old_mark.skip = index + 1;

        isc_free_match(m);
        isc_mark_drop_route(msg);
    }

    LM_DBG("Checking if ISC is for originating user\n");
    /* originating leg */
    if (dir == DLG_MOBILE_ORIGINATING) {
        k = cscf_get_originating_user(msg, &s);
        LM_DBG("ISC is for Orig user\n");
        if (k) {
            LM_DBG("Orig user is [%.*s]\n", s.len, s.s);
            k = isc_is_registered(&s, d);
            if (k == IMPU_NOT_REGISTERED) {
                LM_DBG("User is not registered\n");
                return ISC_RETURN_FALSE;
            }

            LM_DBG("Orig User <%.*s> [%d]\n", s.len, s.s, k);
            //CHECK if this is a new call (According to spec if the new uri and old mark URI are different then this is a new call and should
            //be triggered accordingly
            LM_DBG("Checking if RURI has changed...comparing: <%.*s> and <%.*s>\n",
                    old_mark.aor.len, old_mark.aor.s,
                    s.len, s.s);
            if ((old_mark.aor.len == s.len) && memcmp(old_mark.aor.s, s.s, s.len) != 0) {
                LM_DBG("This is a new call....... trigger accordingly\n");
                m = isc_checker_find(s, old_mark.direction, 0, msg,
                        isc_is_registered(&s, d), d);
            } else {
                m = isc_checker_find(s, old_mark.direction, old_mark.skip, msg,
                        isc_is_registered(&s, d), d);
            }
            if (m) {
                new_mark.direction = IFC_ORIGINATING_SESSION;
                new_mark.skip = m->index + 1;
                new_mark.handling = m->default_handling;
                new_mark.aor = s;
                ret = isc_forward(msg, m, &new_mark);
                isc_free_match(m);
                goto done;
            }
        }
        goto done;
    }
    LM_DBG("Checking if ISC is for terminating user\n");
    /* terminating leg */
    if (dir == DLG_MOBILE_TERMINATING) {
        k = cscf_get_terminating_user(msg, &s);
        //sometimes s is populated by an ims_getter method cscf_get_terminating_user that alloc memory that must be free-ed at the end
        free_s = 1;
        LM_DBG("ISC is for Term user\n");
        if (k) {
            k = isc_is_registered(&s, d);
            if (k == IMPU_REGISTERED) {
                new_mark.direction = IFC_TERMINATING_SESSION;
            } else {
                new_mark.direction = IFC_TERMINATING_UNREGISTERED;
            }
            LM_DBG("Term User <%.*s> [%d]\n", s.len, s.s, k);
            //CHECK if this is a new call (According to spec if the new uri and old mark URI are different then this is a new call and should
            //be triggered accordingly
            LM_DBG("Checking if RURI has changed...comparing: <%.*s> and <%.*s>\n",
                    old_mark.aor.len, old_mark.aor.s,
                    s.len, s.s);
            if ((old_mark.aor.len == s.len) && memcmp(old_mark.aor.s, s.s, s.len) != 0) {
                LM_DBG("This is a new call....... trigger accordingly\n");
                m = isc_checker_find(s, new_mark.direction, 0, msg, isc_is_registered(&s, d), d);
            } else {
                LM_DBG("Resuming triggering\n");
                m = isc_checker_find(s, new_mark.direction, old_mark.skip, msg, isc_is_registered(&s, d), d);
            }
            if (m) {
                new_mark.skip = m->index + 1;
                new_mark.handling = m->default_handling;
                new_mark.aor = s;
                ret = isc_forward(msg, m, &new_mark);
                isc_free_match(m);
                goto done;
            }
        }
        goto done;
    }

done:

    if (s.s && free_s == 1)
        shm_free(s.s); // shm_malloc in cscf_get_terminating_user  

    if (old_mark.aor.s)
        pkg_free(old_mark.aor.s);
    return ret;
}
示例#12
0
int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
{
	contact_t* c;
	int st, mode;
	str aor;
	int ret;
	sip_uri_t *u;
	rr_t *route;
	struct sip_uri puri;
	param_hooks_t hooks;
	param_t *params;
	contact_t *contact;
	int use_ob = 1, use_regid = 1;

	u = parse_to_uri(_m);
	if(u==NULL)
		goto error;

	rerrno = R_FINE;
	ret = 1;

	if (parse_message(_m) < 0) {
		goto error;
	}

	if (check_contacts(_m, &st) > 0) {
		goto error;
	}

	if (parse_supported(_m) == 0) {
		if (!(get_supported(_m)	& F_OPTION_TAG_OUTBOUND)
				&& reg_outbound_mode == REG_OUTBOUND_REQUIRE) {
			LM_WARN("Outbound required by server and not supported by UAC\n");
			rerrno = R_OB_UNSUP;
			goto error;
		}
	}

	if (parse_require(_m) == 0) {
		if ((get_require(_m) & F_OPTION_TAG_OUTBOUND)
				&& reg_outbound_mode == REG_OUTBOUND_NONE) {
			LM_WARN("Outbound required by UAC and not supported by server\n");
			rerrno = R_OB_REQD;
			goto error;
		}
	}

	if (reg_outbound_mode != REG_OUTBOUND_NONE
			&& _m->contact && _m->contact->parsed
			&& !(parse_headers(_m, HDR_VIA2_F, 0) == -1 || _m->via2 == 0
				|| _m->via2->error != PARSE_OK)) {
		/* Outbound supported on server, and more than one Via: - not the first hop */

		if (!(parse_headers(_m, HDR_PATH_F, 0) == -1 || _m->path == 0)) {
			route = (rr_t *)0;
			if (parse_rr_body(_m->path->body.s, _m->path->body.len, &route) < 0) {
				LM_ERR("Failed to parse Path: header body\n");
				goto error;
			}
			if (parse_uri(route->nameaddr.uri.s, route->nameaddr.uri.len, &puri) < 0) {
				LM_ERR("Failed to parse Path: URI\n");
				goto error;
			}
			if (parse_params(&puri.params, CLASS_URI, &hooks, &params) != 0) {
				LM_ERR("Failed to parse Path: URI parameters\n");
				goto error;
			}
			if (!hooks.uri.ob) {
				/* No ;ob parameter to top Path: URI - no outbound */
				use_ob = 0;
			}

		} else {
			/* No Path: header - no outbound */
			use_ob = 0;

		}

		contact = ((contact_body_t *) _m->contact->parsed)->contacts;
		if (!contact) {
			LM_ERR("empty Contact:\n");
			goto error;
		}

		if ((use_ob == 0) && (reg_regid_mode == REG_REGID_OUTBOUND)) {
			if ((get_supported(_m) & F_OPTION_TAG_OUTBOUND)
					&& contact->reg_id) {
				LM_WARN("Outbound used by UAC but not supported by edge proxy\n");
				rerrno = R_OB_UNSUP_EDGE;
				goto error;
			} else {
				/* ignore ;reg-id parameter */
				use_regid = 0;
			}
		}
	}

	get_act_time();
	c = get_first_contact(_m);

	if (extract_aor((_uri)?_uri:&get_to(_m)->uri, &aor, NULL) < 0) {
		LM_ERR("failed to extract Address Of Record\n");
		goto error;
	}

	mem_only = is_cflag_set(REG_SAVE_MEM_FL)?FL_MEM:FL_NONE;

	if (c == 0) {
		if (st) {
			if (star(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error;
			else ret=3;
		} else {
			if (no_contacts(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error;
			else ret=4;
		}
	} else {
		mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0;
		if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode, use_regid)) < 0)
			goto error;
		ret = (ret==0)?1:ret;
	}

	update_stat(accepted_registrations, 1);

	/* Only send reply upon request, not upon reply */
	if ((is_route_type(REQUEST_ROUTE) || is_route_type(FAILURE_ROUTE))
			&& !is_cflag_set(REG_SAVE_NORPL_FL) && (reg_send_reply(_m) < 0))
		return -1;

	return ret;
error:
	update_stat(rejected_registrations, 1);
	if (is_route_type(REQUEST_ROUTE) && !is_cflag_set(REG_SAVE_NORPL_FL) )
		reg_send_reply(_m);

	return 0;
}
示例#13
0
文件: save.c 项目: halan/kamailio
int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
{
	contact_t* c;
	int st, mode;
	str aor;
	int ret;
	sip_uri_t *u;

	u = parse_to_uri(_m);
	if(u==NULL)
		goto error;

	rerrno = R_FINE;
	ret = 1;

	if (parse_message(_m) < 0) {
		goto error;
	}

	if (check_contacts(_m, &st) > 0) {
		goto error;
	}

	if (parse_supported(_m) == 0) {
		if (!(((struct supported_body *)_m->supported->parsed)->supported_all
				& F_SUPPORTED_OUTBOUND) && reg_outbound_mode == REG_OUTBOUND_REQUIRE) {
			LM_WARN("Outbound required by server and not supported by UAC\n");
			rerrno = R_OB_UNSUP;
			goto error;
		}
	}
	
	get_act_time();
	c = get_first_contact(_m);

	if (extract_aor((_uri)?_uri:&get_to(_m)->uri, &aor, NULL) < 0) {
		LM_ERR("failed to extract Address Of Record\n");
		goto error;
	}

	mem_only = is_cflag_set(REG_SAVE_MEM_FL)?FL_MEM:FL_NONE;

	if (c == 0) {
		if (st) {
			if (star(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error;
			else ret=3;
		} else {
			if (no_contacts(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error;
			else ret=4;
		}
	} else {
		mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0;
		if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode)) < 0)
			goto error;
		ret = (ret==0)?1:ret;
	}

	update_stat(accepted_registrations, 1);

	/* Only send reply upon request, not upon reply */
	if ((is_route_type(REQUEST_ROUTE)) && !is_cflag_set(REG_SAVE_NORPL_FL) && (reg_send_reply(_m) < 0))
		return -1;

	return ret;
error:
	update_stat(rejected_registrations, 1);
	if (is_route_type(REQUEST_ROUTE) && !is_cflag_set(REG_SAVE_NORPL_FL) )
		reg_send_reply(_m);

	return 0;
}