Browse Source

siputils: added new function is_first_hop()

- detect if it is first hop after original sender
- added section ids for functions, remove a duplicate content for
  is_rpid_user_e164()
Daniel-Constantin Mierla 12 years ago
parent
commit
c8e928a2c7

+ 94 - 94
modules/siputils/README

@@ -40,7 +40,7 @@ Edited by
 
 
 Gabriel Vasile
 Gabriel Vasile
 
 
-   Copyright (c) 2008, 2005, 2003 1&1 Internet AG, FhG Fokus, Voice Sistem
+   Copyright © 2008, 2005, 2003 1&1 Internet AG, FhG Fokus, Voice Sistem
    SRL
    SRL
      __________________________________________________________________
      __________________________________________________________________
 
 
@@ -84,16 +84,16 @@ Gabriel Vasile
               4.14. decode_contact_header()
               4.14. decode_contact_header()
               4.15. cmp_uri(str1, str2)
               4.15. cmp_uri(str1, str2)
               4.16. cmp_aor(str1, str2)
               4.16. cmp_aor(str1, str2)
-              4.17. is_rpid_user_e164()
-              4.18. append_rpid_hf()
-              4.19. append_rpid_hf(prefix, suffix)
-              4.20. is_rpid_user_e164()
-              4.21. set_uri_user(uri, user)
-              4.22. set_uri_host(uri, host)
-              4.23. is_request()
-              4.24. is_reply()
-              4.25. is_gruu([uri])
-              4.26. is_supported(option)
+              4.17. append_rpid_hf()
+              4.18. append_rpid_hf(prefix, suffix)
+              4.19. is_rpid_user_e164()
+              4.20. set_uri_user(uri, user)
+              4.21. set_uri_host(uri, host)
+              4.22. is_request()
+              4.23. is_reply()
+              4.24. is_gruu([uri])
+              4.25. is_supported(option)
+              4.26. is_first_hop()
 
 
    List of Examples
    List of Examples
 
 
@@ -122,16 +122,16 @@ Gabriel Vasile
    1.23. decode_contact_header usage
    1.23. decode_contact_header usage
    1.24. cmp_uri usage
    1.24. cmp_uri usage
    1.25. cmp_aor usage
    1.25. cmp_aor usage
-   1.26. is_rpid_user_e164 usage
-   1.27. append_rpid_hf usage
-   1.28. append_rpid_hf(prefix, suffix) usage
-   1.29. is_rpid_user_e164 usage
-   1.30. set_uri_user usage
-   1.31. set_uri_host usage
-   1.32. is_request usage
-   1.33. is_reply usage
-   1.34. is_gruu() usage
-   1.35. is_supported() usage
+   1.26. append_rpid_hf usage
+   1.27. append_rpid_hf(prefix, suffix) usage
+   1.28. is_rpid_user_e164 usage
+   1.29. set_uri_user usage
+   1.30. set_uri_host usage
+   1.31. is_request usage
+   1.32. is_reply usage
+   1.33. is_gruu() usage
+   1.34. is_supported() usage
+   1.35. is_first_hop() usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -173,16 +173,16 @@ Chapter 1. Admin Guide
         4.14. decode_contact_header()
         4.14. decode_contact_header()
         4.15. cmp_uri(str1, str2)
         4.15. cmp_uri(str1, str2)
         4.16. cmp_aor(str1, str2)
         4.16. cmp_aor(str1, str2)
-        4.17. is_rpid_user_e164()
-        4.18. append_rpid_hf()
-        4.19. append_rpid_hf(prefix, suffix)
-        4.20. is_rpid_user_e164()
-        4.21. set_uri_user(uri, user)
-        4.22. set_uri_host(uri, host)
-        4.23. is_request()
-        4.24. is_reply()
-        4.25. is_gruu([uri])
-        4.26. is_supported(option)
+        4.17. append_rpid_hf()
+        4.18. append_rpid_hf(prefix, suffix)
+        4.19. is_rpid_user_e164()
+        4.20. set_uri_user(uri, user)
+        4.21. set_uri_host(uri, host)
+        4.22. is_request()
+        4.23. is_reply()
+        4.24. is_gruu([uri])
+        4.25. is_supported(option)
+        4.26. is_first_hop()
 
 
 1. Overview
 1. Overview
 
 
@@ -374,18 +374,18 @@ modparam("auth", "rpid_avp", "$avp(myrpid)")
    4.14. decode_contact_header()
    4.14. decode_contact_header()
    4.15. cmp_uri(str1, str2)
    4.15. cmp_uri(str1, str2)
    4.16. cmp_aor(str1, str2)
    4.16. cmp_aor(str1, str2)
