/** * Checks if there is a match on REGISTER. * Inserts route headers and set the dst_uri * @param msg - the message to check * @param str1 - if the user was previously registered 0 - for initial registration, 1 for re/de-registration * @param str2 - not used * @returns #ISC_RETURN_TRUE if found, #ISC_RETURN_FALSE if not */ int isc_match_filter_reg(struct sip_msg *msg, char *str1, udomain_t* d) { int k; isc_match *m; str s = {0, 0}; int ret = ISC_RETURN_FALSE; isc_mark old_mark; enum dialog_direction dir = DLG_MOBILE_ORIGINATING; LM_DBG("Checking triggers\n"); /* starting or resuming? */ memset(&old_mark, 0, sizeof (isc_mark)); LM_DBG("Starting triggering\n"); /* originating leg */ if (dir == DLG_MOBILE_ORIGINATING) { k = cscf_get_originating_user(msg, &s); if (k) { if (str1 == 0 || strlen(str1) != 1) { LM_ERR("wrong parameter - must be \"0\" (initial registration) or \"1\"(previously registered) \n"); return ret; } else if (str1[0] == '0') k = 0; else k = 1; LM_DBG("Orig User <%.*s> [%d]\n", s.len, s.s, k); m = isc_checker_find(s, old_mark.direction, old_mark.skip, msg, k, d); while (m) { LM_DBG("REGISTER match found in filter criteria\n"); ret = isc_third_party_reg(msg, m, &old_mark); old_mark.skip = m->index + 1; isc_free_match(m); m = isc_checker_find(s, old_mark.direction, old_mark.skip, msg, k, d); } if (ret == ISC_RETURN_FALSE) LM_DBG("No REGISTER match found in filter criteria\n"); } } 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; }
/** * Handle third party registration * @param msg - the SIP REGISTER 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 allowed, #ISC_RETURN_FALSE if not */ int isc_third_party_reg(struct sip_msg *msg, isc_match *m, isc_mark *mark, udomain_t* d) { r_third_party_registration r; str path, path_received; int expires = 0; str req_uri = {0, 0}; str to = {0, 0}; str pvni = {0, 0}; str pani = {0, 0}; str cv = {0, 0}; str s = {0, 0}; impurecord_t *p; struct hdr_field *hdr; LM_DBG("isc_third_party_reg: Enter\n"); /* Set Request Uri to IFC matching server name */ req_uri.len = m->server_name.len; req_uri.s = m->server_name.s; /* Get To header*/ to = cscf_get_public_identity(msg); if (cscf_get_originating_user(msg, &s)) { isc_ulb.lock_udomain(d, &s); if ( isc_ulb.get_impurecord(d,&s,&p) != 0) { isc_ulb.unlock_udomain(d, &s); LM_ERR("Failed to get IMPU domain from usrloc\n"); goto no_pai; } if ( build_p_associated_uri(p->s) != 0) { isc_ulb.unlock_udomain(d, &s); LM_ERR("Failed to build P-Associated URI for 3rd party reg\n"); goto no_pai; } isc_ulb.unlock_udomain(d, &s); } /*TODO - check if the min/max expires is in the acceptable limits * this does not work correctly if the user has multiple contacts * and register/deregisters them individually!!! */ no_pai: expires = cscf_get_max_expires(msg, 0); /* Get P-Visited-Network-Id header */ pvni = cscf_get_visited_network_id(msg, &hdr); /* Get P-Access-Network-Info header */ pani = cscf_get_access_network_info(msg, &hdr); if (build_path_vector(msg, &path, &path_received) < 0) { LM_ERR("Failed to parse PATH header for third-party reg\n"); return ISC_RETURN_FALSE; } LM_DBG("PATH header in REGISTER is [%.*s]\n", path.len, path.s); /* Get P-Charging-Vector header */ /* Just forward the charging header received from P-CSCF */ /* Todo: implement also according to TS 24.229, chap 5.4.1.7 */ cv = cscf_get_charging_vector(msg, &hdr); if (req_uri.s) { memset(&r, 0, sizeof (r_third_party_registration)); r.req_uri = req_uri; r.to = to; r.from = isc_my_uri_sip; r.pvni = pvni; r.pani = pani; r.cv = cv; if (m->service_info.s && m->service_info.len) { r.body.content_type = CT_SERVICE_INFO; r.body.content = m->service_info; } else if (m->include_register_request) { r.body.content_type = CT_REGISTER_REQ; r.body.content.s = msg->first_line.u.request.method.s; r.body.content.len = msg->len; } else if (m->include_register_response) { struct bookmark dummy_bm; r.body.content_type = CT_REGISTER_RESP; r.body.content.s = build_res_buf_from_sip_req(200, ®_resp_200OK, 0, msg, (unsigned int*)&r.body.content.len, &dummy_bm); if (!r.body.content.s) { LM_DBG("response building failed for body of third party register request"); r.body.content_type = CT_NONE; } } else { r.body.content_type = CT_NONE; } r.path = path; if (expires <= 0) r_send_third_party_reg(&r, 0); else r_send_third_party_reg(&r, expires + isc_expires_grace); return ISC_RETURN_TRUE; } else { return ISC_RETURN_FALSE; } }