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
2014-06-02 21:49 GMT+02:00 LAA ornitorrinco7424@gmail.com:
Apologize. Previous message was too long. L.
El 02/06/2014 20:25, "LAA" ornitorrinco7424@gmail.com escribió:
Hi all,
Another guy strugling his mind trying to get a configuration to enable calls between WebRTC UA (JSSIP) to standard SIP UA (Twinkle or SjPhone) I've been working with the examples that were shared by Carlos Ruiz Diaz and Peter Dunkley (thanks to both).
http://www.slideshare.net/crocodilertc/webrtc-websockets http://caruizdiaz.com/2014/02/26/webrtc-kamailio/
Kamailio is not running behind NAT. I'm using rtpproxy-ng module with Kamailio 4.1.3, and Rtpengine.
I share a link with my current configuration, wich is based in Peters example, with websocket support from websocket.cfg example.
- Calls between SIP standard UA's are working OK. I have some endpoint
behind nat.
- Calls between JSIP UA's are working OK. So, websocket support is
running.
- Calls from JSIP and Twinkle are NOT WORKING OK. sip UA send's back a
488 response, and Kamailio send it back to JSSIP (Incompatible SDP).
- Calls from Twinkle to Jsip are NOT WORKING OK: Kamailio sends an
INVITE to JSIP, and it returns an error. And Kamailio sends 488 to Twinkle.
It seems as if Kamailio is not catching 488. I share a snippet of my config, and links to tcpdump captures:
https://www.dropbox.com/s/i7c9ty57oauujc4/fromws0.pcap https://www.dropbox.com/s/q3q30pgzvdoswts/kamailio.cfg https://www.dropbox.com/s/rqtjwcbgg1foaoq/tows0.pcap
What am I missing?
Best regards.
Luis.