فهرست منبع

modules/lcr: same gateway may now belong all lcr instances
- Gateways with special lcr instance id 0 belong to all normal lcr
instances.

Juha Heinanen 13 سال پیش
والد
کامیت
3e6570dae9
3فایلهای تغییر یافته به همراه295 افزوده شده و 256 حذف شده
  1. 17 12
      modules/lcr/README
  2. 12 6
      modules/lcr/doc/lcr_admin.xml
  3. 266 238
      modules/lcr/lcr_mod.c

+ 17 - 12
modules/lcr/README

@@ -210,7 +210,10 @@ Chapter 1. Admin Guide
    the gateways is tried is based on admin defined "least cost" rules.
 
    The LCR module supports many independent LCR instances (gateways and
-   least cost rules). Each such instance has its own LCR identifier.
+   least cost rules). Each such instance has its own LCR instance
+   identifier. Identifiers of normal LCR instances are positive integers.
+   Gateways may belong to special LCR instance with identifier 0 meaning
+   that such gateways belong to all normal LCR instances.
 
    For the purpose of facilitating least cost routing of requests, each
    gateway of an LCR instance is associated with one or more <prefix, from
@@ -360,7 +363,9 @@ modparam("lcr", "id_column", "row_id")
 3.4. lcr_id_column (string)
 
    Name of the column holding the identifier of an LCR instance. Common to
-   all lcr module tables.
+   all lcr module tables. In lcr_rule and lcr_rule_target tables, value of
+   the column is integer from 1 to lcr_count. In lcr_gw table, value of
+   the column is from 0 to lcr_count.
 
    Default value is “lcr_id”.
 
@@ -777,13 +782,13 @@ modparam("lcr", "fetch_rows", 3000)
 4.1.  load_gws(lcr_id[, uri_user[, caller_uri]])
 
    Loads attributes of matching gateways to gw_uri_avp (see Overview
-   section). Argument lcr_id specifies the used LCR instance. It can be an
-   integer or a pseudo variable containing an integer value. If uri_user
-   is given, it is used, instead of Request-URI user part, to look for
-   matching gateways. Caller's URI may be given by caller_uri argument. If
-   caller_uri argument is omitted, it defaults to empty string. Both
-   uri_user and caller_uri argument may be a string or a pseudo variable
-   containing a sting value.
+   section). Argument lcr_id specifies the used LCR instance. It can be a
+   positive integer or a pseudo variable containing an integer value. If
+   uri_user is given, it is used, instead of Request-URI user part, to
+   look for matching gateways. Caller's URI may be given by caller_uri
+   argument. If caller_uri argument is omitted, it defaults to empty
+   string. Both uri_user and caller_uri argument may be a string or a
+   pseudo variable containing a sting value.
 
    Returns 1 if at least one matching gateway was found, 2 if no matching
    gateways was found, and -1 on error.
@@ -860,7 +865,7 @@ defunct_gw(60);
 4.4.  from_gw(lcr_id[, ip_addr, proto])
 
    Checks if request comes from IP address and transport protocol
-   spesified for a gateway in LCR instance lcr_id. Fails if the LCR
+   specified for a gateway in LCR instance lcr_id. Fails if the LCR
    instance includes one or more gateways without IP address. IP address
    and transport protocol to be checked are either taken from source IP
    address of the request or (if present) from ip_addr and proto
