Hi all, Another attempt,
After doing some tests, I saw that one of the problems was that was necessary to comment the following lines within the deffinition of the RELAY route:
# enable additional event routes for forwarded requests
# - serial forking, RTP relaying handling, a.s.o.
#if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
# if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
#}
At this time, all the features of my old configuration are working fine, and I can make good calls beetween standard SIP UA's and JSSIP UA's, originationg the call from both sides. I'm Using Cisco SPA3000 GW, and Twinkle and SJ Phone softphones.
But now, problems are still present with calls between JS SIP UA's. When the B side accepts the calls, Kamailio sends OK to A side, but Offering RTP/AVP instead of RTP/SAVFP, and the call is been rejected because of BAD Media Description.
Can anybody help me with this issue, please?. Here you are a snippet of my config, wich is based in the standard one, mixed with the example of Carlos Ruiz Diaz:
####### Routing Logic ########
# Main SIP request routing logic
# - processing of any incoming SIP request starts with this route
# - note: this is the same as route { ... }
request_route {
#!ifdef WITH_WEBSOCKETS
if ((($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT)
&& !(proto == WS || proto == WSS)) || $Rp == MY_MSRP_PORT) {
xlog("L_WARN", "SIP request received on $Rp\n");
sl_send_reply("403", "Forbidden");
exit;
}
#!endif
# per request initial checks
route(REQINIT);
#!ifdef WITH_WEBSOCKETS
if (nat_uac_test(64)) {
# Do NAT traversal stuff for requests from a WebSocket
# connection - even if it is not behind a NAT!
# This won't be needed in the future if Kamailio and the
# WebSocket client support Outbound and Path.
force_rport();
if (is_method("REGISTER")) {
fix_nated_register();
} else {
if (!add_contact_alias()) {
xlog("L_ERR", "Error aliasing contact <$ct>\n");
sl_send_reply("400", "Bad Request");
exit;
}
}
}
#!endif
# NAT detection
route(NATDETECT);
# CANCEL processing
if (is_method("CANCEL"))
{
if (t_check_trans()) {
route(RELAY);
}
exit;
}
# handle requests within SIP dialogs
route(WITHINDLG);
### only initial requests (no To tag)
t_check_trans();
# authentication
route(AUTH);
# record routing for dialog forming requests (in case they are routed)
# - remove preloaded route headers
remove_hf("Route");
if (is_method("INVITE|SUBSCRIBE"))
record_route();
# account only INVITEs
if (is_method("INVITE"))
{
setflag(FLT_ACC); # do accounting
#!ifdef WITH_CPL
if(!cpl_run_script("incoming","is_stateful"))
{
# script execution failed
t_reply("500","CPL script execution failed");
};
#!endif
}
# dispatch requests to foreign domains
route(SIPOUT);
### requests for my local domains
# handle presence related requests
route(PRESENCE);
# handle registrations
route(REGISTRAR);
if ($rU==$null)
{
# request with no Username in RURI
sl_send_reply("484","Address Incomplete");
exit;
}
#if (!is_method("INVITE")) {
#route(RELAY);
#exit;
#}
if (!is_method("INVITE")) {
route(RELAY);
exit;
}
# user location service
route(LOCATION);
}
#!ifdef WITH_WEBRTCGW
route[SETUP_BY_TRANSPORT] {
if ($ru =~ "transport=ws") {
xlog("L_INFO", "Request going to WS");
rtpproxy_manage("froc+SP");
t_on_reply("REPLY_FROM_WS");
}
else if ($proto =~ "ws") {
xlog("L_INFO", "Request coming from WS");
rtpproxy_manage("froc-sp");
t_on_reply("REPLY_TO_WS");
}
else {
xlog("L_INFO", "This is a classic phone call");
rtpproxy_manage("co");
t_on_reply("MANAGE_CLASSIC_REPLY");
}
}
#!endif
route[RELAY] {
#!ifdef WITH_WEBRTCGW
route(SETUP_BY_TRANSPORT);
#!endif
# enable additional event routes for forwarded requests
# - serial forking, RTP relaying handling, a.s.o.
#if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
# if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
#}
if (is_method("INVITE|SUBSCRIBE|UPDATE")) {
if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY");
}
if (is_method("INVITE")) {
if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE");
}
if (!t_relay()) {
sl_reply_error();
}
exit;
}
# Per SIP request initial checks
route[REQINIT] {
#!ifdef WITH_ANTIFLOOD
# flood dection from same IP and traffic ban for a while
# be sure you exclude checking trusted peers, such as pstn gateways
# - local host excluded (e.g., loop to self)
if(src_ip!=myself)
{
if($sht(ipban=>$si)!=$null)
{
# ip is already blocked
xdbg("request from blocked IP - $rm from $fu (IP:$si:$sp)\n");
exit;
}
if (!pike_check_req())
{
xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)\n");
$sht(ipban=>$si) = 1;
exit;
}
}
#!endif
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483","Too Many Hops");
exit;
}
if(!sanity_check("1511", "7"))
{
xlog("Malformed SIP message from $si:$sp\n");
exit;
}
}
# Handle requests within SIP dialogs
route[WITHINDLG] {
if (has_totag()) {
# sequential request withing a dialog should
# take the path determined by record-routing
if (loose_route()) {
#!ifdef WITH_WEBSOCKETS
if ($du == "") {
if (!handle_ruri_alias()) {
xlog("L_ERR", "Bad alias <$ru>\n");
sl_send_reply("400", "Bad Request");
exit;
}
}
#!endif
route(DLGURI);
if (is_method("BYE")) {
setflag(FLT_ACC); # do accounting ...
setflag(FLT_ACCFAILED); # ... even if the transaction fails
}
else if ( is_method("ACK") ) {
# ACK is forwarded statelessy
route(NATMANAGE);
}
else if ( is_method("NOTIFY") ) {
# Add Record-Route for in-dialog NOTIFY as per RFC 6665.
record_route();
}
route(RELAY);
} else {
if (is_method("SUBSCRIBE") && uri == myself) {
# in-dialog subscribe requests
route(PRESENCE);
exit;
}
if ( is_method("ACK") ) {
if ( t_check_trans() ) {
# no loose-route, but stateful ACK;
# must be an ACK after a 487
# or e.g. 404 from upstream server
route(RELAY);
exit;
} else {
# ACK without matching transaction ... ignore and discard
exit;
}
}
sl_send_reply("404","Not here");
}
exit;
}
}
# Handle SIP registrations
route[REGISTRAR] {
if (is_method("REGISTER"))
{
#!ifdef WITH_CPL
cpl_process_register();
#!endif
if(isflagset(FLT_NATS))
{
setbflag(FLB_NATB);
# uncomment next line to do SIP NAT pinging
## setbflag(FLB_NATSIPPING);
}
if (!save("location"))
sl_reply_error();
exit;
}
}
# USER location service
route[LOCATION] {
#!ifdef WITH_SPEEDDIAL
# search for short dialing - 2-digit extension
if($rU=~"^[0-9][0-9]$")
if(sd_lookup("speed_dial"))
route(SIPOUT);
#!endif
#!ifdef WITH_ALIASDB
# search in DB-based aliases
if(alias_db_lookup("dbaliases"))
route(SIPOUT);
#!endif
$avp(oexten) = $rU;
if (!lookup("location")) {
$var(rc) = $rc;
route(TOVOICEMAIL);
t_newtran();
switch ($var(rc)) {
case -1:
case -3:
send_reply("404", "Not Found");
exit;
case -2:
send_reply("405", "Method Not Allowed");
exit;
}
}
# when routing via usrloc, log the missed calls also
if (is_method("INVITE"))
{
setflag(FLT_ACCMISSED);
}
route(RELAY);
exit;
}
# Presence server route
route[PRESENCE] {
if(!is_method("PUBLISH|SUBSCRIBE"))
return;
if(is_method("SUBSCRIBE") && $hdr(Event)=="message-summary") {
route(TOVOICEMAIL);
# returns here if no voicemail server is configured
sl_send_reply("404", "No voicemail service");
exit;
}
#!ifdef WITH_PRESENCE
if (!t_newtran())
{
sl_reply_error();
exit;
}
if(is_method("PUBLISH"))
{
handle_publish();
t_release();
} else if(is_method("SUBSCRIBE")) {
handle_subscribe();
t_release();
}
exit;
#!endif
# if presence enabled, this part will not be executed
if (is_method("PUBLISH") || $rU==$null)
{
sl_send_reply("404", "Not here");
exit;
}
return;
}
# Authentication route
route[AUTH] {
#!ifdef WITH_AUTH
#!ifdef WITH_IPAUTH
if((!is_method("REGISTER")) && allow_source_address())
{
# source IP allowed
return;
}
#!endif
if (is_method("REGISTER") || from_uri==myself)
{
# authenticate requests
if (!auth_check("$fd", "subscriber", "1")) {
auth_challenge("$fd", "0");
exit;
}
# user authenticated - remove auth header
if(!is_method("REGISTER|PUBLISH"))
consume_credentials();
}
# if caller is not local subscriber, then check if it calls
# a local destination, otherwise deny, not an open relay here
if (from_uri!=myself && uri!=myself)
{
sl_send_reply("403","Not relaying");
exit;
}
#!endif
return;
}
# Caller NAT detection route
route[NATDETECT] {
#!ifdef WITH_NAT
force_rport();
if (nat_uac_test("19")) {
if (is_method("REGISTER")) {
fix_nated_register();
} else {
if(is_first_hop())
set_contact_alias();
}
setflag(FLT_NATS);
}
#!endif
return;
}
# RTPProxy control
route[NATMANAGE] {
#!ifdef WITH_NAT
if (is_request()) {
if(has_totag()) {
if(check_route_param("nat=yes")) {
setbflag(FLB_NATB);
}
}
}
if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB)))
return;
#rtpproxy_manage("co");
if (is_request()) {
if (!has_totag()) {
if(t_is_branch_route()) {
add_rr_param(";nat=yes");
}
}
}
if (is_reply()) {
if(isbflagset(FLB_NATB)) {
if(is_first_hop())
set_contact_alias();
#add_contact_alias();
}
}
#!endif
return;
}
# URI update for dialog requests
route[DLGURI] {
#!ifdef WITH_NAT
if(!isdsturiset()) {
handle_ruri_alias();
}
#!endif
return;
}
# Routing to foreign domains
route[SIPOUT] {
if (!uri==myself)
{
append_hf("P-hint: outbound\r\n");
route(RELAY);
}
}
# XMLRPC routing
#!ifdef WITH_XMLRPC
route[XMLRPC] {
# allow XMLRPC from localhost
if ((method=="POST" || method=="GET")
&& (src_ip==127.0.0.1)) {
# close connection only for xmlrpclib user agents (there is a bug in
# xmlrpclib: it waits for EOF before interpreting the response).
if ($hdr(User-Agent) =~ "xmlrpclib")
set_reply_close();
set_reply_no_connect();
dispatch_rpc();
exit;
}
send_reply("403", "Forbidden");
exit;
}
#!endif
# route to voicemail server
route[TOVOICEMAIL] {
#!ifdef WITH_VOICEMAIL
if(!is_method("INVITE|SUBSCRIBE"))
return;
# check if VoiceMail server IP is defined
if (strempty($sel(cfg_get.voicemail.srv_ip))) {
xlog("SCRIPT: VoiceMail rotuing enabled but IP not defined\n");
return;
}
if(is_method("INVITE")) {
if($avp(oexten)==$null)
return;
$ru = "sip:" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip)
+ ":" + $sel(cfg_get.voicemail.srv_port);
} else {
if($rU==$null)
return;
$ru = "sip:" + $rU + "@" + $sel(cfg_get.voicemail.srv_ip)
+ ":" + $sel(cfg_get.voicemail.srv_port);
}
route(RELAY);
exit;
#!endif
return;
}
# manage outgoing branches
branch_route[MANAGE_BRANCH] {
xdbg("new branch [$T_branch_idx] to $ru\n");
route(NATMANAGE);
}
# manage incoming replies
onreply_route[MANAGE_REPLY] {
xdbg("incoming reply\n");
if(status=~"[12][0-9][0-9]")
route(NATMANAGE);
}
# manage failure routing cases
failure_route[MANAGE_FAILURE] {
route(NATMANAGE);
if (t_is_canceled()) {
exit;
}
#!ifdef WITH_BLOCK3XX
# block call redirect based on 3xx replies.
if (t_check_status("3[0-9][0-9]")) {
t_reply("404","Not found");
exit;
}
#!endif
#################################################
#Desvío a buzón de voz si ocupado o no contesta
if (t_check_status("486|408")) {
remove_hf("P-App-Name");
append_hf("P-App-Name: voicemail\r\n");
$var(usr_voicemail) = "voicemail" + $rU;
append_hf("P-App-Param: mod=box;usr=$var(usr_voicemail);dom=
sipproxy.a.com;uid=$var(usr_voicemail);did=
sipproxy.a.com;\r\n");
$ru = "sip:" + $var(usr_voicemail) + "@" + "
192.168.0.197:5080";
$du = $null;
route(RELAY);
exit;
}
#################################################
#!ifdef WITH_VOICEMAIL
# serial forking
# - route to voicemail on busy or no answer (timeout)
if (t_check_status("486|408")) {
$du = $null;
route(TOVOICEMAIL);
exit;
}
#!endif
}
#!ifdef WITH_WEBSOCKETS
onreply_route {
if ((($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT)
&& !(proto == WS || proto == WSS)) || $Rp == MY_MSRP_PORT) {
xlog("L_WARN", "SIP response received on $Rp\n");
drop;
exit;
}
if (nat_uac_test(64)) {
# Do NAT traversal stuff for replies to a WebSocket connection
# - even if it is not behind a NAT!
# This won't be needed in the future if Kamailio and the
# WebSocket client support Outbound and Path.
add_contact_alias();
}
}
event_route[xhttp:request] {
set_reply_close();
set_reply_no_connect();
if ($Rp != MY_WS_PORT
#!ifdef WITH_TLS
&& $Rp != MY_WSS_PORT
#!endif
) {
xlog("L_WARN", "HTTP request received on $Rp\n");
xhttp_reply("403", "Forbidden", "", "");
exit;
}
xlog("L_DBG", "HTTP Request Received\n");
if ($hdr(Upgrade)=~"websocket"
&& $hdr(Connection)=~"Upgrade"
&& $rm=~"GET") {
# Validate Host - make sure the client is using the correct
# alias for WebSockets
if ($hdr(Host) == $null || !is_myself("sip:" + $hdr(Host))) {
xlog("L_WARN", "Bad host $hdr(Host)\n");
xhttp_reply("403", "Forbidden", "", "");
exit;
}
# Optional... validate Origin - make sure the client is from an
# authorised website. For example,
#
# if ($hdr(Origin) != "
http://communicator.MY_DOMAIN"
# && $hdr(Origin) != "
https://communicator.MY_DOMAIN") {
# xlog("L_WARN", "Unauthorised client $hdr(Origin)\n");
# xhttp_reply("403", "Forbidden", "", "");
# exit;
# }
# Optional... perform HTTP authentication
# ws_handle_handshake() exits (no further configuration file
# processing of the request) when complete.
if (ws_handle_handshake())
{
# Optional... cache some information about the
# successful connection
exit;
}
}
xhttp_reply("404", "Not Found", "", "");
}
event_route[websocket:closed] {
xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
}
#!endif
#!ifdef WITH_WEBRTCGW
onreply_route[REPLY_TO_WS] {
xlog("L_INFO", "Reply from softphone: $rs");
if (t_check_status("183")) {
change_reply_status("180", "Ringing");
remove_body();
exit;
}
if(!(status=~"[12][0-9][0-9]"))
return;
rtpproxy_manage("froc+SP");
route(NATMANAGE);
}
onreply_route[REPLY_FROM_WS] {
xlog("L_INFO", "Reply from webrtc client: $rs");
if(status=~"[12][0-9][0-9]") {
rtpproxy_manage("froc-sp");
route(NATMANAGE);
}
}
onreply_route[MANAGE_CLASSIC_REPLY] {
xlog("L_INFO", "Boring reply from softphone: $rs");
if(status=~"[12][0-9][0-9]") {
rtpproxy_manage("co");
route(NATMANAGE);
}
}
#!endif