Well, not the simpl5.org site itself, since it uses its own Websocket-SIP gateway to make calls. I downloaded their code and changed the gateway address from "sipml5.org" to "192.168.0.148" which is the VM where I'm testing. Also, Apache is using ports 8000 and 4443 since Kamailio uses 80 and 443.
But when I try to make a call, filling 192.168.0.48 as the realm, I get "Disconnected: Failed to connet to the server" from the call.htm page. I monitored packets with Wireshark and I see no traffic that would make sense between the machine with the browser and the one with Kamailio. I suspect I have to make more changes in the sipml5.org Javascript, am I correct?
Kamailio itself (Dev version) is up and running and normal SIP from normal UAs works. Here's the config I'm using. It's the example in the websocket module directory, just changed to use my db and the default TLS cert that was installed:
---------------------------------------------------------------------- #!KAMAILIO # # Simple/sample kamailio.cfg for running a proxy/registrar with TLS and # WebSockets support.
#!substdef "!DBURL!mysql://ser:heslo@localhost/ser!g" #!substdef "!MY_IP_ADDR!192.168.0.148!g" #!substdef "!MY_WS_PORT!80!g" #!substdef "!MY_WSS_PORT!443!g" #!substdef "!MY_WS_ADDR!tcp:MY_IP_ADDR:MY_WS_PORT!g" #!substdef "!MY_WSS_ADDR!tls:MY_IP_ADDR:MY_WSS_PORT!g"
##!define LOCAL_TEST_RUN #!define WITH_TLS #!define WITH_WEBSOCKETS
####### Global Parameters #########
fork=yes children=4
#alias="example.com"
#!ifdef WITH_TLS enable_tls=1 #!endif
listen=MY_IP_ADDR #!ifdef WITH_WEBSOCKETS listen=MY_WS_ADDR #!ifdef WITH_TLS listen=MY_WSS_ADDR #!endif #!endif
tcp_connection_lifetime=3604 tcp_accept_no_cl=yes tcp_rd_buf_size=16384
syn_branch=0 debug=2
# set paths to location of modules (to sources or installation folders) #!ifdef WITH_SRCPATH mpath="modules_k:modules" #!else mpath="/usr/local/kamailio/lib/kamailio/modules_k/:/usr/local/kamailio/lib/kamailio/modules/" #!endif
loadmodule "db_mysql.so" loadmodule "tm.so" loadmodule "sl.so" loadmodule "rr.so" loadmodule "pv.so" loadmodule "maxfwd.so" loadmodule "usrloc.so" loadmodule "registrar.so" loadmodule "textops.so" loadmodule "siputils.so" loadmodule "xlog.so" loadmodule "sanity.so" loadmodule "ctl.so" loadmodule "auth.so" loadmodule "auth_db.so" loadmodule "kex.so" loadmodule "mi_rpc.so" #!ifdef WITH_TLS loadmodule "tls.so" #!endif #!ifdef WITH_WEBSOCKETS loadmodule "xhttp.so" loadmodule "websocket.so" loadmodule "nathelper.so" #!endif
# ----------------- setting module-specific parameters ---------------
# ----- tm params ----- # auto-discard branches from previous serial forking leg modparam("tm", "failure_reply_mode", 3) # default retransmission timeout: 30sec modparam("tm", "fr_timer", 30000) # default invite retransmission timeout after 1xx: 120sec modparam("tm", "fr_inv_timer", 120000)
# ----- 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 ----- modparam("registrar", "method_filtering", 1) modparam("registrar", "max_expires", 3600) modparam("registrar", "gruu_enabled", 0)
# ----- usrloc params ----- modparam("usrloc", "db_url", "DBURL") modparam("usrloc", "db_mode", 0)
# ----- auth_db params ----- modparam("auth_db", "db_url", "DBURL") modparam("auth_db", "calculate_ha1", yes) modparam("auth_db", "password_column", "password") modparam("auth_db", "load_credentials", "")
#!ifdef WITH_TLS # ----- tls params ----- modparam("tls", "config", "/usr/local/kamailio/etc/kamailio/tls.cfg") #!endif
#!ifdef WITH_WEBSOCKETS # ----- nathelper params ----- modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)") # Note: leaving NAT pings turned off here as nathelper is _only_ being used for # WebSocket connections. NAT pings are not needed as WebSockets have # their own keep-alives. #!endif
####### 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 {
# 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
# handle requests within SIP dialogs route(WITHINDLG);
### only initial requests (no To tag)
# CANCEL processing if (is_method("CANCEL")) { if (t_check_trans()) t_relay(); exit; }
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")) record_route();
# handle registrations route(REGISTRAR);
if ($rU==$null) { # request with no Username in RURI sl_send_reply("484","Address Incomplete"); exit; }
# user location service route(LOCATION);
route(RELAY); }
route[RELAY] { if (!t_relay()) { sl_reply_error(); } exit; }
# Per SIP request initial checks route[REQINIT] { 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(RELAY); } else { 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 t_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")) { if (!save("location")) sl_reply_error();
exit; } }
# USER location service route[LOCATION] { if (!lookup("location")) { $var(rc) = $rc; t_newtran(); switch ($var(rc)) { case -1: case -3: send_reply("404", "Not Found"); exit; case -2: send_reply("405", "Method Not Allowed"); exit; } } }
# Authentication route route[AUTH] { 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")) 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; } }
#!ifdef WITH_WEBSOCKETS onreply_route { 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 && $Rp != MY_WSS_PORT) { 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") { xlog("L_DBG", "WebSocket\n"); xlog("L_DBG", " Host: $hdr(Host)\n"); xlog("L_DBG", " Origin: $hdr(Origin)\n");
if ($hdr(Host) == $null || !is_myself($hdr(Host))) { xlog("L_WARN", "Bad host $hdr(Host)\n"); xhttp_reply("403", "Forbidden", "", ""); exit; }
# Optional... validate Origin # 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 abou 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 ----------------------------------------------------------------------