-   4.17. is_rpid_user_e164()
-   4.18. append_rpid_hf()
-   4.19. append_rpid_hf(prefix, suffix)
-   4.20. is_rpid_user_e164()
-   4.21. set_uri_user(uri, user)
-   4.22. set_uri_host(uri, host)
-   4.23. is_request()
-   4.24. is_reply()
-   4.25. is_gruu([uri])
-   4.26. is_supported(option)
-
-4.1.  ring_insert_callid()
+   4.17. append_rpid_hf()
+   4.18. append_rpid_hf(prefix, suffix)
+   4.19. is_rpid_user_e164()
+   4.20. set_uri_user(uri, user)
+   4.21. set_uri_host(uri, host)
+   4.22. is_request()
+   4.23. is_reply()
+   4.24. is_gruu([uri])
+   4.25. is_supported(option)
+   4.26. is_first_hop()
+
+4.1. ring_insert_callid()
 
 
    Inserting the call-id in the internal list, which is checked when
    Inserting the call-id in the internal list, which is checked when
    further replies arrive. Any 183 reply that is received during the
    further replies arrive. Any 183 reply that is received during the
@@ -402,7 +402,7 @@ modparam("auth", "rpid_avp", "$avp(myrpid)")
 ring_insert_callid();
 ring_insert_callid();
 ...
 ...
 
 
-4.2.  options_reply()
+4.2. options_reply()
 
 
    This function checks if the request method is OPTIONS and if the
    This function checks if the request method is OPTIONS and if the
    request URI does not contain an username. If both is true the request
    request URI does not contain an username. If both is true the request
@@ -430,7 +430,7 @@ if (uri==myself) {
 }
 }
 ...
 ...
 
 
-4.3.  is_user(username)
+4.3. is_user(username)
 
 
    Check if the username in credentials matches the given username.
    Check if the username in credentials matches the given username.
 
 
@@ -446,7 +446,7 @@ if (is_user("john")) {
 };
 };
 ...
 ...
 
 
-4.4.  has_totag()
+4.4. has_totag()
 
 
    Check if To header field uri contains tag parameter.
    Check if To header field uri contains tag parameter.
 
 
@@ -459,7 +459,7 @@ if (has_totag()) {
 };
 };
 ...
 ...
 
 
-4.5.  uri_param(param)
+4.5. uri_param(param)
 
 
    Find if Request URI has a given parameter with no value
    Find if Request URI has a given parameter with no value
 
 
@@ -475,7 +475,7 @@ if (uri_param("param1")) {
 };
 };
 ...
 ...
 
 
-4.6.  uri_param(param,value)
+4.6. uri_param(param,value)
 
 
    Find if Request URI has a given parameter with matching value
    Find if Request URI has a given parameter with matching value
 
 
@@ -492,7 +492,7 @@ if (uri_param("param1","value1")) {
 };
 };
 ...
 ...
 
 
-4.7.  add_uri_param(param)
+4.7. add_uri_param(param)
 
 
    Add to RURI a parameter (name=value);
    Add to RURI a parameter (name=value);
 
 