@@ -894,7 +899,7 @@ if (from_gw(1, $avp(s:real_source_addr), 2) {
 4.5.  from_any_gw([ip_addr, proto])
 
    Checks if request comes from IP address and transport protocol
-   spesified for any gateway. Only LCR instances, where all gateways have
+   specified for any gateway. Only LCR instances, where all gateways have
    IP address, are included in the test. IP address and transport protocol
    to be checked are either taken from source IP address and transport
    protocol of the request or (if present) from ip_addr and proto
@@ -922,7 +927,7 @@ $var(lcr_id) = from_any_gw("192.168.1.1", 3);
 4.6.  to_gw(lcr_id[, ip_addr, proto])
 
    Checks if in-dialog request goes to IP address and transport protocol
-   spesified for a gateway in LCR instance lcr_id. Fails if LCR instance
+   specified for a gateway in LCR instance lcr_id. Fails if LCR instance
    includes one or more gateways without IP address. IP address and
    transport protocol to be checked are either taken from Request-URI or
    (if present) from ip_addr and proto arguments. See from_gw() for more

+ 12 - 6
modules/lcr/doc/lcr_admin.xml

@@ -24,7 +24,10 @@
 	<para>
 	The LCR module supports many independent LCR instances (gateways and
 	least cost rules).  Each such instance has its own <emphasis>LCR
-	identifier.</emphasis>
+	instance identifier</emphasis>.  Identifiers of normal LCR instances
+	are positive integers. Gateways may belong to special LCR instance
+	with identifier 0 meaning that such gateways belong to all normal
+	LCR instances.
 	</para>
 	<para>
 	For the purpose of facilitating least cost routing of requests,
@@ -211,7 +214,10 @@ modparam("lcr", "id_column", "row_id")
 		<title><varname>lcr_id_column</varname> (string)</title>
 		<para>
 		Name of the column holding the identifier of an LCR
-		instance.  Common to all lcr module tables.
+		instance.  Common to all lcr module tables.  In lcr_rule and
+		lcr_rule_target tables, value of the column is
+		integer from 1 to lcr_count.  In lcr_gw table, value of the
+		column is from 0 to lcr_count.
 		</para>
 		<para>
 		<emphasis>
@@ -980,7 +986,7 @@ modparam("lcr", "fetch_rows", 3000)
 		<para>
 		Loads attributes of matching gateways to gw_uri_avp
 		(see Overview section).  Argument lcr_id specifies the used
-	        LCR instance.  It can be an integer or a pseudo
+	        LCR instance.  It can be a positive integer or a pseudo
 		variable containing an integer value.
 		If uri_user is given, it is used, instead of Request-URI user
 		part, to look for matching gateways.  Caller's URI may be given
@@ -1106,7 +1112,7 @@ defunct_gw(60);
 		</title>
 		<para>
 		Checks if request comes from IP address and transport protocol
-		spesified for a gateway in LCR instance lcr_id.
+		specified for a gateway in LCR instance lcr_id.
 		Fails if the LCR instance includes 
 		one or more gateways without IP address.
 		IP address and transport protocol to be checked are either
@@ -1156,7 +1162,7 @@ if (from_gw(1, $avp(s:real_source_addr), 2) {
 		</title>
 		<para>
 		Checks if request comes from IP address and transport 
-		protocol spesified for any gateway.  Only LCR instances,
+		protocol specified for any gateway.  Only LCR instances,
 		where all gateways
 		have IP address, are included in the test.
 		IP address and transport protocol to be checked are either
@@ -1202,7 +1208,7 @@ $var(lcr_id) = from_any_gw("192.168.1.1", 3);
 		</title>
 		<para>
 		Checks if in-dialog request goes to IP address and transport
-		protocol spesified for a gateway in LCR instance lcr_id.
+		protocol specified for a gateway in LCR instance lcr_id.
 		Fails if LCR
 		instance includes one or more gateways without IP
 		address.  IP address and transport protocol to be

+ 266 - 238
modules/lcr/lcr_mod.c

@@ -873,6 +873,252 @@ static int prefix_len_insert(struct rule_info **table,
     return 1;
 }
 
+static int insert_gws(db1_res_t *res, struct gw_info *gws,
+		      unsigned int *null_gw_ip_addr,
+		      unsigned int *gw_cnt)
+{
+    unsigned int i, gw_id, defunct_until, gw_name_len, port, params_len,
+	hostname_len, strip, prefix_len, tag_len, flags;
+    char *gw_name, *params, *hostname, *prefix, *tag;
+    db_row_t* row;
+    struct in_addr in_addr;
+    struct ip_addr ip_addr, *ip_p;
+    str ip_string;
+    uri_type scheme;
+    uri_transport transport;
+    
+    for (i = 0; i < RES_ROW_N(res); i++) {
+	row = RES_ROWS(res) + i;
+	if ((VAL_NULL(ROW_VALUES(row) + 12) == 1) ||
+	    (VAL_TYPE(ROW_VALUES(row) + 12) != DB1_INT)) {
+	    LM_ERR("lcr_gw id at row <%u> is null or not int\n", i);
+	    return 0;
+	}
+	gw_id = (unsigned int)VAL_INT(ROW_VALUES(row) + 12);
+	if (VAL_NULL(ROW_VALUES(row) + 11)) {
+	    defunct_until = 0;
+	} else {
+	    if (VAL_TYPE(ROW_VALUES(row) + 11) != DB1_INT) {
+		LM_ERR("lcr_gw defunct at row <%u> is not int\n", i);
+		return 0;
+	    }
+	    defunct_until = (unsigned int)VAL_INT(ROW_VALUES(row) + 11);
+	    if (defunct_until > 4294967294UL) {
+		LM_DBG("skipping disabled gw <%u>\n", gw_id);
+		continue;
+	    }
+	}
+	if (!VAL_NULL(ROW_VALUES(row)) &&
+	    (VAL_TYPE(ROW_VALUES(row)) != DB1_STRING)) {
+	    LM_ERR("lcr_gw gw_name at row <%u> is not null or string\n", i);
+	    return 0;
+	}
+	if (VAL_NULL(ROW_VALUES(row))) {
+	    gw_name_len = 0;
+	    gw_name = (char *)0;
+	} else {
+	    if (VAL_TYPE(ROW_VALUES(row)) != DB1_STRING) {
+		LM_ERR("lcr_gw gw_name at row <%u> is not string\n", i);
+		return 0;
+	    }
+	    gw_name = (char *)VAL_STRING(ROW_VALUES(row));
+	    gw_name_len = strlen(gw_name);
+	}
+	if (gw_name_len > MAX_NAME_LEN) {
+	    LM_ERR("lcr_gw gw_name <%u> at row <%u> it too long\n",
+		   gw_name_len, i);
+	    return 0;
+	}
+	if (!VAL_NULL(ROW_VALUES(row) + 1) &&
+	    (VAL_TYPE(ROW_VALUES(row) + 1) != DB1_STRING)) {
+	    LM_ERR("lcr_gw ip_addr at row <%u> is not null or string\n",
+		   i);
+	    return 0;
+	}
+	if (VAL_NULL(ROW_VALUES(row) + 1)) {
+	    ip_string.s = (char *)0;
+	    ip_addr.af = 0;
+	    ip_addr.len = 0;
+	    *null_gw_ip_addr = 1;
+	} else {
+	    ip_string.s = (char *)VAL_STRING(ROW_VALUES(row) + 1);
+	    ip_string.len = strlen(ip_string.s);
+	    if ((ip_p = str2ip(&ip_string))) {
+		/* 123.123.123.123 */
+		ip_addr = *ip_p;
+	    }
+#ifdef USE_IPV6
+	    else if ((ip_p = str2ip6(&ip_string))) {
+		/* fe80::123:4567:89ab:cdef and [fe80::123:4567:89ab:cdef] */
+		ip_addr = *ip_p;
+	    }
+#endif
+	    else if (inet_aton(ip_string.s, &in_addr) == 0) {
+		/* backwards compatibility for integer or hex notations */
+		ip_addr.u.addr32[0] = in_addr.s_addr;
+		ip_addr.af = AF_INET;
+		ip_addr.len = 4;
+	    }
+	    else {
+		LM_ERR("lcr_gw ip_addr <%s> at row <%u> is invalid\n",
+		       ip_string.s, i);
+		return 0;
+	    }
+	}
+	if (VAL_NULL(ROW_VALUES(row) + 2)) {
+	    port = 0;
+	} else {
+	    if (VAL_TYPE(ROW_VALUES(row) + 2) != DB1_INT) {
+		LM_ERR("lcr_gw port at row <%u> is not int\n", i);
+		return 0;
+	    }
+	    port = (unsigned int)VAL_INT(ROW_VALUES(row) + 2);
+	}
+	if (port > 65536) {
+	    LM_ERR("lcr_gw port <%d> at row <%u> is too large\n", port, i);
+	    return 0;
+	}
+	if (VAL_NULL(ROW_VALUES(row) + 3)) {
+	    scheme = SIP_URI_T;
+	} else {
+	    if (VAL_TYPE(ROW_VALUES(row) + 3) != DB1_INT) {
+		LM_ERR("lcr_gw uri scheme at row <%u> is not int\n", i);
+		return 0;
+	    }
+	    scheme = (uri_type)VAL_INT(ROW_VALUES(row) + 3);
+	}
+	if ((scheme != SIP_URI_T) && (scheme != SIPS_URI_T)) {
+	    LM_ERR("lcr_gw has unknown or unsupported URI scheme <%u> at "
+		   "row <%u>\n", (unsigned int)scheme, i);
+	    return 0;
+	}
+	if (VAL_NULL(ROW_VALUES(row) + 4)) {
+	    transport = PROTO_NONE;
+	} else {
+	    if (VAL_TYPE(ROW_VALUES(row) + 4) != DB1_INT) {
+		LM_ERR("lcr_gw transport at row <%u> is not int\n", i);
+		return 0;
+	    }
+	    transport = (uri_transport)VAL_INT(ROW_VALUES(row) + 4);
+	}
+	if ((transport != PROTO_UDP) && (transport != PROTO_TCP) &&
+	    (transport != PROTO_TLS) && (transport != PROTO_SCTP) &&
+	    (transport != PROTO_NONE)) {
+	    LM_ERR("lcr_gw has unknown or unsupported transport <%u> at "
+		   " row <%u>\n", (unsigned int)transport, i);
+	    return 0;
+	}
+	if ((scheme == SIPS_URI_T) && (transport == PROTO_UDP)) {
+	    LM_ERR("lcr_gw has wrong transport <%u> for SIPS URI "
+		   "scheme at row <%u>\n", transport, i);
+	    return 0;
+	}
+	if (VAL_NULL(ROW_VALUES(row) + 5)) {
+	    params_len = 0;
+	    params = (char *)0;
+	} else {
+	    if (VAL_TYPE(ROW_VALUES(row) + 5) != DB1_STRING) {
+		LM_ERR("lcr_gw params at row <%u> is not string\n", i);
+		return 0;
+	    }
+	    params = (char *)VAL_STRING(ROW_VALUES(row) + 5);
+	    params_len = strlen(params);
+	    if ((params_len > 0) && (params[0] != ';')) {
+		LM_ERR("lcr_gw params at row <%u> does not start "
+		       "with ';'\n", i);
+		return 0;
+	    }
+	}
+	if (params_len > MAX_PARAMS_LEN) {
+	    LM_ERR("lcr_gw params length <%u> at row <%u> it too large\n",
+		   params_len, i);
+	    return 0;
+	}
+	if (VAL_NULL(ROW_VALUES(row) + 6)) {
+	    if (ip_string.s == 0) {
+		LM_ERR("lcr_gw gw ip_addr and hostname are both null "
+		       "at row <%u>\n", i);
+		return 0;
+	    }
+	    hostname_len = 0;
+	    hostname = (char *)0;
+	} else {
+	    if (VAL_TYPE(ROW_VALUES(row) + 6) != DB1_STRING) {
+		LM_ERR("hostname at row <%u> is not string\n", i);
+		return 0;
+	    }
+	    hostname = (char *)VAL_STRING(ROW_VALUES(row) + 6);
+	    hostname_len = strlen(hostname);
+	}
+	if (hostname_len > MAX_HOST_LEN) {
+	    LM_ERR("lcr_gw hostname at row <%u> it too long\n", i);
+	    return 0;
+	}
+	if (VAL_NULL(ROW_VALUES(row) + 7)) {
+	    strip = 0;
+	} else {
+	    if (VAL_TYPE(ROW_VALUES(row) + 7) != DB1_INT) {
+		LM_ERR("lcr_gw strip count at row <%u> is not int\n", i);
+		return 0;
+	    }
+	    strip = (unsigned int)VAL_INT(ROW_VALUES(row) + 7);
+	}
+	if (strip > MAX_USER_LEN) {
+	    LM_ERR("lcr_gw strip count <%u> at row <%u> it too large\n",
+		   strip, i);
+	    return 0;
+	}
+	if (VAL_NULL(ROW_VALUES(row) + 8)) {
+	    prefix_len = 0;
+	    prefix = (char *)0;
+	} else {
+	    if (VAL_TYPE(ROW_VALUES(row) + 8) != DB1_STRING) {
+		LM_ERR("lcr_gw prefix at row <%u> is not string\n", i);
+		return 0;
+	    }
+	    prefix = (char *)VAL_STRING(ROW_VALUES(row) + 8);
+	    prefix_len = strlen(prefix);
+	}
+	if (prefix_len > MAX_PREFIX_LEN) {
+	    LM_ERR("lcr_gw prefix at row <%u> it too long\n", i);
+	    return 0;
+	}
+	if (VAL_NULL(ROW_VALUES(row) + 9)) {
+	    tag_len = 0;
+	    tag = (char *)0;
+	} else {
+	    if (VAL_TYPE(ROW_VALUES(row) + 9) != DB1_STRING) {
+		LM_ERR("lcr_gw tag at row <%u> is not string\n", i);
+		return 0;
+	    }
+	    tag = (char *)VAL_STRING(ROW_VALUES(row) + 9);
+	    tag_len = strlen(tag);
+	}
+	if (tag_len > MAX_TAG_LEN) {
+	    LM_ERR("lcr_gw tag at row <%u> it too long\n", i);
+	    return 0;
+	}
+	if (VAL_NULL(ROW_VALUES(row) + 10)) {
+	    flags = 0;
+	} else {
+	    if (VAL_TYPE(ROW_VALUES(row) + 10) != DB1_INT) {
+		LM_ERR("lcr_gw flags at row <%u> is not int\n", i);
+		return 0;
+	    }
+	    flags = (unsigned int)VAL_INT(ROW_VALUES(row) + 10);
+	}
+	(*gw_cnt)++;
+	if (!insert_gw(gws, *gw_cnt, gw_id, gw_name, gw_name_len,
+		       scheme, &ip_addr, port,
+		       transport, params, params_len, hostname,
+		       hostname_len, ip_string.s, strip, prefix, prefix_len,
+		       tag, tag_len, flags, defunct_until)) {
+	    return 0;
+	}
+    }
+    return 1;
+}
+
 
 /*
  * Reload gws to unused gw table, rules to unused lcr hash table, and
@@ -881,15 +1127,9 @@ static int prefix_len_insert(struct rule_info **table,
  */
 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;
-    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;
+    unsigned int i, n, lcr_id, rule_id, gw_id, from_uri_len, stopper,
+	prefix_len, enabled, gw_cnt, null_gw_ip_addr, priority, weight, tmp;
+    char *prefix, *from_uri;
     db1_res_t* res = NULL;
     db_row_t* row;
     db_key_t key_cols[1];
@@ -901,7 +1141,6 @@ int reload_tables()
     pcre *from_uri_re;
     struct gw_info *gws, *gw_pt_tmp;
     struct rule_info **rules, **rule_pt_tmp;
-    str ip_string;
 
     key_cols[0] = &lcr_id_col;
     op[0] = OP_EQ;
@@ -1105,236 +1344,25 @@ int reload_tables()
 
 	null_gw_ip_addr = gw_cnt = 0;
 
-	for (i = 0; i < RES_ROW_N(res); i++) {
-	    row = RES_ROWS(res) + i;
-	    if ((VAL_NULL(ROW_VALUES(row) + 12) == 1) ||
-		(VAL_TYPE(ROW_VALUES(row) + 12) != DB1_INT)) {
-		LM_ERR("lcr_gw id at row <%u> is null or not int\n", i);
-		goto err;
-	    }
-	    gw_id = (unsigned int)VAL_INT(ROW_VALUES(row) + 12);
-	    if (VAL_NULL(ROW_VALUES(row) + 11)) {
-		defunct_until = 0;
-	    } else {
-		if (VAL_TYPE(ROW_VALUES(row) + 11) != DB1_INT) {
-		    LM_ERR("lcr_gw defunct at row <%u> is not int\n", i);
-		    goto err;
-		}
-		defunct_until = (unsigned int)VAL_INT(ROW_VALUES(row) + 11);
-		if (defunct_until > 4294967294UL) {
-		    LM_DBG("skipping disabled gw <%u>\n", gw_id);
-		    continue;
-		}
-	    }
-	    if (!VAL_NULL(ROW_VALUES(row)) &&
-		(VAL_TYPE(ROW_VALUES(row)) != DB1_STRING)) {
-		LM_ERR("lcr_gw gw_name at row <%u> is not null or string\n", i);
-		goto err;
-	    }
-	    if (VAL_NULL(ROW_VALUES(row))) {
-		gw_name_len = 0;
-		gw_name = (char *)0;
-	    } else {
-		if (VAL_TYPE(ROW_VALUES(row)) != DB1_STRING) {
-		    LM_ERR("lcr_gw gw_name at row <%u> is not string\n", i);
-		    goto err;
-		}
-		gw_name = (char *)VAL_STRING(ROW_VALUES(row));
-		gw_name_len = strlen(gw_name);
-	    }
-	    if (gw_name_len > MAX_NAME_LEN) {
-		LM_ERR("lcr_gw gw_name <%u> at row <%u> it too long\n",
-		       gw_name_len, i);
-		goto err;
-	    }
-	    if (!VAL_NULL(ROW_VALUES(row) + 1) &&
-		(VAL_TYPE(ROW_VALUES(row) + 1) != DB1_STRING)) {
-		LM_ERR("lcr_gw ip_addr at row <%u> is not null or string\n",
-		       i);
-		goto err;
-	    }
-	    if (VAL_NULL(ROW_VALUES(row) + 1)) {
-		ip_string.s = (char *)0;
-		ip_addr.af = 0;
-		ip_addr.len = 0;
-		null_gw_ip_addr = 1;
-	    } else {
-		ip_string.s = (char *)VAL_STRING(ROW_VALUES(row) + 1);
-		ip_string.len = strlen(ip_string.s);
-		if ((ip_p = str2ip(&ip_string))) {
-		    /* 123.123.123.123 */
-		    ip_addr = *ip_p;
-		}
-#ifdef USE_IPV6
-		else if ((ip_p = str2ip6(&ip_string))) {
-		    /* fe80::123:4567:89ab:cdef and [fe80::123:4567:89ab:cdef] */
-		    ip_addr = *ip_p;
-		}
-#endif
-		else if (inet_aton(ip_string.s, &in_addr) == 0) {
-		    /* backwards compatibility for integer or hex notations */
-		    ip_addr.u.addr32[0] = in_addr.s_addr;
-		    ip_addr.af = AF_INET;
-		    ip_addr.len = 4;
-		}
-		else {
-		    LM_ERR("lcr_gw ip_addr <%s> at row <%u> is invalid\n",
-			   ip_string.s, i);
-		    goto err;
-		}
-	    }
-	    if (VAL_NULL(ROW_VALUES(row) + 2)) {
-		port = 0;
-	    } else {
-		if (VAL_TYPE(ROW_VALUES(row) + 2) != DB1_INT) {
-		    LM_ERR("lcr_gw port at row <%u> is not int\n", i);
-		    goto err;
-		}
-		port = (unsigned int)VAL_INT(ROW_VALUES(row) + 2);
-	    }
-	    if (port > 65536) {
-		LM_ERR("lcr_gw port <%d> at row <%u> is too large\n", port, i);
-		goto err;
-	    }
-	    if (VAL_NULL(ROW_VALUES(row) + 3)) {
-		scheme = SIP_URI_T;
-	    } else {
-		if (VAL_TYPE(ROW_VALUES(row) + 3) != DB1_INT) {
-		    LM_ERR("lcr_gw uri scheme at row <%u> is not int\n", i);
-		    goto err;
-		}
-		scheme = (uri_type)VAL_INT(ROW_VALUES(row) + 3);
-	    }
-	    if ((scheme != SIP_URI_T) && (scheme != SIPS_URI_T)) {
-		LM_ERR("lcr_gw has unknown or unsupported URI scheme <%u> at "
-		       "row <%u>\n", (unsigned int)scheme, i);
-		goto err;
-	    }
-	    if (VAL_NULL(ROW_VALUES(row) + 4)) {
-		transport = PROTO_NONE;
-	    } else {
-		if (VAL_TYPE(ROW_VALUES(row) + 4) != DB1_INT) {
-		    LM_ERR("lcr_gw transport at row <%u> is not int\n", i);
-		    goto err;
-		}
-		transport = (uri_transport)VAL_INT(ROW_VALUES(row) + 4);
-	    }
-	    if ((transport != PROTO_UDP) && (transport != PROTO_TCP) &&
-		(transport != PROTO_TLS) && (transport != PROTO_SCTP) &&
-		(transport != PROTO_NONE)) {
-		LM_ERR("lcr_gw has unknown or unsupported transport <%u> at "
-		       " row <%u>\n", (unsigned int)transport, i);
-		goto err;
-	    }
-	    if ((scheme == SIPS_URI_T) && (transport == PROTO_UDP)) {
-		LM_ERR("lcr_gw has wrong transport <%u> for SIPS URI "
-		       "scheme at row <%u>\n", transport, i);
-		goto err;
-	    }
-	    if (VAL_NULL(ROW_VALUES(row) + 5)) {
-		params_len = 0;
-		params = (char *)0;
-	    } else {
-		if (VAL_TYPE(ROW_VALUES(row) + 5) != DB1_STRING) {
-		    LM_ERR("lcr_gw params at row <%u> is not string\n", i);
-		    goto err;
-		}
-		params = (char *)VAL_STRING(ROW_VALUES(row) + 5);
-		params_len = strlen(params);
-		if ((params_len > 0) && (params[0] != ';')) {
-		    LM_ERR("lcr_gw params at row <%u> does not start "
-			   "with ';'\n", i);
-		    goto err;
-		}
-	    }
-	    if (params_len > MAX_PARAMS_LEN) {
-		LM_ERR("lcr_gw params length <%u> at row <%u> it too large\n",
-		       params_len, i);
-		goto err;
-	    }
-	    if (VAL_NULL(ROW_VALUES(row) + 6)) {
-		if (ip_string.s == 0) {
-		    LM_ERR("lcr_gw gw ip_addr and hostname are both null "
-			   "at row <%u>\n", i);
-		    goto err;
-		}
-		hostname_len = 0;
-		hostname = (char *)0;
-	    } else {
-		if (VAL_TYPE(ROW_VALUES(row) + 6) != DB1_STRING) {
-		    LM_ERR("hostname at row <%u> is not string\n", i);
-		    goto err;
-		}
-		hostname = (char *)VAL_STRING(ROW_VALUES(row) + 6);
-		hostname_len = strlen(hostname);
-	    }
-	    if (hostname_len > MAX_HOST_LEN) {
-		LM_ERR("lcr_gw hostname at row <%u> it too long\n", i);
-		goto err;
-	    }
-	    if (VAL_NULL(ROW_VALUES(row) + 7)) {
-		strip = 0;
-	    } else {
-		if (VAL_TYPE(ROW_VALUES(row) + 7) != DB1_INT) {
-		    LM_ERR("lcr_gw strip count at row <%u> is not int\n", i);
-		    goto err;
-		}
-		strip = (unsigned int)VAL_INT(ROW_VALUES(row) + 7);
-	    }
-	    if (strip > MAX_USER_LEN) {
-		LM_ERR("lcr_gw strip count <%u> at row <%u> it too large\n",
-		       strip, i);
-		goto err;
-	    }
-	    if (VAL_NULL(ROW_VALUES(row) + 8)) {
-		prefix_len = 0;
-		prefix = (char *)0;
-	    } else {
-		if (VAL_TYPE(ROW_VALUES(row) + 8) != DB1_STRING) {
-		    LM_ERR("lcr_gw prefix at row <%u> is not string\n", i);
-		    goto err;
-		}
-		prefix = (char *)VAL_STRING(ROW_VALUES(row) + 8);
-		prefix_len = strlen(prefix);
-	    }
-	    if (prefix_len > MAX_PREFIX_LEN) {
-		LM_ERR("lcr_gw prefix at row <%u> it too long\n", i);
-		goto err;
-	    }
-	    if (VAL_NULL(ROW_VALUES(row) + 9)) {
-		tag_len = 0;
-		tag = (char *)0;
-	    } else {
-		if (VAL_TYPE(ROW_VALUES(row) + 9) != DB1_STRING) {
-		    LM_ERR("lcr_gw tag at row <%u> is not string\n", i);
-		    goto err;
-		}
-		tag = (char *)VAL_STRING(ROW_VALUES(row) + 9);
-		tag_len = strlen(tag);
-	    }
-	    if (tag_len > MAX_TAG_LEN) {
-		LM_ERR("lcr_gw tag at row <%u> it too long\n", i);
-		goto err;
-	    }
-	    if (VAL_NULL(ROW_VALUES(row) + 10)) {
-		flags = 0;
-	    } else {
-		if (VAL_TYPE(ROW_VALUES(row) + 10) != DB1_INT) {
-		    LM_ERR("lcr_gw flags at row <%u> is not int\n", i);
-		    goto err;
-		}
-		flags = (unsigned int)VAL_INT(ROW_VALUES(row) + 10);
-	    }
-	    gw_cnt++;
-	    if (!insert_gw(gws, gw_cnt, gw_id, gw_name, gw_name_len,
-			   scheme, &ip_addr, port,
-			   transport, params, params_len, hostname,
-			   hostname_len, ip_string.s, strip, prefix, prefix_len,
-			   tag, tag_len, flags, defunct_until)) {
-		goto err;
-	    }
+	if (!insert_gws(res, gws, &null_gw_ip_addr, &gw_cnt)) goto err;
+
+	lcr_dbf.free_result(dbh, res);
+	res = NULL;
+
+	VAL_INT(vals) = 0;
+	if (lcr_dbf.query(dbh, key_cols, op, vals, gw_cols, 1, 13, 0, &res)
+	    < 0) {
+	    LM_ERR("failed to query gw data\n");
+	    goto err;
 	}
 
+	if (RES_ROW_N(res) + 1 + gw_cnt > lcr_gw_count_param) {
+	    LM_ERR("too many gateways\n");
+	    goto err;
+	}
+
+	if (!insert_gws(res, gws, &null_gw_ip_addr, &gw_cnt)) goto err;
+
 	lcr_dbf.free_result(dbh, res);
 	res = NULL;