📄 lcr_mod.c
字号:
uri_type scheme; uri_transport transport; struct ip_addr address; str addr_str, port_str; char *at, *prefix; int_str val; struct mi matched_gws[MAX_NO_OF_GWS + 1]; unsigned short strip_len, prefix_len, priority; int randomizer_start, randomizer_end, randomizer_flag; struct lcr_info lcr_rec; /* Find Request-URI user */ if (parse_sip_msg_uri(_m) < 0) { LOG(L_ERR, "load_gws(): Error while parsing R-URI\n"); return -1; } ruri_user = _m->parsed_uri.user; /* Look for Caller RPID or From URI */ if (search_first_avp(rpid_avp_name_str, rpid_name, &val, 0) && val.s.s && val.s.len) { /* Get URI user from RPID */ from_uri.len = val.s.len; from_uri.s = val.s.s; } else { /* Get URI from From URI */ if ((!_m->from) && (parse_headers(_m, HDR_FROM_F, 0) == -1)) { LOG(L_ERR, "load_gws(): Error while parsing message\n"); return -1; } if (!_m->from) { LOG(L_ERR, "load_gws(): FROM header field not found\n"); return -1; } if ((!(_m->from)->parsed) && (parse_from_header(_m) < 0)) { LOG(L_ERR, "load_gws(): Error while parsing From body\n"); return -1; } from_uri = get_from(_m)->uri; } if (from_uri.len < MAX_FROM_URI_LEN) { strncpy(from_uri_str, from_uri.s, from_uri.len); from_uri_str[from_uri.len] = '\0'; } else { LOG(L_ERR, "load_gws(): from_uri to large\n"); return -1; } /* * Check if the gws and lcrs were reloaded */ if (reload_counter != *lcrs_ws_reload_counter) { if (load_from_uri_regex() != 0) { return -1; } } if (db_mode == 0) { if(grp_id >= 0) { q_len = snprintf(query, MAX_QUERY_SIZE, "SELECT %.*s.%.*s, %.*s.%.*s, %.*s.%.*s, %.*s.%.*s, %.*s.%.*s, %.*s.%.*s FROM %.*s, %.*s WHERE %.*s.%.*s = %d AND '%.*s' LIKE %.*s.%.*s AND '%.*s' LIKE CONCAT(%.*s.%.*s, '%%') AND %.*s.%.*s = %.*s.%.*s ORDER BY CHAR_LENGTH(%.*s.%.*s), %.*s.%.*s DESC, RAND()", gw_table.len, gw_table.s, ip_addr_col.len, ip_addr_col.s, gw_table.len, gw_table.s, port_col.len, port_col.s, gw_table.len, gw_table.s, uri_scheme_col.len, uri_scheme_col.s, gw_table.len, gw_table.s, transport_col.len, transport_col.s, gw_table.len, gw_table.s, strip_col.len, strip_col.s, gw_table.len, gw_table.s, prefix_col.len, prefix_col.s, gw_table.len, gw_table.s, lcr_table.len, lcr_table.s, lcr_table.len, lcr_table.s, grp_id_col.len, grp_id_col.s, grp_id, from_uri.len, from_uri.s, lcr_table.len, lcr_table.s, from_uri_col.len, from_uri_col.s, ruri_user.len, ruri_user.s, lcr_table.len, lcr_table.s, prefix_col.len, prefix_col.s, lcr_table.len, lcr_table.s, grp_id_col.len, grp_id_col.s, gw_table.len, gw_table.s, grp_id_col.len, grp_id_col.s, lcr_table.len, lcr_table.s, prefix_col.len, prefix_col.s, lcr_table.len, lcr_table.s, priority_col.len, priority_col.s); } else { q_len = snprintf(query, MAX_QUERY_SIZE, "SELECT %.*s.%.*s, %.*s.%.*s, %.*s.%.*s, %.*s.%.*s, %.*s.%.*s, %.*s.%.*s FROM %.*s, %.*s WHERE '%.*s' LIKE %.*s.%.*s AND '%.*s' LIKE CONCAT(%.*s.%.*s, '%%') AND %.*s.%.*s = %.*s.%.*s ORDER BY CHAR_LENGTH(%.*s.%.*s), %.*s.%.*s DESC, RAND()", gw_table.len, gw_table.s, ip_addr_col.len, ip_addr_col.s, gw_table.len, gw_table.s, port_col.len, port_col.s, gw_table.len, gw_table.s, uri_scheme_col.len, uri_scheme_col.s, gw_table.len, gw_table.s, transport_col.len, transport_col.s, gw_table.len, gw_table.s, strip_col.len, strip_col.s, gw_table.len, gw_table.s, prefix_col.len, prefix_col.s, gw_table.len, gw_table.s, lcr_table.len, lcr_table.s, from_uri.len, from_uri.s, lcr_table.len, lcr_table.s, from_uri_col.len, from_uri_col.s, ruri_user.len, ruri_user.s, lcr_table.len, lcr_table.s, prefix_col.len, prefix_col.s, lcr_table.len, lcr_table.s, grp_id_col.len, grp_id_col.s, gw_table.len, gw_table.s, grp_id_col.len, grp_id_col.s, lcr_table.len, lcr_table.s, prefix_col.len, prefix_col.s, lcr_table.len, lcr_table.s, priority_col.len, priority_col.s); } if (q_len >= MAX_QUERY_SIZE) { LOG(L_ERR, "load_gws(): Too long database query\n"); return -1; } if (lcr_dbf.raw_query(db_handle, query, &res) < 0) { LOG(L_ERR, "load_gws(): Failed to query accept data\n"); return -1; } for (i = 0; i < RES_ROW_N(res); i++) { row = RES_ROWS(res) + i; if (VAL_NULL(ROW_VALUES(row)) == 1) { LOG(L_ERR, "load_gws(): Gateway IP address is NULL\n"); goto skip1; } addr = (unsigned int)VAL_INT(ROW_VALUES(row)); for (j = i + 1; j < RES_ROW_N(res); j++) { r = RES_ROWS(res) + j; if (addr == (unsigned int)VAL_INT(ROW_VALUES(r))) goto skip1; } if (VAL_NULL(ROW_VALUES(row) + 1) == 1) { port = 0; } else { port = (unsigned int)VAL_INT(ROW_VALUES(row) + 1); } if (VAL_NULL(ROW_VALUES(row) + 2) == 1) { scheme = SIP_URI_T; } else { scheme = (uri_type)VAL_INT(ROW_VALUES(row) + 2); } if (VAL_NULL(ROW_VALUES(row) + 3) == 1) { transport = PROTO_NONE; } else { transport = (uri_transport)VAL_INT(ROW_VALUES(row) + 3); } if (VAL_NULL(ROW_VALUES(row) + 4) == 1) { strip = 0; strip_len = 1; } else { strip = VAL_INT(ROW_VALUES(row) + 4); if (strip<10) strip_len = 1; else if (strip < 100) strip_len = 2; else strip_len = 3; } if (VAL_NULL(ROW_VALUES(row) + 5) == 1) { prefix_len = 0; prefix = (char *)0; } else { prefix = (char *)VAL_STRING(ROW_VALUES(row) + 5); prefix_len = strlen(prefix); } if (5 + prefix_len + 1 + strip_len + 1 + 15 + 1 + 5 + 1 + 14 > MAX_URI_SIZE) { LOG(L_ERR, "load_gws(): Request URI would be too long\n"); goto skip1; } at = (char *)&(ruri[0]); if (scheme == SIP_URI_T) { memcpy(at, "sip:", 4); at = at + 4; } else if (scheme == SIPS_URI_T) { memcpy(at, "sips:", 5); at = at + 5; } else { LOG(L_ERR, "load_gws(): Unknown or unsupported URI " "scheme: %u\n", (unsigned int)scheme); goto skip1; } if (prefix_len) { memcpy(at, prefix, prefix_len); at = at + prefix_len; } /* Add strip in this form |number. For example: |3 means * strip first 3 characters */ *at = '|'; at = at + 1; sprintf(at,"%d", strip); at = at + strip_len; *at = '@'; at = at + 1; address.af = AF_INET; address.len = 4; address.u.addr32[0] = addr; addr_str.s = ip_addr2a(&address); addr_str.len = strlen(addr_str.s); memcpy(at, addr_str.s, addr_str.len); at = at + addr_str.len; if (port != 0) { if (port > 65536) { LOG(L_ERR, "load_gws(): Port of GW is too large: %u\n", port); goto skip1; } *at = ':'; at = at + 1; port_str.s = int2str(port, &port_str.len); memcpy(at, port_str.s, port_str.len); at = at + port_str.len; } if (transport != PROTO_NONE) { memcpy(at, ";transport=", 11); at = at + 11; if (transport == PROTO_UDP) { memcpy(at, "udp", 3); at = at + 3; } else if (transport == PROTO_TCP) { memcpy(at, "tcp", 3); at = at + 3; } else if (transport == PROTO_TLS) { memcpy(at, "tls", 3); at = at + 3; } else { LOG(L_ERR, "load_gws(): Unknown or unsupported " "transport: %u\n", (unsigned int)transport); goto skip1; } } value.s = (char *)&(ruri[0]); value.len = at - value.s; val.s = value; add_avp(gw_uri_avp_name_str|AVP_VAL_STR, gw_uri_name, val); DBG("load_gws(): DEBUG: Added gw_uri_avp <%.*s>\n", value.len, value.s);skip1: continue; } /* end for */ lcr_dbf.free_result(db_handle, res); return 1; } else { /* CACHE MODE */ /* * Let's match the gws: * 1. prefix matching * 2. from_uri matching * 3. grp_id matching * * Note: A gateway must be in the list _only_ once. */ gw_index = 0; duplicated_gw = 0; for (i = 0; i < MAX_NO_OF_LCRS; i++) { lcr_rec = (*lcrs)[i]; if (lcr_rec.end_record != 0) { break; } if ((lcr_rec.prefix_len <= ruri_user.len) && (strncmp(lcr_rec.prefix, ruri_user.s, lcr_rec.prefix_len)==0)) { /* 1. Prefix matching is done */ if ((lcr_rec.from_uri_len == 0) || (from_uri_reg[i].valid && (regexec(&(from_uri_reg[i].re), from_uri_str, 0, (regmatch_t *)NULL, 0) == 0))) { /* 2. from_uri matching is done */ for (j = 0; j < MAX_NO_OF_GWS; j++) { if ((*gws)[j].ip_addr == 0) { break; } if (lcr_rec.grp_id == (*gws)[j].grp_id && (grp_id < 0 || (*gws)[j].grp_id == grp_id)) { /* 3. grp_id matching is done */ for (k = 0; k < gw_index; k++) { if ((*gws)[j].ip_addr == (*gws)[matched_gws[k].gw_index].ip_addr) { /* Found the same gw in the list */ /* Let's keep the one with higher */ /* match on prefix len */ DBG("DEBUG:lcr:load_gws: duplicate gw for index" " %d [%d,%d] and current [%d,%d] \n", k, matched_gws[k].route_index, matched_gws[k].route_index, i, j); duplicated_gw = 1; if (lcr_rec.prefix_len > (*lcrs)[matched_gws[k].route_index].prefix_len) { /* Replace the old entry with the new one */ DBG("DEBUG:lcr:load_gws: replace[%d,%d]" " with [%d,%d] on index %d:" " prefix reason %d>%d\n", matched_gws[k].route_index, matched_gws[k].gw_index, i, j, k, lcr_rec.prefix_len, (*lcrs)[matched_gws[k].route_index].prefix_len); matched_gws[k].route_index = i; matched_gws[k].gw_index = j; /* Stop searching in the matched_gws list */ break; } else if (lcr_rec.prefix_len == (*lcrs)[matched_gws[k].route_index].prefix_len) { if (lcr_rec.priority > (*lcrs)[matched_gws[k].route_index].priority) { /* Replace the old entry with the new one */ DBG("DEBUG:lcr:load_gws: replace[%d,%d] with" " [%d,%d] on index %d:" " priority reason %d>%d\n", matched_gws[k].route_index, matched_gws[k].gw_index, i, j, k, lcr_rec.priority, (*lcrs)[matched_gws[k].route_index].priority); matched_gws[k].route_index = i; matched_gws[k].gw_index = j; /* Stop searching in the matched_gws list */ break; } } } } if (duplicated_gw == 0) { /* This is a new gw */ matched_gws[gw_index].route_index = i; matched_gws[gw_index].gw_index = j; DBG("DEBUG:lcr:load_gws: add matched_gws[%d]=[%d,%d]\n", gw_index, i, j); gw_index++; } else { duplicated_gw = 0; } } } } } } matched_gws[gw_index].route_index = -1; matched_gws[gw_index].gw_index = -1; /* * Sort the gateways based on: * 1. prefix len * 2. priority */ qsort(matched_gws, gw_index, sizeof(struct mi), comp_lcrs); randomizer_start = 0; /* Randomizing the gateways with same prefix_len and same priority */ randomizer_flag = 0; prefix_len = (*lcrs)[matched_gws[0].route_index].prefix_len; priority = (*lcrs)[matched_gws[0].route_index].priority; for (i = 1; i < gw_index; i++) { if ( prefix_len == (*lcrs)[matched_gws[i].route_index].prefix_len && priority == (*lcrs)[matched_gws[i].route_index].priority) { /* we have a match */ if (randomizer_flag == 0) { randomizer_flag = 1; randomizer_start = i - 1; } matched_gws[i - 1].randomizer = rand(); } else { if (randomizer_flag == 1) { randomizer_end = i - 1; randomizer_flag = 0; qsort(&matched_gws[randomizer_start], randomizer_end - randomizer_start + 1, sizeof(struct mi), rand_lcrs); } prefix_len = (*lcrs)[matched_gws[i].route_index].prefix_len; priority = (*lcrs)[matched_gws[i].route_index].priority; } } if (randomizer_flag == 1) { randomizer_end = gw_index - 1; matched_gws[i - 1].randomizer = rand(); qsort(&matched_gws[randomizer_start], randomizer_end - randomizer_start + 1, sizeof(struct mi), rand_lcrs); } for (i = 0; i < MAX_NO_OF_GWS; i++) { index = matched_gws[i].gw_index; if (index == -1) { break; } addr = (*gws)[index].ip_addr; port = (*gws)[index].port; scheme = (*gws)[index].scheme; transport = (*gws)[index].transport; strip = (*gws)[index].strip; if (strip<10) strip_len = 1; else if (strip < 100) strip_len = 2; else strip_len = 3; prefix_len = (*gws)[index].prefix_len; prefix = (*gws)[index].prefix; if (5 + prefix_len + 1 + strip_len + 1 + 15 + 1 + 5 + 1 + 14 > MAX_URI_SIZE) { LOG(L_ERR, "load_gws(): Request URI would be too long\n"); goto skip; } at = (char *)&(ruri[0]); if (scheme == SIP_URI_T) { memcpy(at, "sip:", 4); at = at + 4; } else if (scheme == SIPS_URI_T) { memcpy(at, "sips:", 5); at = at + 5; } else { LOG(L_ERR, "load_gws(): Unknown or unsupported URI scheme: %u\n", (unsigned int)scheme); goto skip; } if (prefix_len) { memcpy(at, prefix, prefix_len); at = at + prefix_len; } //Add strip in this form |number. For example: |3 means strip first 3 characters *at = '|'; at = at + 1; sprintf(at,"%d", strip); at = at + strip_len; *at = '@'; at = at + 1; address.af = AF_INET; address.len = 4; address.u.addr32[0] = addr; addr_str.s = ip_addr2a(&address); addr_str.len = strlen(addr_str.s); memcpy(at, addr_str.s, addr_str.len); at = at + addr_str.len; if (port != 0) { if (port > 65536) { LOG(L_ERR, "load_gws(): Port of GW is too large: %u\n", port); goto skip; } *at = ':'; at = at + 1; port_str.s = int2str(port, &port_str.len); memcpy(at, port_str.s, port_str.len); at = at + port_str.len; } if (transport != PROTO_NONE) { memcpy(at, ";transport=", 11); at = at + 11; if (transport == PROTO_UDP) { memcpy(at, "udp", 3); at = at + 3; } else if (transport == PROTO_TCP) { memcpy(at, "tcp", 3); at = at + 3; } else if (transport == PROTO_TLS) { memcpy(at, "tls", 3); at = at + 3; } else { LOG(L_ERR, "load_gws(): Unknown or unsupported transport: %u\n", (unsigned int)transport); goto skip; } } value.s = (char *)&(ruri[0]); value.len = at - value.s; val.s = value; add_avp(gw_uri_avp_name_str|AVP_VAL_STR, gw_uri_name, val); DBG("load_gws(): DEBUG: Added gw_uri_avp <%.*s>\n", value.len, value.s); skip: continue; } return 1; }}/* * Load info of matching GWs from database to gw_uri AVPs * taking into account the given group id. */int load_gws_grp(struct sip_msg* _m, char* _s1, char* _s2){ int grp_id; grp_id = (int)(long)_s1; return do_load_gws(_m, grp_id);}/* * Load info of matching GWs from database to gw_uri AVPs * ignoring the group id. */int load_gws(struct sip_msg* _m, char* _s1, char* _s2){ return do_load_gws(_m, -1);}/* * If called from request route block, rewrites scheme, host, port, and * transport parts of R-URI based on first gw_uri AVP value, which is then * destroyed. Also saves R-URI user to ruri_user AVP for later use in * failure route block. * If called from failure route block, appends a new branch to request * where scheme, host, port, and transport of URI are taken from the first * gw_uri AVP value, which is then destroyed. URI user is taken from * ruri_user AVP value saved earlier. * Returns 1 upon success and -1 upon failure. */int next_gw(struct sip_msg* _m, char* _s1, char* _s2){ int_str gw_uri_val, ruri_user_val, val; struct action act; int rval; struct usr_avp *gw_uri_avp, *ruri_user_avp; str new_ruri; char *at, *at_char; char *strip_char; unsigned int strip; gw_uri_avp = search_first_avp(gw_uri_avp_name_str, gw_uri_name, &gw_uri_val, 0); if (!gw_uri_avp) return -1; if (route_type == REQUEST_ROUTE) { /* Create new Request-URI taking URI user from current Request-URI and other parts of from gw_uri AVP. */ if (parse_sip_msg_uri(_m) < 0) { LOG(L_ERR, "next_gw(): Parsing of R-URI failed.\n"); return -1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -