diff --git a/modules/lcr/hash.c b/modules/lcr/hash.c index 2082ad82c..2db56c152 100644 --- a/modules/lcr/hash.c +++ b/modules/lcr/hash.c @@ -38,7 +38,9 @@ int rule_hash_table_insert(struct rule_info **hash_table, unsigned int lcr_id, unsigned int rule_id, unsigned short prefix_len, char *prefix, unsigned short from_uri_len, char *from_uri, - pcre *from_uri_re, unsigned short stopper) + pcre *from_uri_re, unsigned short request_uri_len, + char *request_uri, pcre *request_uri_re, + unsigned short stopper) { struct rule_info *rule; str prefix_str; @@ -48,6 +50,7 @@ int rule_hash_table_insert(struct rule_info **hash_table, if (rule == NULL) { LM_ERR("Cannot allocate memory for rule hash table entry\n"); if (from_uri_re) shm_free(from_uri_re); + if (request_uri_re) shm_free(request_uri_re); return 0; } memset(rule, 0, sizeof(struct rule_info)); @@ -63,6 +66,12 @@ int rule_hash_table_insert(struct rule_info **hash_table, (rule->from_uri)[from_uri_len] = '\0'; rule->from_uri_re = from_uri_re; } + rule->request_uri_len = request_uri_len; + if (request_uri_len) { + memcpy(rule->request_uri, request_uri, request_uri_len); + (rule->request_uri)[request_uri_len] = '\0'; + rule->request_uri_re = request_uri_re; + } rule->stopper = stopper; rule->targets = (struct target *)NULL; @@ -73,9 +82,9 @@ int rule_hash_table_insert(struct rule_info **hash_table, rule->next = hash_table[hash_val]; hash_table[hash_val] = rule; - LM_DBG("inserted rule <%u>, prefix <%.*s>, from_uri <%.*s>, stopper <%u>, " + LM_DBG("inserted rule <%u>, prefix <%.*s>, from_uri <%.*s>, request_uri <%.*s>, stopper <%u>, " "into index <%u>\n", - rule_id, prefix_len, prefix, from_uri_len, from_uri, stopper, + rule_id, prefix_len, prefix, from_uri_len, from_uri, request_uri_len, request_uri, stopper, hash_val); return 1; @@ -177,6 +186,8 @@ void rule_hash_table_contents_free(struct rule_info **hash_table) if (r->from_uri_re) { shm_free(r->from_uri_re); } + if (r->request_uri_re) + shm_free(r->request_uri_re); t = r->targets; while (t) { next_t = t->next; diff --git a/modules/lcr/hash.h b/modules/lcr/hash.h index 9434fabf0..bfe46e07d 100644 --- a/modules/lcr/hash.h +++ b/modules/lcr/hash.h @@ -36,7 +36,9 @@ int rule_hash_table_insert(struct rule_info **hash_table, unsigned int lcr_id, unsigned int rule_id, unsigned short prefix_len, char *prefix, unsigned short from_uri_len, char *from_uri, - pcre *from_uri_re, unsigned short stopper); + pcre *from_uri_re, unsigned short request_uri_len, + char *request_uri, pcre *request_uri_re, + unsigned short stopper); int rule_hash_table_insert_target(struct rule_info **hash_table, struct gw_info *gws, diff --git a/modules/lcr/lcr_mod.c b/modules/lcr/lcr_mod.c index 9825703f3..9f262ef66 100644 --- a/modules/lcr/lcr_mod.c +++ b/modules/lcr/lcr_mod.c @@ -90,7 +90,7 @@ MODULE_VERSION /* * versions of database tables required by the module. */ -#define LCR_RULE_TABLE_VERSION 1 +#define LCR_RULE_TABLE_VERSION 2 #define LCR_RULE_TARGET_TABLE_VERSION 1 #define LCR_GW_TABLE_VERSION 1 @@ -104,6 +104,7 @@ MODULE_VERSION #define LCR_ID_COL "lcr_id" #define PREFIX_COL "prefix" #define FROM_URI_COL "from_uri" +#define REQUEST_URI_COL "request_uri" #define STOPPER_COL "stopper" #define ENABLED_COL "enabled" #define RULE_ID_COL "rule_id" @@ -164,6 +165,7 @@ static str id_col = str_init(ID_COL); static str lcr_id_col = str_init(LCR_ID_COL); static str prefix_col = str_init(PREFIX_COL); static str from_uri_col = str_init(FROM_URI_COL); +static str request_uri_col = str_init(REQUEST_URI_COL); static str stopper_col = str_init(STOPPER_COL); static str enabled_col = str_init(ENABLED_COL); static str rule_id_col = str_init(RULE_ID_COL); @@ -294,6 +296,7 @@ static param_export_t params[] = { {"id_column", STR_PARAM, &id_col.s}, {"prefix_column", STR_PARAM, &prefix_col.s}, {"from_uri_column", STR_PARAM, &from_uri_col.s}, + {"request_uri_column", STR_PARAM, &request_uri_col.s}, {"stopper_column", STR_PARAM, &stopper_col.s}, {"enabled_column", STR_PARAM, &enabled_col.s}, {"rule_id_column", STR_PARAM, &rule_id_col.s}, @@ -416,6 +419,7 @@ static int mod_init(void) lcr_id_col.len = strlen(lcr_id_col.s); prefix_col.len = strlen(prefix_col.s); from_uri_col.len = strlen(from_uri_col.s); + request_uri_col.len = strlen(request_uri_col.s); stopper_col.len = strlen(stopper_col.s); enabled_col.len = strlen(enabled_col.s); rule_id_col.len = strlen(rule_id_col.s); @@ -895,21 +899,21 @@ int reload_tables() unsigned int i, n, lcr_id, rule_id, gw_id, gw_name_len, port, strip, tag_len, prefix_len, from_uri_len, stopper, enabled, flags, gw_cnt, hostname_len, params_len, defunct_until, null_gw_ip_addr, priority, - weight, tmp; + request_uri_len, weight, tmp; struct in_addr in_addr; struct ip_addr ip_addr, *ip_p; uri_type scheme; uri_transport transport; - char *gw_name, *hostname, *tag, *prefix, *from_uri, *params; + char *gw_name, *hostname, *tag, *prefix, *from_uri, *params, *request_uri; db1_res_t* res = NULL; db_row_t* row; db_key_t key_cols[1]; db_op_t op[1]; db_val_t vals[1]; db_key_t gw_cols[12]; - db_key_t rule_cols[5]; + db_key_t rule_cols[6]; db_key_t target_cols[4]; - pcre *from_uri_re; + pcre *from_uri_re, *request_uri_re; struct gw_info *gws, *gw_pt_tmp; struct rule_info **rules, **rule_pt_tmp; str ip_string; @@ -924,6 +928,7 @@ int reload_tables() rule_cols[2] = &from_uri_col; rule_cols[3] = &stopper_col; rule_cols[4] = &enabled_col; + rule_cols[5] = &request_uri_col; gw_cols[0] = &gw_name_col; gw_cols[1] = &ip_addr_col; @@ -943,7 +948,7 @@ int reload_tables() target_cols[2] = &priority_col; target_cols[3] = &weight_col; - from_uri_re = 0; + request_uri_re = from_uri_re = 0; if (lcr_db_init(&db_url) < 0) { LM_ERR("unable to open database connection\n"); @@ -964,7 +969,7 @@ int reload_tables() VAL_INT(vals) = lcr_id; if (DB_CAPABILITY(lcr_dbf, DB_CAP_FETCH)) { - if (lcr_dbf.query(dbh, key_cols, op, vals, rule_cols, 1, 5, 0, 0) + if (lcr_dbf.query(dbh, key_cols, op, vals, rule_cols, 1, 6, 0, 0) < 0) { LM_ERR("db query on lcr_rule table failed\n"); goto err; @@ -974,7 +979,7 @@ int reload_tables() goto err; } } else { - if (lcr_dbf.query(dbh, key_cols, op, vals, rule_cols, 1, 5, 0, &res) + if (lcr_dbf.query(dbh, key_cols, op, vals, rule_cols, 1, 6, 0, &res) < 0) { LM_ERR("db query on lcr_rule table failed\n"); goto err; @@ -982,13 +987,13 @@ int reload_tables() } n = 0; - from_uri_re = 0; + request_uri_re = from_uri_re = 0; do { LM_DBG("loading, cycle %d with <%d> rows", n++, RES_ROW_N(res)); for (i = 0; i < RES_ROW_N(res); i++) { - from_uri_re = 0; + request_uri_re = from_uri_re = 0; row = RES_ROWS(res) + i; if ((VAL_NULL(ROW_VALUES(row)) == 1) || @@ -1070,9 +1075,37 @@ int reload_tables() from_uri_re = 0; } + if (VAL_NULL(ROW_VALUES(row) + 5) == 1) { + request_uri_len = 0; + request_uri = 0; + } else { + if (VAL_TYPE(ROW_VALUES(row) + 5) != DB1_STRING) { + LM_ERR("lcr rule <%u> request_uri is not string\n", + rule_id); + goto err; + } + request_uri = (char *)VAL_STRING(ROW_VALUES(row) + 5); + request_uri_len = strlen(from_uri); + } + if (request_uri_len > MAX_URI_LEN) { + LM_ERR("lcr rule <%u> request_uri is too long\n", rule_id); + goto err; + } + if (request_uri_len > 0) { + request_uri_re = reg_ex_comp(request_uri); + if (request_uri_re == 0) { + LM_ERR("failed to compile lcr rule <%u> request_uri " + "<%s>\n", rule_id, request_uri); + goto err; + } + } else { + request_uri_re = 0; + } + if (!rule_hash_table_insert(rules, lcr_id, rule_id, prefix_len, prefix, from_uri_len, from_uri, - from_uri_re, stopper) || + from_uri_re, request_uri_len, + request_uri, request_uri_re, stopper) || !prefix_len_insert(rules, prefix_len)) { goto err; } @@ -1703,7 +1736,7 @@ void add_gws_into_avps(struct gw_info *gws, struct matched_gw_info *matched_gws, static int load_gws(struct sip_msg* _m, fparam_t *_lcr_id, pv_spec_t* _from_uri) { - str ruri_user, from_uri; + str ruri_user, from_uri, *request_uri; int i, j, lcr_id; unsigned int gw_index, now, dex; int_str val; @@ -1749,6 +1782,7 @@ static int load_gws(struct sip_msg* _m, fparam_t *_lcr_id, return -1; } ruri_user = _m->parsed_uri.user; + request_uri = GET_RURI(_m); /* * Find lcr entries that match based on prefix and from_uri and collect @@ -1774,34 +1808,43 @@ static int load_gws(struct sip_msg* _m, fparam_t *_lcr_id, rule = rule_hash_table_lookup(rules, pl->prefix_len, ruri_user.s); while (rule) { /* Match prefix */ - if ((rule->prefix_len == pl->prefix_len) && - (strncmp(rule->prefix, ruri_user.s, pl->prefix_len) == 0)) { - /* Match from uri */ - if ((rule->from_uri_len == 0) || - (pcre_exec(rule->from_uri_re, NULL, from_uri.s, - from_uri.len, 0, 0, NULL, 0) >= 0)) { - /* Load gws associated with this rule */ - t = rule->targets; - while (t) { - /* If this gw is defunct, skip it */ - if (gws[t->gw_index].defunct_until > now) goto skip_gw; - matched_gws[gw_index].gw_index = t->gw_index; - matched_gws[gw_index].prefix_len = pl->prefix_len; - matched_gws[gw_index].priority = t->priority; - matched_gws[gw_index].weight = t->weight * - (rand() >> 8); - matched_gws[gw_index].duplicate = 0; - LM_DBG("added matched_gws[%d]=[%u, %u, %u, %u]\n", - gw_index, t->gw_index, pl->prefix_len, - t->priority, matched_gws[gw_index].weight); - gw_index++; - skip_gw: - t = t->next; - } - /* Do not look further if this matching rule was stopper */ - if (rule->stopper == 1) goto done; - } + if ((rule->prefix_len != pl->prefix_len) || + (strncmp(rule->prefix, ruri_user.s, pl->prefix_len))) + goto next; + + /* Match from uri */ + if ((rule->from_uri_len != 0) && + (pcre_exec(rule->from_uri_re, NULL, from_uri.s, + from_uri.len, 0, 0, NULL, 0) < 0)) + goto next; + + /* Match request uri */ + if ((rule->request_uri_len != 0) && + (pcre_exec(rule->request_uri_re, NULL, request_uri->s, + request_uri->len, 0, 0, NULL, 0) < 0)) + goto next; + + /* Load gws associated with this rule */ + t = rule->targets; + while (t) { + /* If this gw is defunct, skip it */ + if (gws[t->gw_index].defunct_until > now) goto skip_gw; + matched_gws[gw_index].gw_index = t->gw_index; + matched_gws[gw_index].prefix_len = pl->prefix_len; + matched_gws[gw_index].priority = t->priority; + matched_gws[gw_index].weight = t->weight * + (rand() >> 8); + matched_gws[gw_index].duplicate = 0; + LM_DBG("added matched_gws[%d]=[%u, %u, %u, %u]\n", + gw_index, t->gw_index, pl->prefix_len, + t->priority, matched_gws[gw_index].weight); + gw_index++; + skip_gw: + t = t->next; } + /* Do not look further if this matching rule was stopper */ + if (rule->stopper == 1) goto done; +next: rule = rule->next; } pl = pl->next; diff --git a/modules/lcr/lcr_mod.h b/modules/lcr/lcr_mod.h index 9c87e1289..df9ceb256 100644 --- a/modules/lcr/lcr_mod.h +++ b/modules/lcr/lcr_mod.h @@ -62,6 +62,9 @@ struct rule_info { char from_uri[MAX_URI_LEN + 1]; unsigned short from_uri_len; pcre *from_uri_re; + char request_uri[MAX_URI_LEN + 1]; + unsigned short request_uri_len; + pcre *request_uri_re; unsigned short stopper; unsigned int enabled; struct target *targets;