diff --git a/opensips/opensips.cfg b/opensips/opensips.cfg index 59a5e4e..e362520 100644 --- a/opensips/opensips.cfg +++ b/opensips/opensips.cfg @@ -291,11 +291,14 @@ modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo") ###################################################################### route { + # log the basic info regarding this call xlog("L_INFO", "$ci|start|recieved $oP request $rm $ou"); xlog("L_INFO", "$ci|log|source $si:$sp"); xlog("L_INFO", "$ci|log|from $fu"); xlog("L_INFO", "$ci|log|to $tu"); + # check that hop cound for this request and make sure it is under 10 + # to prevent endless loops if (!mf_process_maxfwd_header("10")) { xlog("L_WARN", "$ci|end|to many hops"); @@ -305,6 +308,10 @@ route exit; } + # this check detemines if the opensips has routed the request to itself, + # this happens because the server is the destination of the request but + # we mangle it to send it else where. When that mangeling fails and we + # still relay it then it just comes right back to us... if (src_ip==myself) { xlog("L_WARN", "$ci|end|sourced from this server"); @@ -312,6 +319,8 @@ route exit; } + # currently we dont support subscribe in whistle so to keep the noise down + # just end the request here. For options just end the request here as well. if (is_method("OPTIONS|SUBSCRIBE")) { xlog("L_NOTICE", "$ci|end|unsupported method"); @@ -321,7 +330,9 @@ route exit; } - + # if the source IP/port are in one of the server dispatch lists + # then this request originated from one of our media servers, mark it + # as such by setting flag 26 if (ds_is_in_list("$si", "$sp", "1") || ds_is_in_list("$si", "$sp", "2")) { xlog("L_INFO", "$ci|log|inception on-net"); @@ -329,11 +340,16 @@ route # Flag 26 marks the source as a on-net server setflag(26); } + # if the request source IP/port was not in any dispatcher lists + # this this originated outside our equipment (carrier, client, ect) else { xlog("L_INFO", "$ci|log|inception off-net"); } + # if the to header has a tag attached then it implies this request + # has been processed by us before (IE: a media server has added + # its tag on the to header in prior messages) if (has_totag()) { # sequential request within a dialog should @@ -342,7 +358,9 @@ route { append_hf("P-hint: rr-enforced\r\n"); - if (isflagset(26) && is_method("ACK")) + # if the request is an ACK from our media servers with a IP in the from domain + # then bump the association + if ($(fd{ip.isip}) && isflagset(26) && is_method("ACK")) { xlog("L_INFO", "$ci|log|maintaining contact association to media server $fd"); @@ -373,6 +391,8 @@ route } } + # request with a to tag that cant be routed loosly and is not an ACK + # ignor eand discard xlog("L_WARN", "$ci|end|could not route in dialog"); sl_send_reply("486", "PC Load Letter"); @@ -380,7 +400,7 @@ route exit; } - # CANCEL processing + # if the request is to cancel a transaction process it now if (is_method("CANCEL")) { # If this cancel is part of a transaction @@ -391,6 +411,8 @@ route route(1); } + # if the cancel does not belong to a known transaction or a + # request that has not progressed outside this server dont relay it else { xlog("L_NOTICE", "$ci|end|no matching transaction"); @@ -403,7 +425,9 @@ route # and do standard processing of the message t_check_trans(); - # preloaded route checking + # Except for an ACK no request should have a route set with no to tag, this would + # indicate that the intial request has the Route headers and is likely someone trying + # to get us to send the request were they want if (loose_route()) { if (!is_method("ACK")) @@ -416,8 +440,12 @@ route } } + # If the request is a register we will pass it along but we need + # to add the path header (along with the received IP/port info) if (is_method("REGISTER")) { + # if we fail to add the path header then dont let it + # register because it will cause issues later... if (!add_path_received()) { xlog("L_ERR", "$ci|end|unable to add path"); @@ -430,19 +458,21 @@ route xlog("L_INFO", "$ci|log|added path"); } - # is from media servers + # if the request is from on of our media servers then dont change the routing if (isflagset(26)) { xlog("L_INFO", "$ci|log|originated from internal source"); } - # not from media severs has a contact uri and is in memcache + # if the request is not from our media severs but has a contact uri in memcache + # then change the routing to go to the server previously associated with it. else if ($ct.fields(uri) && cache_fetch("memcached_callid_hash", "$(ct.fields(uri){uri.user})", $avp(i:55))) { $rd = $avp(i:55); - xlog("L_INFO", "$ci|log|contact $(ct.fields(uri){uri.user}) is associated with media server"); + xlog("L_INFO", "$ci|log|contact $(ct.fields(uri){uri.user}) is associated with media server $rd"); } - # not from media servers and call id is in memcache + # if the request is not from our media severs but has a call-id in memcache + # then change the routing to go to the server previously associated with it. else if (cache_fetch("memcached_callid_hash", "$ci", $avp(i:55))) { $rd = $avp(i:55); @@ -456,15 +486,26 @@ route cache_store("memcached_callid_hash", "$(ct.fields(uri){uri.user})", "$rd", 3600); } } - # not from media servers and no information in memcache + # if the request is not from our media servers and no associations in memcache + # then try to distribute to a media server + else if (ds_select_domain("1", "4")) + { + xlog("L_INFO", "$ci|log|routing call to arbitrary media server $rd"); + } + # if no media server could be set with ds_select_domain and there is no existing + # association then we have no way to route this call, terminate else { - ds_select_domain("1", "4"); + xlog("L_ERR", "$ci|end|no servers avaliable"); - xlog("L_INFO", "$ci|log|routing call to arbitrary media server"); + sl_send_reply("486", "All servers busy"); + + exit; } - # record routing + # for all initial request (not having been processed above in the has_totag) + # that are not a register or message add this sever to the route set on the + # request so subsequent messages come through this server if (!is_method("REGISTER|MESSAGE")) { # Record the route that this request has taken @@ -481,34 +522,52 @@ route[1] { route("nat_test_and_correct"); + # if the request domain is an IP and it exists in the list of our media servers (irregardless of the port) + # then... + # 1. remove any X-AUTH-IP headers so we will be the only one to set it + # 2. set the X-AUTH-IP header for freeswitch ACLs + # 3. set the final reply timer to two seconds, so we failover faster + # 4. arm a logging branch for replies + # 5. arm a failure branch that will try another one of our media servers when possible if ($(rd{ip.isip}) && (ds_is_in_list("$rd", "", "1") || ds_is_in_list("$rd", "", "2"))) { remove_hf("X-AUTH-IP"); + xlog("L_INFO", "$ci|log|X-AUTH-IP: $si"); + append_hf("X-AUTH-IP: $si\r\n"); + xlog("L_INFO", "$ci|log|provisional reply required in 2 seconds"); + $avp(s:final_reply_timer) = 2; t_on_reply("on_net_reply"); t_on_failure("on_net_fault"); } + # if the request domain is not an IP or in our list of media servers then + # assume it is going somewhere outside our control and give that equipment + # longer to respond. Also arm a branch to log the replies else { + xlog("L_INFO", "$ci|log|provisional reply required in 6 seconds"); + $avp(s:final_reply_timer) = 6; t_on_reply("off_net_reply"); } - if (!t_relay()) + # try to send the request on its way, if it fails send back a + # stateless error to the requestor + if (t_relay()) { - xlog("L_ERR", "$ci|end|unable to relay message"); - - sl_reply_error(); + xlog("L_INFO", "$ci|pass|$rd"); } else { - xlog("L_INFO", "$ci|pass|$rd"); + xlog("L_ERR", "$ci|end|unable to relay message"); + + sl_reply_error(); } exit; @@ -516,33 +575,40 @@ route[1] route[nat_test_and_correct] { + # check if the request is from a client behind NAT, and fix if so... + # this check looks at: + # 1. if client has a private IP address (as defined by RFC1918) in the Contact field of the SIP message + # 2. if client has contacted OpenSIPS from an address that is different from the one in the Via field if (client_nat_test("3")) { xlog("L_INFO", "$ci|log|via address differs from source or RFC1918 address in contact"); + # adds the rport parameter to the first Via header force_rport(); - #xlog("L_INFO", "$ci|log|forced rport"); - + # will replace the IP and port in the Contact header with the IP and port + # the SIP message was received from fix_contact(); - - #xlog("L_INFO", "$ci|log|fixed contact"); } + # if the request has a body see if it needs NAT corrections as well, + # this check looks at: + # 8. SDP is searched for occurrence of RFC1918 addresses if (has_body("application/sdp") && nat_uac_test("8")) { xlog("L_INFO", "$ci|log|SDP contains a RFC1918 address"); - #xlog("L_INFO", "$ci|log|rewrite SDP connection data with source address"); - - #xlog("L_INFO", "$ci|log|rewrite SDP origin with source address "); - + # alters the SDP information in order to facilitate NAT traversal. + # 2. rewrite media IP address (c=) with source IP + # 8. rewrite IP from origin description (o=) with source IP fix_nated_sdp("10"); } } onreply_route[off_net_reply] { + # this branch handles replies that are comming from equipment + # outside our control, just logging and NAT corrections xlog("L_INFO", "$ci|start|recieved off-net reply $rs $rr"); xlog("L_INFO", "$ci|log|source $si:$sp"); @@ -553,11 +619,16 @@ onreply_route[off_net_reply] onreply_route[on_net_reply] { + # this branch handles replies that are comming from our + # media server, just logging and NAT corrections xlog("L_INFO", "$ci|start|recieved on-net reply $rs $rr"); xlog("L_INFO", "$ci|log|source $si:$sp"); route("nat_test_and_correct"); + # if one of our media servers has replied with a 407 or 401 associate + # this call-id with that media server so the next "initial" requests + # go to it (IE: the reply to the challenge) if (t_check_status("(407)|(401)")) { cache_store("memcached_callid_hash", "$ci ", "$si", 60); @@ -570,6 +641,8 @@ onreply_route[on_net_reply] failure_route[on_net_fault] { + # if the failure cause was due to the transaction being + # cancelled then we are complete if (t_was_cancelled()) { xlog("L_INFO", "$ci|end|transaction was cancelled"); @@ -577,6 +650,8 @@ failure_route[on_net_fault] exit; } + # if the failure case was soemthing that we should recover + # from then try to find a new media server if (t_check_status("(408)|(5[0-9][0-9])")) { xlog("L_INFO", "$ci|start|recieved or generated negative reply"); @@ -584,12 +659,24 @@ failure_route[on_net_fault] xlog("L_ERR", "$ci|log|moving media server $rd to probing mode"); + # flag the media server that failed and start sending SIP pings + # when it begins responding put it back in the lsit ds_mark_dst("p"); - if(ds_select_domain("1", "4")) + # keep track of the original request domain so we can detemine + # if ds_select_domain chooses the same domain... + $avp(s:old_rd)=$rd; + + # try to find a new media server to send the calls to, this is + # taking advantage of a bug since ds_select_domain is not supposed + # to be using in the failover branch (but it is necessary in our + # configuration). + if(ds_select_domain("1", "4") && $avp(s:old_rd) != $rd) { - xlog("L_INFO", "$ci|log|routing call to arbitrary media server"); + xlog("L_INFO", "$ci|log|routing call to arbitrary media server $rd"); + # if the request has a contact and is an INVITE then store the new + # association if ($ct.fields(uri) && is_method("INVITE")) { xlog("L_INFO", "$ci|log|associated contact $(ct.fields(uri){uri.user}) with media server $rd"); @@ -599,11 +686,15 @@ failure_route[on_net_fault] xlog("L_INFO", "$ci|pass|$rd"); + # reset the final reply timer $avp(s:final_reply_timer) = 2; + # relay the request to the new media server t_relay(); exit; } + + xlog("L_ERR", "$ci|end|no other media servers avaliable"); } }