@@ -506,7 +506,7 @@ if (uri_param("param1","value1")) {
 add_uri_param("nat=yes");
 add_uri_param("nat=yes");
 ...
 ...
 
 
-4.8.  get_uri_param(name, var)
+4.8. get_uri_param(name, var)
 
 
    Get the value of RURI parameter.
    Get the value of RURI parameter.
 
 
@@ -521,7 +521,7 @@ add_uri_param("nat=yes");
 get_uri_param("nat", "$var(nat)");
 get_uri_param("nat", "$var(nat)");
 ...
 ...
 
 
-4.9.  tel2sip(uri, hostpart, result)
+4.9. tel2sip(uri, hostpart, result)
 
 
    Converts URI in first param (pseudo variable or string) to SIP URI, if
    Converts URI in first param (pseudo variable or string) to SIP URI, if
    it is a tel URI. If conversion was done, writes resulting SIP URI to
    it is a tel URI. If conversion was done, writes resulting SIP URI to
@@ -553,7 +553,7 @@ tel2sip("$ru", $fd", "$ru");
 # $ru:  sip:+12345678;ext=200;[email protected];user=phone
 # $ru:  sip:+12345678;ext=200;[email protected];user=phone
 ...
 ...
 
 
-4.10.  is_e164(pseudo-variable)
+4.10. is_e164(pseudo-variable)
 
 
    Checks if string value of pseudo variable argument is an E164 number.
    Checks if string value of pseudo variable argument is an E164 number.
 
 
@@ -571,7 +571,7 @@ if (is_e164("$avp(i:705)") {
 };
 };
 ...
 ...
 
 
-4.11.  is_uri_user_e164(pseudo-variable)
+4.11. is_uri_user_e164(pseudo-variable)
 
 
    Checks if userpart of URI stored in pseudo variable is E164 number.
    Checks if userpart of URI stored in pseudo variable is E164 number.
 
 
@@ -588,7 +588,7 @@ if (is_uri_user_e164("$avp(i:705)") {
 };
 };
 ...
 ...
 
 
-4.12.  encode_contact(encoding_prefix,hostpart)
+4.12. encode_contact(encoding_prefix,hostpart)
 
 
    This function will encode uri-s inside Contact header in the following
    This function will encode uri-s inside Contact header in the following
    manner sip:username:password@ip:port;transport=protocol goes
    manner sip:username:password@ip:port;transport=protocol goes
@@ -615,7 +615,7 @@ if (is_uri_user_e164("$avp(i:705)") {
 if (src_ip == 10.0.0.0/8) encode_contact("natted_client","1.2.3.4");
 if (src_ip == 10.0.0.0/8) encode_contact("natted_client","1.2.3.4");
 ...
 ...
 
 
-4.13.  decode_contact()
+4.13. decode_contact()
 
 
    This function will decode the request URI. If the RURI is in the format
    This function will decode the request URI. If the RURI is in the format
    sip:encoding_prefix*username*ip*port*protocol@hostpart it will be
    sip:encoding_prefix*username*ip*port*protocol@hostpart it will be
@@ -633,7 +633,7 @@ if (src_ip == 10.0.0.0/8) encode_contact("natted_client","1.2.3.4");
 if (uri =~ "^sip:natted_client") { decode_contact(); }
 if (uri =~ "^sip:natted_client") { decode_contact(); }
 ...
 ...
 
 
-4.14.  decode_contact_header()
+4.14. decode_contact_header()
 
 
    This function will decode URIs inside Contact header. If the URI in the
    This function will decode URIs inside Contact header. If the URI in the
    format sip:encoding_prefix*username*ip*port*protocol@hostpart it will
    format sip:encoding_prefix*username*ip*port*protocol@hostpart it will
@@ -655,7 +655,7 @@ reply_route[2] {
 }
 }
 ...
 ...
 
 
-4.15.  cmp_uri(str1, str2)
+4.15. cmp_uri(str1, str2)
 
 
    The function returns true if the two parameters matches as SIP URI.
    The function returns true if the two parameters matches as SIP URI.
 
 
@@ -669,7 +669,7 @@ if(cmp_uri("$ru", "sip:[email protected]"))
 }
 }
 ...
 ...
 
 
-4.16.  cmp_aor(str1, str2)
+4.16. cmp_aor(str1, str2)
 
 
    The function returns true if the two parameters matches as AoR. The
    The function returns true if the two parameters matches as AoR. The
    parameters have to be SIP URIs.
    parameters have to be SIP URIs.
@@ -684,24 +684,7 @@ if(cmp_aor("[email protected]", "sip:kamailio@$fd"))
 }
 }
 ...
 ...
 
 
