######################################################################
# Route for handling Registrations:
######################################################################
route[REGISTER] {
	# Provide some statistics
        if ($sht(a=>$ci::start_time) == $null || $sht(a=>$ci::start_time) == 0) {
            $sht(a=>$ci::start_time) = $TV(Sn);
        } 

	# Strip Transport from RURI:
	$ru = $(ru{re.subst,/;transport=[A-Za-z]*//g});

	if (is_present_hf("Contact")) {
		pcscf_save_pending("location");
	} else {
		send_reply("403", "No contact header");
		exit;
	}


	# Strip additional Tags from RURI:
	if ($rU == $null)
		$ru = "sip:"+$rd;
	else
		$ru = "sip:"+$rU+"@"+$rd;

#!ifdef WITH_RX	
	xlog("L_DBG","Subscribing to signalling bearer status\n");

	Rx_AAR_Register("REG_AAR_REPLY", "location");
	switch ($retcode) {
		case -1:
			# There was an error sending the AAR-Request:
			xlog("L_ERR", "Diameter: AAR failed on subscription to signalling\n");
			send_reply("403", "Can't register to QoS for signalling");
			exit;
			break;
		case 0:
			# We are waiting for an async reply, just exit here.
			exit;
			break;
		case 1:
			# We did not need to send AAR, so just continue as normal
			route(REGISTER_CONTINUE);
			break;
	}
	exit;
}

route[REG_AAR_REPLY] {
	switch ($avp(s:aar_return_code)) {
		case 1:
			xlog("L_DBG", "Diameter: AAR success on subscription to signalling\n");
			break;
		default:
			xlog("L_ERR", "Diameter: AAR failed on subscription to signalling\n");
			send_reply("403", "Can't register to QoS for signalling");
			exit;
	}
	# Proceed with Registering:
	route(REGISTER_CONTINUE);
}

route[REGISTER_CONTINUE] {
#!endif
	append_hf("Path: <sip:term@HOSTNAME;lr>\r\n");

	remove_hf("Supported");
	append_hf("Supported: path\r\n");
	remove_hf("Require");
	append_hf("Require: path\r\n");

	# Add a visited Network-ID-Header:
	if (is_present_hf("P-Visited-Network-ID")) {
		$var(new_hdr) = "NETWORKNAME, "+$hdr(P-Visited-Network-ID);
		append_hf("P-Visited-Network-ID: $var(new_hdr)\r\n");
	} else {
		append_hf("P-Visited-Network-ID: NETWORKNAME\r\n");
	}
#!ifdef WITH_SBC
#!ifndef WITH_SBC_CALL
	t_on_failure("SBC_failure");
	# Choose an SBC to send the call to:
	if (!ds_select_dst(DISPATCHER_LIST_SBC, "4")) {
		send_reply("503", "Service Unavailable (SBC failure)");
		exit;
	}
#!else
	t_on_failure("REGISTER_failure");
#!endif
#!else
	t_on_failure("REGISTER_failure");
#!endif
	t_on_reply("REGISTER_reply");
	# Forward request:
	route(RELAY);
	exit;
}

# Replies for REGISTER requests:
######################################################################
onreply_route[REGISTER_reply]
{
#!ifdef WITH_IMS_HDR_CACHE
	if (is_present_hf("Service-Route")) {
		$sht(serviceroutes=>$ci) = $hdr(Service-Route);
	} else {
		if ($sht(serviceroutes=>$ci) != $null) {
			append_hf("Service-Route: $sht(serviceroutes=>$ci)\r\n");
			msg_apply_changes();
		}
	}
	if (is_present_hf("P-Associated-URI")) {
		$sht(associateduris=>$ci) = $hdr(P-Associated-URI);
	} else {
		if ($sht(associateduris=>$ci) != $null) {
			append_hf("P-Associated-URI: $sht(associateduris=>$ci)\r\n");
			msg_apply_changes();
		}
	}
#!endif

	if (t_check_status("200")) {
#!ifdef WITH_IPBLOCK
		$sht(failedauth=>$T_req($si)) = $null;
#!endif
		pcscf_save("location");
#!ifdef WITH_NATPING
#!ifdef WITH_PING_UDP
		if ($T_req($pr) == "udp") {
			$var(ouri) = "sip:"+$T_req($si)+":"+$T_req($sp);
			$sht(natping=>$var(ouri)) = $(T_req($ct){nameaddr.uri});
		}
#!endif
#!ifdef WITH_PING_TCP
		if ($T_req($pr) == "tcp") {
			$var(ouri) = "sip:"+$T_req($si)+":"+$T_req($sp)+";transport=tcp";
			$sht(natping=>$var(ouri)) = $(T_req($ct){nameaddr.uri});
		}
#!endif
#!ifdef WITH_PING_TLS
		if ($T_req($pr) == "tls") {
			$var(ouri) = "sip:"+$T_req($si)+":"+$T_req($sp)+";transport=tls";
			$sht(natping=>$var(ouri)) = $(T_req($ct){nameaddr.uri});
		}
#!endif
#!endif
		#update stats for register reply on success
        	$var(start_secs) = $(sht(a=>$ci::start_time){s.select,0,.});
        	$var(start_usecs) = $(sht(a=>$ci::start_time){s.select,1,.});
        	$var(diff_secs) = $TV(s) - $var(start_secs);
        	$var(diff_usecs) = $TV(u) - $var(start_usecs);
        	$var(diff_ms) = $var(diff_secs)*1000 + ($var(diff_usecs)/1000);
        	$sht(a=>$ci::start_time)=0;
        	$var(stat_add) = "+" + $var(diff_ms);
        	xlog("L_DBG", "REGISTER SUCCESS[$ci] took $var(stat_add)ms\n"); 
        	update_stat("register_success", "+1");
        	update_stat("register_time", "$var(stat_add)");
#!ifdef WITH_IPSEC
            ipsec_forward("location");
   	}
	else {  
		if (t_check_status("401")) {
			ipsec_create("location");
        }
#!endif
    }
	exit;
}

# Negative replies to REGISTER requests:
######################################################################
failure_route[REGISTER_failure]
{
#!ifdef WITH_IPBLOCK
	if (t_check_status("403|[5-6][0-9][0-9]")) {
		if ($sht(failedauth=>$si) != $null)
			$sht(failedauth=>$si) = $sht(failedauth=>$si) + 1;
		else
			$sht(failedauth=>$si) = 1;
		if ($sht(failedauth=>$si) > 10) {
			xlog("L_ALERT","ALERT: blocking $rm from $fu (IP:$si:$sp), more than 5 failed auth requests!\n");
			xlog("Blocking traffic from $si\n");
			$sht(ipban=>$si) = 1;
		}
                update_stat("register_failed", "+1");
	}
#!endif
	if (t_check_status("408")) {
		send_reply("504","Server Time-Out");
                update_stat("register_failed", "+1");
		exit;
	}
}
