[OpenSIPS-Users] Problems using OpenSIPS as a load balancer for asterisk gateways

Alejandro Recarey alexrecarey at gmail.com
Tue Jun 7 17:38:54 CEST 2011


Hello all,

I am currently running 2 opensips, one for "inbound" calls and one
for "outbound". My inbound OpenSIPS handles registrations and load
balances the calls over asterisk gateways. The "outbound" opensips
just proxies outbound calls for the VoIP operators who wish to receive
all calls from the same IP address.

I am trying to migrate customers from registering directly on my asterisk
boxes and manually "load balancing" them between servers to registering
in my opensips box and using opensips to load balance calls between
asterisk servers. However, I am having some problems which are impeding
my migration.


I am getting the following logs in my inbound OpenSIPS instalation:

Jun  7 17:09:12 c1opsip1 opensips[6365]: ERROR:core:parse_msg: message=<>
Jun  7 17:09:12 c1opsip1 opensips[6365]: ERROR:core:receive_msg:
parse_msg failed
Jun  7 17:09:12 c1opsip1 opensips[6367]: INFO:core:parse_first_line:
method not followed by SP
Jun  7 17:09:12 c1opsip1 opensips[6367]: INFO:core:parse_first_line:
bad message
Jun  7 17:09:12 c1opsip1 opensips[6367]: ERROR:core:parse_msg: message=<>
Jun  7 17:09:12 c1opsip1 opensips[6367]: ERROR:core:receive_msg:
parse_msg failed
Jun  7 17:09:12 c1opsip1 opensips[6367]: INFO:core:parse_first_line:
empty  or bad first line
Jun  7 17:09:12 c1opsip1 opensips[6367]: INFO:core:parse_first_line:
bad message
Jun  7 17:09:12 c1opsip1 opensips[6367]: ERROR:core:parse_msg: message=<>
Jun  7 17:09:12 c1opsip1 opensips[6367]: ERROR:core:receive_msg:
parse_msg failed
Jun  7 17:09:12 c1opsip1 opensips[6367]: ERROR:core:parse_first_line:
bad request first line
Jun  7 17:09:12 c1opsip1 opensips[6369]: INFO:core:parse_first_line:
empty  or bad first line
Jun  7 17:09:12 c1opsip1 opensips[6371]: INFO:core:parse_first_line:
empty  or bad first line
Jun  7 17:09:12 c1opsip1 opensips[6365]: INFO:core:parse_first_line:
empty  or bad first line
Jun  7 17:09:12 c1opsip1 opensips[6367]: ERROR:core:parse_first_line:
at line 0 char 10:
Jun  7 17:09:12 c1opsip1 opensips[6369]: INFO:core:parse_first_line:
bad message
Jun  7 17:09:12 c1opsip1 opensips[6371]: INFO:core:parse_first_line:
bad message
Jun  7 17:09:12 c1opsip1 opensips[6365]: INFO:core:parse_first_line:
bad message
Jun  7 17:09:12 c1opsip1 opensips[6367]: ERROR:core:parse_first_line:
parsed so far: � ��oC"x%
Jun  7 17:09:12 c1opsip1 opensips[6369]: ERROR:core:parse_msg: message=<>
Jun  7 17:09:12 c1opsip1 opensips[6371]: ERROR:core:parse_msg: message=<>
Jun  7 17:09:12 c1opsip1 opensips[6365]: ERROR:core:parse_msg: message=<>

It is installed on CentOS and the version is 1.6.2.

Obviously I am worried at receiving so many errors in my OpenSIPS logs,
but my outbound OpenSIPS installation does not show these errors.

Of course, this new OpenSIPS is intalled to load balance inbound calls
between my asterisk gateways, so it must handle registrations, while
the other OpenSIPS does not handle registrations, just proxies outbound
calls.

I am having various problems with my "inbound" OpenSIPS and I believe they
might be related to the errors I am receiving in my log.

For example, most of the times calls work perfectly, but asterisk is
the one who records the cdrs, and sometimes I get calls where
"duration" is over 300 seconds, but "billsec" is 0. This never happened
when customers registered directly to the asterisk server, and I suppose
it means that somehow asterisk did not get the "BYE" message and did
not use RTP to detect the end of the call, as it ususaly does.

I have some more information if necessary and am recording all SIP
packets to match them to the calls to see what is going wrong, but
I wonder if anybody has had some experience in these issues and can
maybe tell me what I am doing wrong?

Since I am using asterisk with canreinvite=no, I am proxying the RTP
packets through my asterisk boxes. Usualy this is enough to solve
all of my NAT issues, but the problems I am having look suspiciously
like NAT issues.

Also, my location table in OpenSIPs has some entries like:

contact = 'sip:134378 at 192.168.1.100:5074',

That is a private IP! Does OpenSIPS not store the public IP anywhere?