-4.17.  is_rpid_user_e164()
-
-   The function checks if the SIP URI received from the database or radius
-   server and will potentially be used in Remote-Party-ID header field
-   contains an E164 number (+followed by up to 15 decimal digits) in its
-   user part. Check fails, if no such SIP URI exists (i.e. radius server
-   or database didn't provide this information).
-
-   This function can be used from REQUEST_ROUTE.
-
-   Example 1.26. is_rpid_user_e164 usage
-...
-if (is_rpid_user_e164()) {
-    # do something here
-};
-...
-
-4.18.  append_rpid_hf()
+4.17. append_rpid_hf()
 
 
    Appends to the message a Remote-Party-ID header that contains header
    Appends to the message a Remote-Party-ID header that contains header
    'Remote-Party-ID: ' followed by the saved value of the SIP URI received
    'Remote-Party-ID: ' followed by the saved value of the SIP URI received
@@ -712,14 +695,14 @@ if (is_rpid_user_e164()) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE.
    BRANCH_ROUTE.
 
 
-   Example 1.27. append_rpid_hf usage
+   Example 1.26. append_rpid_hf usage
 ...
 ...
 append_rpid_hf();  # Append Remote-Party-ID header field
 append_rpid_hf();  # Append Remote-Party-ID header field
 ...
 ...
 
 
-4.19.  append_rpid_hf(prefix, suffix)
+4.18. append_rpid_hf(prefix, suffix)
 
 
-   This function is the same as Section 4.18, " append_rpid_hf()". The
+   This function is the same as Section 4.17, " append_rpid_hf()". The
    only difference is that it accepts two parameters--prefix and suffix to
    only difference is that it accepts two parameters--prefix and suffix to
    be added to Remote-Party-ID header field. This function ignores
    be added to Remote-Party-ID header field. This function ignores
    rpid_prefix and rpid_suffix parameters, instead of that allows to set
    rpid_prefix and rpid_suffix parameters, instead of that allows to set
@@ -736,13 +719,13 @@ append_rpid_hf();  # Append Remote-Party-ID header field
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE.
    BRANCH_ROUTE.
 
 
-   Example 1.28. append_rpid_hf(prefix, suffix) usage
+   Example 1.27. append_rpid_hf(prefix, suffix) usage
 ...
 ...
 # Append Remote-Party-ID header field
 # Append Remote-Party-ID header field
 append_rpid_hf("", ";party=calling;id-type=subscriber;screen=yes");
 append_rpid_hf("", ";party=calling;id-type=subscriber;screen=yes");
 ...
 ...
 
 
-4.20.  is_rpid_user_e164()
+4.19. is_rpid_user_e164()
 
 
    The function checks if the SIP URI received from the database or radius
    The function checks if the SIP URI received from the database or radius
    server and will potentially be used in Remote-Party-ID header field
    server and will potentially be used in Remote-Party-ID header field
@@ -752,68 +735,68 @@ append_rpid_hf("", ";party=calling;id-type=subscriber;screen=yes");
 
 
    This function can be used from REQUEST_ROUTE.
    This function can be used from REQUEST_ROUTE.
 
 
-   Example 1.29. is_rpid_user_e164 usage
+   Example 1.28. is_rpid_user_e164 usage
 ...
 ...
 if (is_rpid_user_e164()) {
 if (is_rpid_user_e164()) {
     # do something here
     # do something here
 };
 };
 ...
 ...
 
 
-4.21.  set_uri_user(uri, user)
+4.20. set_uri_user(uri, user)
 
 
    Sets userpart of SIP URI stored in writable pseudo variable 'uri' to
    Sets userpart of SIP URI stored in writable pseudo variable 'uri' to
    value of pseudo variable 'user'.
    value of pseudo variable 'user'.
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.30. set_uri_user usage
+   Example 1.29. set_uri_user usage
 ...
 ...
 $var(uri) = "sip:user@host";
 $var(uri) = "sip:user@host";
 $var(user) = "new_user";
 $var(user) = "new_user";
 set_uri_user("$var(uri)", "$var(user)");
 set_uri_user("$var(uri)", "$var(user)");
 ...
 ...
 
 
-4.22.  set_uri_host(uri, host)
+4.21. set_uri_host(uri, host)
 
 
    Sets hostpart of SIP URI stored in writable pseudo variable 'uri' to
    Sets hostpart of SIP URI stored in writable pseudo variable 'uri' to
    value of pseudo variable 'host'.
    value of pseudo variable 'host'.
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.31. set_uri_host usage
+   Example 1.30. set_uri_host usage
 ...
 ...
 $var(uri) = "sip:user@host";
 $var(uri) = "sip:user@host";
 $var(host) = "new_host";
 $var(host) = "new_host";
 set_uri_host("$var(uri)", "$var(host)");
 set_uri_host("$var(uri)", "$var(host)");
 ...
 ...
 
 
-4.23.  is_request()
+4.22. is_request()
 
 
    Return true if the SIP message is a request.
    Return true if the SIP message is a request.
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.32. is_request usage
+   Example 1.31. is_request usage
 ...
 ...
 if (is_request()) {
 if (is_request()) {
         ...
         ...
 }
 }
 ...
 ...
 
 
-4.24.  is_reply()
+4.23. is_reply()
 
 
    Return true if the SIP message is a reply.
    Return true if the SIP message is a reply.
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.33. is_reply usage
+   Example 1.32. is_reply usage
 ...
 ...
 if (is_reply()) {
 if (is_reply()) {
         ...
         ...
 }
 }
 ...
 ...
 
 
-4.25.  is_gruu([uri])
+4.24. is_gruu([uri])
 
 
    The function returns true if the uri is GRUU ('gr' parameter is
    The function returns true if the uri is GRUU ('gr' parameter is
    present): 1 - pub-gruu; 2 - temp-gruu.
    present): 1 - pub-gruu; 2 - temp-gruu.
@@ -824,12 +807,12 @@ if (is_reply()) {
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.34. is_gruu() usage
+   Example 1.33. is_gruu() usage
 ...
 ...
 if(is_gruu()) { ... }
 if(is_gruu()) { ... }
 ...
 ...
 
 
-4.26.  is_supported(option)
+4.25. is_supported(option)
 
 
    Function returns true if given option is listed in Supported header(s)
    Function returns true if given option is listed in Supported header(s)
    (if any) of the request. Currently the following options are known:
    (if any) of the request. Currently the following options are known:
@@ -837,7 +820,24 @@ if(is_gruu()) { ... }
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.35. is_supported() usage
+   Example 1.34. is_supported() usage
 ...
 ...
 if (is_supported("outbound")) { ... }
 if (is_supported("outbound")) { ... }
 ...
 ...
+
+4.26. is_first_hop()
+
+   The function returns true if the proxy is first hop after the original
+   sender. For incoming SIP requests, it means there is only one Via
+   header. For incoming SIP replies, it means that top Record-Route URI is
+   'myself' and source address is not matching it (to avoid detecting in
+   case of local loops). Note that it does not detect spirals, which can
+   have the condition for replies true also in the case of additional SIP
+   reply receival.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.35. is_first_hop() usage
+...
+if(is_first_hop()) { ... }
+...

+ 52 - 52
modules/siputils/doc/siputils_admin.xml

@@ -274,7 +274,7 @@ modparam("auth", "rpid_avp", "$avp(myrpid)")
 
 
 	<section>
 	<section>
 	<title>Functions</title>
 	<title>Functions</title>
-		<section>
+		<section id="siputils.f.ring_insert_callid">
 			<title>
 			<title>
 				<function moreinfo="none">ring_insert_callid()</function>
 				<function moreinfo="none">ring_insert_callid()</function>
 			</title>
 			</title>
@@ -298,8 +298,8 @@ ring_insert_callid();
 ...
 ...
 				</programlisting>
 				</programlisting>
 			</example>
 			</example>
-		</section>
-			<section>
+	</section>
+	<section id="siputils.f.options_reply">
 		<title>
 		<title>
 		<function moreinfo="none">options_reply()</function>
 		<function moreinfo="none">options_reply()</function>
 		</title>
 		</title>
@@ -340,7 +340,7 @@ if (uri==myself) {
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="siputils.f.is_user">
 		<title>
 		<title>
 		<function moreinfo="none">is_user(username)</function>
 		<function moreinfo="none">is_user(username)</function>
 		</title>
 		</title>
@@ -368,7 +368,7 @@ if (is_user("john")) {
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section>
+	<section id="siputils.f.has_totag()">
 		<title>
 		<title>
 		<function moreinfo="none">has_totag()</function>
 		<function moreinfo="none">has_totag()</function>
 		</title>
 		</title>
@@ -390,7 +390,7 @@ if (has_totag()) {
 		</example>
 		</example>
 	</section>
 	</section>
 	<section>
 	<section>
-		<title>
+		<title id="siputils.f.uri_param">
 		<function moreinfo="none">uri_param(param)</function>
 		<function moreinfo="none">uri_param(param)</function>
 		</title>
 		</title>
 		<para>
 		<para>
@@ -417,7 +417,7 @@ if (uri_param("param1")) {
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section>
+	<section id="siputils.f.uri_param_value">
 		<title>
 		<title>
 		<function moreinfo="none">uri_param(param,value)</function>
 		<function moreinfo="none">uri_param(param,value)</function>
 		</title>
 		</title>
@@ -449,7 +449,7 @@ if (uri_param("param1","value1")) {
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section>
+	<section id="siputils.f.add_uri_param">
 		<title>
 		<title>
 		<function moreinfo="none">add_uri_param(param)</function>
 		<function moreinfo="none">add_uri_param(param)</function>
 		</title>
 		</title>
@@ -476,7 +476,7 @@ add_uri_param("nat=yes");
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section>
+	<section id="siputils.f.get_uri_param">
 		<title>
 		<title>
 		<function moreinfo="none">get_uri_param(name, var)</function>
 		<function moreinfo="none">get_uri_param(name, var)</function>
 		</title>
 		</title>
@@ -505,7 +505,7 @@ get_uri_param("nat", "$var(nat)");
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section>
+	<section id="siputils.f.tel2sip">
 		<title>
 		<title>
 		<function moreinfo="none">tel2sip(uri, hostpart, result)</function>
 		<function moreinfo="none">tel2sip(uri, hostpart, result)</function>
 		</title>
 		</title>
@@ -553,7 +553,7 @@ tel2sip("$ru", $fd", "$ru");
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="siputils.f.is_e164">
 		<title>
 		<title>
 		<function moreinfo="none">is_e164(pseudo-variable)</function>
 		<function moreinfo="none">is_e164(pseudo-variable)</function>
 		</title>
 		</title>
@@ -581,7 +581,7 @@ if (is_e164("$avp(i:705)") {
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="siputils.f.is_uri_user_e164">
 		<title>
 		<title>
 		<function moreinfo="none">is_uri_user_e164(pseudo-variable)</function>
 		<function moreinfo="none">is_uri_user_e164(pseudo-variable)</function>
 		</title>
 		</title>
@@ -608,7 +608,7 @@ if (is_uri_user_e164("$avp(i:705)") {
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="siputils.f.encode_contact">
 		<title>
 		<title>
 		<function moreinfo="none">encode_contact(encoding_prefix,hostpart)</function>
 		<function moreinfo="none">encode_contact(encoding_prefix,hostpart)</function>
 		</title>
 		</title>
@@ -654,7 +654,7 @@ if (src_ip == 10.0.0.0/8) encode_contact("natted_client","1.2.3.4");
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="siputils.f.decode_contact">
 		<title>
 		<title>
 		<function moreinfo="none">decode_contact()</function>
 		<function moreinfo="none">decode_contact()</function>
 		</title>
 		</title>
@@ -681,7 +681,7 @@ if (uri =~ "^sip:natted_client") { decode_contact(); }
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="siputils.f.decode_contact_header">
 		<title>
 		<title>
 		<function moreinfo="none">decode_contact_header()</function>
 		<function moreinfo="none">decode_contact_header()</function>
 		</title>
 		</title>
@@ -711,7 +711,7 @@ reply_route[2] {
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section>
+	<section id="siputils.f.cmp_uri">
 		<title>
 		<title>
 		<function moreinfo="none">cmp_uri(str1, str2)</function>
 		<function moreinfo="none">cmp_uri(str1, str2)</function>
 		</title>
 		</title>
@@ -735,7 +735,7 @@ if(cmp_uri("$ru", "sip:[email protected]"))
 		</example>
 		</example>
 	</section>
 	</section>
 
 
-	<section>
+	<section id="siputils.f.cmp_aor">
 		<title>
 		<title>
 		<function moreinfo="none">cmp_aor(str1, str2)</function>
 		<function moreinfo="none">cmp_aor(str1, str2)</function>
 		</title>
 		</title>
@@ -759,32 +759,7 @@ if(cmp_aor("[email protected]", "sip:kamailio@$fd"))
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section>
-		<title>
-			<function moreinfo="none">is_rpid_user_e164()</function>
-		</title>
-		<para>
-		The function checks if the SIP URI received from the database or 
-		radius server and will potentially be used in Remote-Party-ID header 
-		field contains an E164 number (+followed by up to 15 decimal digits) 
-		in its user part.  Check fails, if no such SIP URI exists 
-		(i.e. radius server or database didn't provide this information).
-		</para>
-		<para>
-		This function can be used from REQUEST_ROUTE.
-		</para>
-		<example>
-		<title>is_rpid_user_e164 usage</title>
-		<programlisting format="linespecific">
-...
-if (is_rpid_user_e164()) {
-    # do something here
-};
-...
-</programlisting>
-		</example>
-	</section>
-	<section id="append-rpid-hf-no-params">
+	<section  id="siputils.f.append_rpid_hf">
 		<title>
 		<title>
 			<function moreinfo="none">append_rpid_hf()</function></title>
 			<function moreinfo="none">append_rpid_hf()</function></title>
 		<para>
 		<para>
@@ -807,13 +782,13 @@ append_rpid_hf();  # Append Remote-Party-ID header field
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section id="append-rpid-hf-params">
+	<section id="siputils.f.append_rpid_hf_params">
 		<title>
 		<title>
 			<function moreinfo="none">append_rpid_hf(prefix, suffix)</function>
 			<function moreinfo="none">append_rpid_hf(prefix, suffix)</function>
 		</title>
 		</title>
 		<para>
 		<para>
 		This function is the same as 
 		This function is the same as 
-		<xref linkend="append-rpid-hf-no-params"/>. The only difference is
+		<xref linkend="siputils.f.append_rpid_hf"/>. The only difference is
 		that it accepts two parameters--prefix and suffix to be added to 
 		that it accepts two parameters--prefix and suffix to be added to 
 		Remote-Party-ID header field. This function ignores rpid_prefix and 
 		Remote-Party-ID header field. This function ignores rpid_prefix and 
 		rpid_suffix parameters, instead of that allows to set them in every 
 		rpid_suffix parameters, instead of that allows to set them in every 
@@ -850,7 +825,7 @@ append_rpid_hf("", ";party=calling;id-type=subscriber;screen=yes");
 		</example>
 		</example>
 	</section>
 	</section>
 	<section>
 	<section>
-		<title>
+		<title id="siputils.f.is_rpid_user_e164">
 			<function moreinfo="none">is_rpid_user_e164()</function>
 			<function moreinfo="none">is_rpid_user_e164()</function>
 		</title>
 		</title>
 		<para>
 		<para>
@@ -874,7 +849,7 @@ if (is_rpid_user_e164()) {
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section>
+	<section id="siputils.f.set_uri_user">
 		<title>
 		<title>
 			<function moreinfo="none">set_uri_user(uri, user)</function>
 			<function moreinfo="none">set_uri_user(uri, user)</function>
 		</title>
 		</title>
@@ -896,7 +871,7 @@ set_uri_user("$var(uri)", "$var(user)");
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section>
+	<section id="siputils.f.set_uri_host">
 		<title>
 		<title>
 			<function moreinfo="none">set_uri_host(uri, host)</function>
 			<function moreinfo="none">set_uri_host(uri, host)</function>
 		</title>
 		</title>
@@ -918,7 +893,7 @@ set_uri_host("$var(uri)", "$var(host)");
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section>
+	<section id="siputils.f.is_request">
 		<title>
 		<title>
 		<function moreinfo="none">is_request()</function>
 		<function moreinfo="none">is_request()</function>
 		</title>
 		</title>
@@ -939,7 +914,7 @@ if (is_request()) {
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section>
+	<section id="siputils.f.is_reply">
 		<title>
 		<title>
 		<function moreinfo="none">is_reply()</function>
 		<function moreinfo="none">is_reply()</function>
 		</title>
 		</title>
@@ -960,7 +935,7 @@ if (is_reply()) {
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section id="is-gruu">
+	<section id="siputils.f.is_gruu">
 		<title>
 		<title>
 			<function moreinfo="none">is_gruu([uri])</function>
 			<function moreinfo="none">is_gruu([uri])</function>
 		</title>
 		</title>
@@ -989,7 +964,7 @@ if(is_gruu()) { ... }
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
-	<section id="is-supported">
+	<section id="siputils.f.is_supported">
 		<title>
 		<title>
 			<function moreinfo="none">is_supported(option)</function>
 			<function moreinfo="none">is_supported(option)</function>
 		</title>
 		</title>
@@ -1009,6 +984,31 @@ if(is_gruu()) { ... }
 ...
 ...
 if (is_supported("outbound")) { ... }
 if (is_supported("outbound")) { ... }
 ...
 ...
+</programlisting>
+		</example>
+	</section>
+	<section id="siputils.f.is_first_hop">
+		<title>
+			<function moreinfo="none">is_first_hop()</function>
+		</title>
+		<para>
+		The function returns true if the proxy is first hop after the
+		original sender. For incoming SIP requests, it means there is only
+		one Via header. For incoming SIP replies, it means that top
+		Record-Route URI is 'myself' and source address is not matching it
+		(to avoid detecting in case of local loops). Note that it does not
+		detect spirals, which can have the condition for replies true also
+		in the case of additional SIP reply receival.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title>is_first_hop() usage</title>
+		<programlisting format="linespecific">
+...
+if(is_first_hop()) { ... }
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>

+ 80 - 9
modules/siputils/sipops.c

@@ -34,6 +34,10 @@
 #include "../../mod_fix.h"
 #include "../../mod_fix.h"
 #include "../../parser/parse_uri.h"
 #include "../../parser/parse_uri.h"
 #include "../../parser/parse_supported.h"
 #include "../../parser/parse_supported.h"
+#include "../../parser/parse_rr.h"
+#include "../../ip_addr.h"
+#include "../../resolve.h"
+#include "../../forward.h"
 #include "../../lib/kcore/cmpapi.h"
 #include "../../lib/kcore/cmpapi.h"
 
 
 #include "sipops.h"
 #include "sipops.h"
@@ -118,16 +122,83 @@ int w_is_gruu(sip_msg_t *msg, char *uri1, char *p2)
 
 
 int w_is_supported(sip_msg_t *msg, char *_option, char *p2)
 int w_is_supported(sip_msg_t *msg, char *_option, char *p2)
 {
 {
-    unsigned long option;
+	unsigned long option;
 
 
-    option = (unsigned long)_option;
+	option = (unsigned long)_option;
 
 
-    if (parse_supported(msg) < 0)
-	return -1;
+	if (parse_supported(msg) < 0)
+		return -1;
 
 
-    if ((((struct option_tag_body*)msg->supported->parsed)->option_tags_all &
-	 option) == 0)
-	return -1;
-    else
-	return 1;
+	if ((((struct option_tag_body*)msg->supported->parsed)->option_tags_all &
+				option) == 0)
+		return -1;
+	else
+		return 1;
+}
+
+
+int w_is_first_hop(sip_msg_t *msg, char *p1, char *p2)
+{
+	int ret;
+	rr_t* r = NULL;
+	sip_uri_t puri;
+	struct ip_addr *ip;
+
+	if(msg==NULL)
+		return -1;
+
+	if(msg->first_line.type == SIP_REQUEST) {
+		if (parse_headers( msg, HDR_VIA2_F, 0 )<0
+				|| (msg->via2==0) || (msg->via2->error!=PARSE_OK))
+		{
+			/* sip request: if more than one via, then not first hop */
+			/* no second via or error */
+			LM_DBG("no 2nd via found - first hop\n");
+			return 1;
+		}
+		return -1;
+	} else if(msg->first_line.type == SIP_REPLY) {
+		/* sip reply: if top record-route is myself
+		 * and not received from myself (loop), then is first hop */
+		if (parse_headers( msg, HDR_EOH_F, 0 )<0) {
+			LM_DBG("error parsing headers\n");
+			return -1;
+		}
+		if(msg->record_route==NULL) {
+			LM_DBG("no record-route header - first hop\n");
+			return 1;
+		}
+		if(parse_rr(msg->record_route)<0) {
+			LM_DBG("failed to parse first record-route header\n");
+			return -1;
+		}
+		r = (rr_t*)msg->record_route->parsed;
+		if(parse_uri(r->nameaddr.uri.s, r->nameaddr.uri.len, &puri)<0) {
+			LM_DBG("failed to parse uri in first record-route header\n");
+			return -1;
+		}
+		if (((ip = str2ip(&(puri.host))) == NULL)
+				&& ((ip = str2ip6(&(puri.host))) == NULL)) {
+			LM_DBG("uri host is not an ip address\n");
+			return -1;
+		}
+		ret = check_self(&puri.host, (puri.port.s)?puri.port_no:0,
+				(puri.transport_val.s)?puri.proto:0);
+		if(ret!=1) {
+			LM_DBG("top record route uri is not myself\n");
+			return -1;
+		}
+		if (ip_addr_cmp(ip, &(msg->rcv.src_ip))
+				&& ((msg->rcv.src_port == puri.port_no)
+					|| ((puri.port.len == 0) && (msg->rcv.src_port == 5060)))
+				&& (puri.proto==msg->rcv.proto
+					|| (puri.proto==0 && msg->rcv.proto==PROTO_UDP)) ) {
+			LM_DBG("source address matches top record route uri - loop\n");
+			return -1;
+		}
+		/* todo - check spirals */
+		return 1;
+	} else {
+		return -1;
+	}
 }
 }

+ 1 - 0
modules/siputils/sipops.h

@@ -40,5 +40,6 @@ int w_cmp_uri(struct sip_msg *msg, char *uri1, char *uri2);
 int w_cmp_aor(struct sip_msg *msg, char *uri1, char *uri2);
 int w_cmp_aor(struct sip_msg *msg, char *uri1, char *uri2);
 int w_is_gruu(sip_msg_t *msg, char *uri1, char *p2);
 int w_is_gruu(sip_msg_t *msg, char *uri1, char *p2);
 int w_is_supported(sip_msg_t *msg, char *_option, char *p2);
 int w_is_supported(sip_msg_t *msg, char *_option, char *p2);
+int w_is_first_hop(sip_msg_t *msg, char *uri1, char *p2);
 
 
 #endif
 #endif

+ 2 - 0
modules/siputils/siputils.c

@@ -173,6 +173,8 @@ static cmd_export_t cmds[]={
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
 	{"is_supported",  (cmd_function)w_is_supported,                    1, fixup_option,
 	{"is_supported",  (cmd_function)w_is_supported,                    1, fixup_option,
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
+	{"is_first_hop",  (cmd_function)w_is_first_hop,                    0, 0,
+		0, ANY_ROUTE},
 	{0,0,0,0,0,0}
 	{0,0,0,0,0,0}
 };
 };