/* * 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; } }
/*! * \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); }
/*! * \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; }
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); }
/** * 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; }
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; }
/*! * \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; }
/** * 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); }
/*! * \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; }
/** * 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; }
/** * 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; }
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, ¶ms) != 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; }
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; }