This is my asterisk configuration for the peer that represents my
OpenSIPS.

[voip-41]
type=peer
host=XXX.XXX.XXX.41
disallow=all
allow=g729
allow=gsm
allow=alaw
canreinvite=no
quality=yes
context=opensips
insecure=invite,port
nat=yes


This is my opensips.cfg file:

########################################################################
@opensips.cfg
####### Global Parameters #########

debug=3
log_stderror=no
log_facility=LOG_LOCAL4

fork=yes
children=4

# domain aliases
alias=sip.voip.com:5060

/* uncomment the following lines to enable debugging */
#debug=6
#log_stderror=yes

/* uncomment the next line to disable TCP (default on) */
#disable_tcp=yes

/* uncomment the next line to enable the auto temporary blacklisting of
   not available destinations (default disabled) */
#disable_dns_blacklist=no

/* uncomment the next line to enable IPv6 lookup after IPv4 dns
   lookup failures (default disabled) */
#dns_try_ipv6=yes

/* uncomment the next line to disable the auto discovery of local aliases
   based on revers DNS on IPs (default on) */
auto_aliases=no


port=5060



####### Modules Section ########

#set module path
mpath="/usr/lib/opensips/modules/"

/* uncomment next line for MySQL DB support */
loadmodule "db_mysql.so"
loadmodule "signaling.so"
loadmodule "sl.so"
loadmodule "tm.so"
loadmodule "rr.so"
loadmodule "maxfwd.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "textops.so"
loadmodule "mi_fifo.so"
loadmodule "uri.so"
loadmodule "xlog.so"
loadmodule "acc.so"
/* uncomment next lines for MySQL based authentication support
   NOTE: a DB (like db_mysql) module must be also loaded */
loadmodule "auth.so"
loadmodule "auth_db.so"
/* uncomment next line for aliases support
   NOTE: a DB (like db_mysql) module must be also loaded */
#loadmodule "alias_db.so"
/* uncomment next line for multi-domain support
   NOTE: a DB (like db_mysql) module must be also loaded
   NOTE: be sure and enable multi-domain support in all used modules
         (see "multi-module params" section ) */
#loadmodule "domain.so"
/* uncomment the next two lines for presence server support
   NOTE: a DB (like db_mysql) module must be also loaded */
#loadmodule "presence.so"
#loadmodule "presence_xml.so"
/* dialog module must be loaded for the load_balancer to work */
loadmodule "dialog.so"
/* Loadbalancing module */
loadmodule "load_balancer.so"


# ----------------- setting module-specific parameters ---------------


# ----- mi_fifo params -----
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")


# ----- rr params -----
# add value to ;lr param to cope with most of the UAs
modparam("rr", "enable_full_lr", 1)
# do not append from tag to the RR (no need for this script)
modparam("rr", "append_fromtag", 0)


# ----- registrar params -----
/* uncomment the next line not to allow more than 10 contacts per AOR */
#modparam("registrar", "max_contacts", 10)


# ----- usrloc params -----
#modparam("usrloc", "db_mode",   0)
/* uncomment the following lines if you want to enable DB persistency
   for location entries */
modparam("usrloc", "db_mode",   2)  /* db_mode2 keeps users in memory
but periodicaly syncs to db */
modparam("usrloc", "db_url","mysql://********")


# ----- uri params -----
modparam("uri", "use_uri_table", 0)


# ----- acc params -----
/* what sepcial events should be accounted ? */
modparam("acc", "early_media", 1)
modparam("acc", "report_ack", 1)
modparam("acc", "report_cancels", 1)
/* by default ww do not adjust the direct of the sequential requests.
   if you enable this parameter, be sure the enable "append_fromtag"
   in "rr" module */
modparam("acc", "detect_direction", 0)
/* account triggers (flags) */
modparam("acc", "failed_transaction_flag", 3)
modparam("acc", "log_flag", 1)
modparam("acc", "log_missed_flag", 2)
/* uncomment the following lines to enable DB accounting also */
modparam("acc", "db_flag", 1)
modparam("acc", "db_missed_flag", 2)


# ----- auth_db params -----
/* uncomment the following lines if you want to enable the DB based
   authentication */
modparam("auth_db", "calculate_ha1", yes)
modparam("auth_db", "password_column", "password")
modparam("auth_db", "db_url","mysql://********")
modparam("auth_db", "load_credentials", "")


# ----- dialog params -----
/* dialog must be enabled to make use of the load_balancer module */
modparam("dialog", "dlg_flag", 13)
modparam("dialog", "db_mode", 3) /* use db mode 3 for saving dialog
only at shutdown */
modparam("dialog", "db_url", "mysql://********")


# ----- load_balancer params -----
modparam("load_balancer", "db_url","mysql://********")


####### Routing Logic ########


# main request routing logic

route{

	if (!mf_process_maxfwd_header("10")) {
		sl_send_reply("483","Too Many Hops");
		exit;
	}

	if (has_totag()) {
		# sequential request withing a dialog should
		# take the path determined by record-routing
		if (loose_route()) {
			if (is_method("BYE")) {
				setflag(1); # do accounting ...
				setflag(3); # ... even if the transaction fails
			} else if (is_method("INVITE")) {
				# even if in most of the cases is useless, do RR for
				# re-INVITEs alos, as some buggy clients do change route set
				# during the dialog.
				record_route();
			}
			# route it out to whatever destination was set by loose_route()
			# in $du (destination URI).
			route(1);
		} else {
			if ( is_method("ACK") ) {
				if ( t_check_trans() ) {
					# non loose-route, but stateful ACK; must be an ACK after
					# a 487 or e.g. 404 from upstream server
					t_relay();
					exit;
				} else {
					# ACK without matching transaction ->
					# ignore and discard
					exit;
				}
			}
			sl_send_reply("404","Not here");
		}
		exit;
	}

	#initial requests

	# CANCEL processing
	if (is_method("CANCEL"))
	{
		if (t_check_trans())
			t_relay();
		exit;
	}

	t_check_trans();

	# authenticate if from local subscriber (uncomment to enable auth)
	# authenticate all initial non-REGISTER request that pretend to be
	# generated by local subscriber (domain from FROM URI is local)
	if (!(method=="REGISTER") && from_uri==myself) /*no multidomain version*/
	{
		if (!proxy_authorize("", "subscriber")) {
			proxy_challenge("", "0");
			exit;
		}
		if (!db_check_from()) {
			sl_send_reply("403","Forbidden auth ID");
			exit;
		}
	
		consume_credentials();
		# caller authenticated
	}

	# preloaded route checking
	if (loose_route()) {
		xlog("L_ERR",
		"Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]");
		if (!is_method("ACK"))
			sl_send_reply("403","Preload Route denied");
		exit;
	}

	# record routing
	if (!is_method("REGISTER|MESSAGE"))
		record_route();

	# account only INVITEs
	if (is_method("INVITE")) {
		setflag(1); # do accounting
	}

	if (!uri==myself)
	{
		append_hf("P-hint: outbound\r\n");
		
		# Do not act as an open relay
		#   only allow requests from handled domains
		if(from_uri==myself){
			route(1);
		}
		else {
			sl_send_reply("403", "Not here");
		}
	}

	if (is_method("PUBLISH"))
	{
		sl_send_reply("503", "Service Unavailable");
		exit;
	}
	

	if (is_method("REGISTER"))
	{

	    # Authenticate the REGISTER requests
	    # Log incorrect registrations
            $var(auth_code) = www_authorize("", "subscriber");
            if( $var(auth_code) == -1 || $var(auth_code) == -2 ) {
	        xlog("L_NOTICE","Auth error for $fU@$fd from $si cause
$var(auth_code)");
        }
        if( $var(auth_code) < 0 ) {
		    www_challenge("", "0");
		    exit;
        }


		if (!db_check_to())
		{
			sl_send_reply("403","Forbidden auth ID");
			exit;
		}

		if (!save("location"))
			sl_reply_error();

		exit;
	}

	if ($rU==NULL) {
		# request with no Username in RURI
		sl_send_reply("484","Address Incomplete");
		exit;
	}

	
	# ----  Load balance Asterisk gateways ---- #
	# if number is not 6 digits long then
	if (!uri=~"^[0-9]{6}@") {
		route(4);
		
	}
	
	
	# ---- Handle routing to local (registered) users ----#
	if (!lookup("location","m")) {
		switch ($retcode) {
			case -1:
			case -3:
				t_newtran();
				t_reply("404", "Not Found");
				exit;
			case -2:
				sl_send_reply("405", "Method Not Allowed");
				exit;
		}
	}

	# when routing via usrloc, log the missed calls also
	setflag(2);

	route(1);
}


route[1] {
	# for INVITEs enable some additional helper routes
	if (is_method("INVITE")) {
		t_on_branch("2");
		t_on_reply("2");
		t_on_failure("1");
	}

	if (!t_relay()) {
		sl_reply_error();
	};
	exit;
}


route[4] {
	
	if(load_balance("1","routing")){
		route(1);
		exit;
	}
	# if all destinations are full load_balance returns negative value
	else {
		sl_send_reply("500","Service full");
		exit;
    }
	

}

branch_route[2] {
	xlog("new branch at $ru\n");
}


onreply_route[2] {
	xlog("incoming reply\n");
}


failure_route[1] {
	if (t_was_cancelled()) {
		exit;
	}
}


Thank you so much for you're help!

Regards,

Alex



More information about the Users mailing list