소스 검색

lost: support of shape representations (as in RFC5491) and new 3d parameter

- A Presence Information Data Format Location Object (PIDF-LO) may
  contain one of the shape types as listed in RFC5491. A LoST
  findService request currently contains only a profile for
  two-dimensional geodetic location information, which
  is the default setting for this 3d parameter. The parameter
  can be set to 1 if a LoST server supports 3d, otherwise a
  3d location is reduced to 2d by the module.
Wolfgang Kampichler 1 년 전
부모
커밋
f7caef5d4b
6개의 변경된 파일322개의 추가작업 그리고 154개의 파일을 삭제
  1. 156 124
      src/modules/lost/doc/lost_admin.xml
  2. 8 3
      src/modules/lost/functions.c
  3. 3 0
      src/modules/lost/lost.c
  4. 12 10
      src/modules/lost/response.c
  5. 133 16
      src/modules/lost/utilities.c
  6. 10 1
      src/modules/lost/utilities.h

+ 156 - 124
src/modules/lost/doc/lost_admin.xml

@@ -10,19 +10,19 @@
 <!-- Module User's Guide -->
 
 <chapter>
-	<title>&adminguide;</title>
-	<section>
+    <title>&adminguide;</title>
+    <section>
         <title>Overview</title>
         <para>
-        SIP requests may be forwarded based on a location provided with the
+        SIP requests may be forwarded based on a location provided by the
         request or retrieved from a specific location server using an identity
         (HELD). This module implements the basic functionality to get or parse
         location information (civic and geodetic) and to query a mapping service
-        (LOST) in order to get next hop based on location and service urn either
-        specified or provided with the request.
+        (LOST) to get the next hop based on location and service urn either
+        specified or provided with the request. 
         </para>
         <para>
-        This module implements protocol functions that use the http_client api
+        This module implements protocol functions that use the http_client API
         to fetch data from external LOST and HELD servers. The module is using
         the http_client concept of "connections" to define properties of HTTP
         sessions. A connection has one or multiple servers and a set of settings
@@ -48,38 +48,38 @@
         <para>
         The function lost_query allows &kamailio; to assemble a LOST
         findService request  as defined in RFC5222
-        (<ulink url="https://tools.ietf.org/html/rfc5255"/>) to query
+        (<ulink url="https://tools.ietf.org/html/rfc5255"/>) to query 
         routing information for a given (geodetic or civic) location and a service
-        URN. Both, PIDF-LO and service URN may be provided as function parameter,
+        URN. Both, PIDF-LO and service URN may be provided as function parameters,
         or are taken from the request message if applicable. The findServiceResponse
-        is parsed and represented as display name and SIP URI typically used as next
+        is parsed and represented as display name and SIP URI typically used as the next
         hop in a Route header.
         </para>
         <para>
-        The http_client module uses the CURL library setting up connections.
-        The CURL library by default use the system configured DNS resolver,
+        The http_client module uses the CURL library to set up connections.
+        The CURL library by default uses the system-configured DNS resolver,
         not the Kamailio resolver.
         </para>
         <para>
         The module is limited to using HTTP and HTTPS protocols.
         </para>
-	</section>
-	<section>
-	    <title>Dependencies</title>
-	    <section>
-		    <title>&kamailio; Modules</title>
-		    <para>
-		        The following modules must be loaded before this module:
+    </section>
+    <section>
+        <title>Dependencies</title>
+        <section>
+            <title>&kamailio; Modules</title>
+            <para>
+                The following modules must be loaded before this module:
                 <itemizedlist>
                 <listitem><para>
                 HTTP_CLIENT - the http_client module should be
-                loaded first in order to initialize connections properly.
+                loaded first to initialize connections properly.
                 </para></listitem>
                 <listitem><para>
-                TLS - if you use TLS connections (https) the tls module
+                TLS - if you use TLS connections (https) the TLS module
                 should be loaded first in order to initialize &openssl; properly.
                 </para></listitem>
-			    </itemizedlist>
+                </itemizedlist>
             </para>
         </section>
         <section>
@@ -101,12 +101,12 @@
                 </itemizedlist>
             </para>
         </section>
-	</section>
-	<section id="lost.p.general">
-		<title>Parameters</title>
+    </section>
+    <section id="lost.p.general">
+        <title>Parameters</title>
         <para>
         Besides parameters listed, this module uses <emphasis>http_client</emphasis>
-        therefore according parameters may apply.
+        therefore appropriate module parameters may apply.
         </para>
         <section id="lost.p.exact_type">
             <title><varname>exact_type</varname> (int)</title>
@@ -129,13 +129,13 @@
         <section id="lost.p.response_time">
             <title><varname>response_time</varname> (int)</title>
             <para>
-            A time value indicating to the location server how long the client is
+            A time value informs the location server how long the client is
             prepared to wait for a response.
             </para>
             <para>
-            The value is expressed as integer, either -1 'emergencyDispatch', 0 'emergencyRouting',
+            The value is expressed as an integer, either -1 'emergencyDispatch', 0 'emergencyRouting',
             a non-negative integer (>0) in units of milliseconds.
-            Note: The time value is indicative only.
+            Note: The time value is indicative only. 
             </para>
             <para>
             Default: 0 ('emergencyRouting')
@@ -155,7 +155,7 @@
             The "locationType" element contains a list of types that are requested.
             Values are "any", "geodetic", "civic" or "locationURI" and combinations.
             </para>
-			<itemizedlist>
+            <itemizedlist>
                 <listitem><para>
                     <emphasis>any</emphasis> - returns location information in all forms available
                 </para></listitem>
@@ -206,7 +206,7 @@
             profile or combinations. A LoST <emphasis>findService</emphasis> contains only one location, which
             is selected via this parameter as follows:
             </para>
-			<itemizedlist>
+            <itemizedlist>
                 <listitem><para>
                     <emphasis>0</emphasis> - takes the first location of any type
                 </para></listitem>
@@ -228,6 +228,38 @@
                 <programlisting format="linespecific">
     ...
     modparam("lost", "location_profile, 2)
+    ...
+                </programlisting>
+            </example>
+        </section>
+        <section id="lost.p.location_3d">
+            <title><varname>location_3d</varname> (int)</title>
+            <para>
+            A Presence Information Data Format Location Object (PIDF-LO) may
+            contain one of the shape types as listed in RFC5491
+            (<ulink url="https://tools.ietf.org/html/rfc5491"/>).
+            A LoST <emphasis>findService</emphasis> request currently contains only
+            a profile for two-dimensional geodetic location information, which
+            is the default setting for this parameter. The parameter can be set
+            to 1 if a LoST server supports 3d, otherwise a 3d location is reduced
+            to 2d by the module.
+            </para>
+            <itemizedlist>
+                <listitem><para>
+                    <emphasis>0</emphasis> - two-dimensional (2d) shape representations only
+                </para></listitem>
+                <listitem><para>
+                    <emphasis>1</emphasis> - three-dimensional (3d) volume representations allowed
+                </para></listitem>
+            </itemizedlist>
+            <para>
+            Default: 0 (2d representations).
+            </para>
+            <example>
+            <title>Set <varname>location_3d</varname> parameter</title>
+                <programlisting format="linespecific">
+    ...
+    modparam("lost", "location_3d, 1)
     ...
                 </programlisting>
             </example>
@@ -242,7 +274,7 @@
             or an http(s) URI pointing to an external source. This parameter
             supports filtering of the following types:
             </para>
-			<itemizedlist>
+            <itemizedlist>
                 <listitem><para>
                     <emphasis>0 (any)</emphasis> - any URI (first or last)
                 </para></listitem>
@@ -272,7 +304,7 @@
             <title><varname>geoheader_order</varname> (int)</title>
             <para>
             A Geolocation header may include a list of locationValues. This
-            parameter sets the order of the URI used to retrieve location
+            parameter sets the order of the URI used to retrieve the location
             information, either the first element of a certain type or the
             last. Values are 0 (first) or 1 (last).
             </para>
@@ -292,7 +324,7 @@
             <title><varname>recursion</varname> (int)</title>
             <para>
             A Geolocation header may include a list of locationValues. This
-            parameter sets the order of the URI used to retrieve location
+            parameter sets the order of the URI used to retrieve the location
             information, either the first element of a certain type or the
             last. Values are 0 (first) or 1 (last).
             </para>
@@ -337,53 +369,53 @@
                 </programlisting>
             </example>
         </section>
-	</section>
-	<section>
-	    <title>Functions</title>
-		<section id="lost.f.lost_held_query">
-			<title>
-				<function moreinfo="none">lost_held_query(con, [id,] pidf-lo, url, error)</function>
-			</title>
-			<para>
-			Sends a HELD locationRequest to a given connection. The device identity is either
+    </section>
+    <section>
+        <title>Functions</title>
+        <section id="lost.f.lost_held_query">
+            <title>
+                <function moreinfo="none">lost_held_query(con, [id,] pidf-lo, url, error)</function>
+            </title>
+            <para>
+            Sends a HELD locationRequest to a given connection. The device identity is either
             specified, or the P-A-I header value, or the From header value.
-	    	</para>
-			    <itemizedlist>
-				    <listitem><para>
-						<emphasis>con</emphasis> - the name of an existing
-						HTTP connection, defined by a httpcon modparam
-				    </para></listitem>
+            </para>
+                <itemizedlist>
                     <listitem><para>
-						<emphasis>id</emphasis> - the device id used in the HELD
+                        <emphasis>con</emphasis> - the name of an existing
+                        HTTP connection, defined by a httpcon modparam
+                    </para></listitem>
+                    <listitem><para>
+                        <emphasis>id</emphasis> - the device id used in the HELD
                         locationRequest
                     </para></listitem>
                     <listitem><para>
-						<emphasis>pidf-lo</emphasis> - the PIDF-LO returned in the
+                        <emphasis>pidf-lo</emphasis> - the PIDF-LO returned in the
                         HELD locationRequest response
                     </para></listitem>
                     <listitem><para>
-						<emphasis>url</emphasis> - the location reference returned
+                        <emphasis>url</emphasis> - the location reference returned
                         in the HELD locationRequest response - this reference may be
                         added as Geolocation header value and forwarded downstream.
                         Note: to work properly, it is required to include "locationURI"
                         in the location_type parameter.
                     </para></listitem>
                     <listitem><para>
-						<emphasis>error</emphasis> - any error code returned in the
+                        <emphasis>error</emphasis> - any error code returned in the
                         HELD response
                     </para></listitem>
-			    </itemizedlist>
-			<para>
-			The return value is 200 on success, 400 if an internal error occurred, or 500 if an
+                </itemizedlist>
+            <para>
+            The return value is 200 on success, 400 if an internal error occurred, or 500 if an
             error code is returned in the HELD locationRequest response.
-	    	</para>
-			<para>
-			This function can be used from REQUEST_ROUTE,
-			ONREPLY_ROUTE, FAILURE_ROUTE, and BRANCH_ROUTE.
-			</para>
-			<example>
-				<title><function>lost_held_query()</function> usage</title>
-				<programlisting format="linespecific">
+            </para>
+            <para>
+            This function can be used from REQUEST_ROUTE,
+            ONREPLY_ROUTE, FAILURE_ROUTE, and BRANCH_ROUTE.
+            </para>
+            <example>
+                <title><function>lost_held_query()</function> usage</title>
+                <programlisting format="linespecific">
 ...
 modparam("http_client", "httpcon", "heldsrv=>http://service.org/api/held");
 ...
@@ -395,44 +427,44 @@ xlog("L_INFO", "HELD locationRequest: Result code $var(res)\nUrl: $var(url)\n$va
 $var(res) = lost_held_query("heldsrv", "$var(pidf)", "$var(url)", "$var(err)");
 xlog("L_INFO", "HELD locationRequest: Result code $var(res)\nUrl: $var(url)\n$var(pidf)\n");
 ...
-				</programlisting>
-			</example>
-		</section>
-		<section id="lost.f.lost_held_dereference">
-			<title>
-				<function moreinfo="none">lost_held_dereference(url, rtime, rtype, pidf-lo, error)</function>
-			</title>
-			<para>
-			Sends a HELD POST locationRequest to a given URL. Attributes are responseTime and responseType.
+                </programlisting>
+            </example>
+        </section>
+        <section id="lost.f.lost_held_dereference">
+            <title>
+                <function moreinfo="none">lost_held_dereference(url, rtime, rtype, pidf-lo, error)</function>
+            </title>
+            <para>
+            Sends a HELD POST locationRequest to a given URL. Attributes are responseTime and responseType.
             The <emphasis>locationType</emphasis> property "exact" is set to "false".
-	    	</para>
-			    <itemizedlist>
+            </para>
+                <itemizedlist>
                     <listitem><para>
-						<emphasis>url</emphasis> - a URL received via Geolocation header to dereference
+                        <emphasis>url</emphasis> - a URL received via Geolocation header to dereference
                         location
                     </para></listitem>
-				    <listitem><para>
-						<emphasis>rtime</emphasis> - the response time as defined
+                    <listitem><para>
+                        <emphasis>rtime</emphasis> - the response time as defined
                         in <xref linkend="lost.p.response_time"/>
-				    </para></listitem>
+                    </para></listitem>
                     <listitem><para>
-						<emphasis>rtype</emphasis> - the response type (location) as defined
+                        <emphasis>rtype</emphasis> - the response type (location) as defined
                         in <xref linkend="lost.p.location_type"/>
                     </para></listitem>
                     <listitem><para>
-						<emphasis>pidf-lo</emphasis> - the PIDF-LO returned in the
+                        <emphasis>pidf-lo</emphasis> - the PIDF-LO returned in the
                         HELD locationRequest response
                     </para></listitem>
                     <listitem><para>
-						<emphasis>error</emphasis> - any error code returned in the
+                        <emphasis>error</emphasis> - any error code returned in the
                         HELD response
                     </para></listitem>
-			    </itemizedlist>
-			<para>
-			The return value is 200..203 on success, 400 if an internal error occurred, or 500 if an
+                </itemizedlist>
+            <para>
+            The return value is 200..203 on success, 400 if an internal error occurred, or 500 if an
             error code is returned in the HELD response. Success codes in detail are as follows:
-	    	</para>
-			<itemizedlist>
+            </para>
+            <itemizedlist>
                 <listitem><para>
                     <emphasis>200</emphasis> - received 200 OK, but neither location-info nor locationURI element found
                 </para></listitem>
@@ -445,14 +477,14 @@ xlog("L_INFO", "HELD locationRequest: Result code $var(res)\nUrl: $var(url)\n$va
                 <listitem><para>
                     <emphasis>203</emphasis> - received 200 OK with location-info and locationURI element
                 </para></listitem>
-            </itemizedlist>
-			<para>
-			This function can be used from REQUEST_ROUTE,
-			ONREPLY_ROUTE, FAILURE_ROUTE, and BRANCH_ROUTE.
-			</para>
-			<example>
-				<title><function>lost_held_dereference()</function> usage</title>
-				<programlisting format="linespecific">
+            </itemizedlist>            
+            <para>
+            This function can be used from REQUEST_ROUTE,
+            ONREPLY_ROUTE, FAILURE_ROUTE, and BRANCH_ROUTE.
+            </para>
+            <example>
+                <title><function>lost_held_dereference()</function> usage</title>
+                <programlisting format="linespecific">
 ...
 # HELD location dereference
 if ($hdr(Geolocation)=~"^&lt;http.*$") {
@@ -461,19 +493,19 @@ if ($hdr(Geolocation)=~"^&lt;http.*$") {
     xlog("L_INFO", "HELD location dereference: Result code $var(res)\n$var(pidf)");
 ...
 }
-				</programlisting>
-			</example>
-		</section>
-		<section id="lost.f.lost_query">
-			<title>
-				<function moreinfo="none">lost_query(con, [pidf-lo, urn,] uri, name, error)</function>
-			</title>
-			<para>
-			Sends a LOST findService request to a given connection. PIDF-LO and URN are either specified,
+                </programlisting>
+            </example>
+        </section>
+        <section id="lost.f.lost_query">
+            <title>
+                <function moreinfo="none">lost_query(con, [pidf-lo, urn,] uri, name, error)</function>
+            </title>
+            <para>
+            Sends a LOST findService request to a given connection. PIDF-LO and URN are either specified,
             or, if omitted, parsed from the message body (PIDF-LO) and request line (URN). Either "pidf-lo"
-            or "urn" can be set to an empty string in order to be ignored.
-	    	</para>
-			<itemizedlist>
+            or "urn" can be set to an empty string to be ignored. 
+            </para>
+            <itemizedlist>
                 <listitem><para>
                     <emphasis>con</emphasis> - the name of an existing
                     HTTP connection defined by a httpcon modparam
@@ -498,18 +530,18 @@ if ($hdr(Geolocation)=~"^&lt;http.*$") {
                     <emphasis>error</emphasis> - any error code returned in the
                     LOST findServiceResponse
                 </para></listitem>
-			</itemizedlist>
-			<para>
-			The return value is 200 on success, 400 if an internal error occurred, or 500 if an
+            </itemizedlist>
+            <para>
+            The return value is 200 on success, 400 if an internal error occurred, or 500 if an
             error code is returned in the LOST findServiceResponse.
-	    	</para>
-			<para>
-			This function can be used from REQUEST_ROUTE,
-			ONREPLY_ROUTE, FAILURE_ROUTE, and BRANCH_ROUTE.
-			</para>
-			<example>
-				<title><function>lost()</function> usage</title>
-				<programlisting format="linespecific">
+            </para>
+            <para>
+            This function can be used from REQUEST_ROUTE,
+            ONREPLY_ROUTE, FAILURE_ROUTE, and BRANCH_ROUTE.
+            </para>
+            <example>
+                <title><function>lost()</function> usage</title>
+                <programlisting format="linespecific">
 ...
 modparam("http_client", "httpcon", "heldsrv=>http://service.org/api/held");
 modparam("http_client", "httpcon", "lostsrv=>http://service.org/api/lost");
@@ -535,24 +567,24 @@ xlog("L_INFO", "LOST findService: Result code $var(res)\nUri: $var(uri)\nName: $
 $var(res) = lost_query("lostsrv", "$var(uri)", "$var(name)", "$var(err)");
 xlog("L_INFO", "LOST findService: Result code $var(res)\nUri: $var(uri)\nName: $var(name)\n");
 ...
-				</programlisting>
-			</example>
-		</section>
+                </programlisting>
+            </example>
+        </section>
 
     </section>
     <section id="lost.s.counters">
-	    <title>Counters</title>
+        <title>Counters</title>
         <para>
             This module has no specific counters but uses http_client therefore
             according counters may apply.
         </para>
-	</section>
+    </section>
 
     <section id="lost.s.remarks">
         <title>Remarks</title>
         <para>
             Note: libcurl leak in CentOS 6 - this module uses libcurl library
-            (via http_client) and in case if you are using CentOS 6, be aware that
+            (via http_client) and in case you are using CentOS 6, be aware that
             standard libcurl-7.19.7-52 has a memory leak. To fix this memory, install
             libcurl from city-fan repository. More details at:
             <ulink url="https://www.digitalocean.com/community/questions/how-to-upgrade-curl-in-centos6"></ulink>.
@@ -573,7 +605,7 @@ xlog("L_INFO", "LOST findService: Result code $var(res)\nUri: $var(uri)\nName: $
         </para>
         <para>
             Note: in case modparam "geoheader_type" is set to 2 (http), the module may
-            use 3 (https) as fallback and vice versa.
+            use 3 (https) as a fallback and vice versa.
         </para>
     </section>
 </chapter>

+ 8 - 3
src/modules/lost/functions.c

@@ -1,7 +1,7 @@
 /*
  * lost module functions
  *
- * Copyright (C) 2022 Wolfgang Kampichler
+ * Copyright (C) 2023 Wolfgang Kampichler
  * DEC112, FREQUENTIS AG
  *
  * This file is part of Kamailio, a free SIP server.
@@ -67,6 +67,7 @@ extern httpc_api_t httpapi;
 
 extern int lost_geoloc_type;
 extern int lost_geoloc_order;
+extern int lost_geoloc_3d;
 extern int lost_verbose;
 extern int held_resp_time;
 extern int held_exact_type;
@@ -380,7 +381,9 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url,
 			XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA);
 	if(doc == NULL) {
 		LM_WARN("invalid xml document: [%.*s]\n", res.len, res.s);
-		doc = xmlRecoverMemory(res.s, res.len);
+		doc = xmlReadMemory(res.s, res.len, 0, NULL,
+				XML_PARSE_NOBLANKS | XML_PARSE_NONET |
+				XML_PARSE_NOCDATA | XML_PARSE_RECOVER);
 		if(doc == NULL) {
 			LM_ERR("xml document recovery failed on: [%.*s]\n", res.len, res.s);
 			goto err;
@@ -701,7 +704,9 @@ int lost_held_dereference(struct sip_msg *_m, char *_url, char *_pidf,
 			XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA);
 	if(doc == NULL) {
 		LM_WARN("invalid xml document: [%.*s]\n", res.len, res.s);
-		doc = xmlRecoverMemory(res.s, res.len);
+		doc = xmlReadMemory(res.s, res.len, 0, NULL,
+				XML_PARSE_NOBLANKS | XML_PARSE_NONET |
+				XML_PARSE_NOCDATA | XML_PARSE_RECOVER);
 		if(doc == NULL) {
 			LM_ERR("xml document recovery failed on: [%.*s]\n", res.len, res.s);
 			goto err;

+ 3 - 0
src/modules/lost/lost.c

@@ -53,6 +53,8 @@ httpc_api_t httpapi;
 int lost_geoloc_type = 0;
 /* lost: Geolocation header value order: first (0) or last (1) (default: 0) */
 int lost_geoloc_order = 0;
+/* lost: Geolocation header 3d representation: yes (1) or no (0) (default: 0) */
+int lost_geoloc_3d = 0;
 /* lost: Recursion allowed: yes (1) or no (0) (default: 1 = allowed) */
 int lost_recursion = 1;
 /* lost geo profile: first (0), last (1), geo (2) or civic (3) (default: 0) */
@@ -124,6 +126,7 @@ static param_export_t params[] = {{"exact_type", PARAM_INT, &held_exact_type},
 		{"location_type", PARAM_STR, &held_loc_type},
 		{"recursion", PARAM_INT, &lost_recursion},
 		{"location_profile", PARAM_INT, &lost_profile},
+		{"location_3d", PARAM_INT, &lost_geoloc_3d},
 		{"verbose", PARAM_INT, &lost_verbose},
 		{"geoheader_type", PARAM_INT, &lost_geoloc_type},
 		{"geoheader_order", PARAM_INT, &lost_geoloc_order}, {0, 0, 0}};

+ 12 - 10
src/modules/lost/response.c

@@ -1,7 +1,7 @@
 /*
  * lost module LoST response parsing functions
  *
- * Copyright (C) 2022 Wolfgang Kampichler
+ * Copyright (C) 2023 Wolfgang Kampichler
  * DEC112, FREQUENTIS AG
  *
  * This file is part of Kamailio, a free SIP server.
@@ -54,7 +54,7 @@
 #include "utilities.h"
 #include "response.h"
 
-/*
+/* 
  * is_http_laquot(search)
  * return 1 if true else 0
  */
@@ -77,7 +77,7 @@ int is_http_laquot(char *search)
 	return 0;
 }
 
-/*
+/* 
  * is_https_laquot(search)
  * return 1 if true else 0
  */
@@ -101,7 +101,7 @@ int is_https_laquot(char *search)
 	return 0;
 }
 
-/*
+/* 
  * is_http(search)
  * return 1 if true else 0
  */
@@ -123,7 +123,7 @@ int is_http(char *search)
 	return 0;
 }
 
-/*
+/* 
  * is_https(search)
  * return 1 if true else 0
  */
@@ -146,7 +146,7 @@ int is_https(char *search)
 	return 0;
 }
 
-/*
+/* 
  * is_cid_laquot(search)
  * return 1 if true else 0
  */
@@ -168,7 +168,7 @@ int is_cid_laquot(char *search)
 	return 0;
 }
 
-/*
+/* 
  * is_cid(search)
  * return 1 if true else 0
  */
@@ -189,7 +189,7 @@ int is_cid(char *search)
 	return 0;
 }
 
-/*
+/* 
  * is_urn(search)
  * return 1 if true else 0
  */
@@ -612,7 +612,7 @@ void lost_free_findServiceResponse(p_lost_fsr_t *res)
 
 /*
  * lost_get_response_issue(node)
- * parses response issue (errors, warnings) and writes
+ * parses response issue (errors, warnings) and writes 
  * results to issue object
  */
 p_lost_issue_t lost_get_response_issues(xmlNodePtr node)
@@ -963,7 +963,9 @@ p_lost_fsr_t lost_parse_findServiceResponse(str ret)
 
 	if(doc == NULL) {
 		LM_ERR("invalid xml document: [%.*s]\n", ret.len, ret.s);
-		doc = xmlRecoverMemory(ret.s, ret.len);
+		doc = xmlReadMemory(ret.s, ret.len, 0, NULL,
+				XML_PARSE_NOBLANKS | XML_PARSE_NONET |
+				XML_PARSE_NOCDATA | XML_PARSE_RECOVER);
 		if(doc == NULL) {
 			LM_ERR("xml document recovery failed on: [%.*s]\n", ret.len, ret.s);
 			return NULL;

+ 133 - 16
src/modules/lost/utilities.c

@@ -1,7 +1,7 @@
 /*
  * lost module utility functions
  *
- * Copyright (C) 2021 Wolfgang Kampichler
+ * Copyright (C) 2023 Wolfgang Kampichler
  * DEC112, FREQUENTIS AG
  *
  * This file is part of Kamailio, a free SIP server.
@@ -52,6 +52,7 @@
 
 extern int lost_recursion;
 extern int lost_profile;
+extern int lost_geoloc_3d;
 
 /*
  * lost_trim_content(dest, lgth)
@@ -140,6 +141,7 @@ p_lost_loc_t lost_new_loc(str rurn)
 	ptr->urn = urn;
 	ptr->longitude = NULL;
 	ptr->latitude = NULL;
+	ptr->altitude = NULL;
 	ptr->geodetic = NULL;
 	ptr->xpath = NULL;
 	ptr->profile = NULL;
@@ -228,6 +230,8 @@ void lost_free_loc(p_lost_loc_t *loc)
 		pkg_free(ptr->longitude);
 	if(ptr->latitude)
 		pkg_free(ptr->latitude);
+	if(ptr->altitude)
+		pkg_free(ptr->altitude);
 	if(ptr->profile)
 		pkg_free(ptr->profile);
 
@@ -902,7 +906,9 @@ p_lost_loc_t lost_parse_pidf(str pidf, str urn)
 
 	if(doc == NULL) {
 		LM_WARN("invalid xml (pidf-lo): [%.*s]\n", pidf.len, pidf.s);
-		doc = xmlRecoverMemory(pidf.s, pidf.len);
+	doc = xmlReadMemory(pidf.s, pidf.len, 0, NULL,
+			XML_PARSE_NOBLANKS | XML_PARSE_NONET |
+			XML_PARSE_NOCDATA | XML_PARSE_RECOVER);
 		if(doc == NULL) {
 			LM_ERR("xml (pidf-lo) recovery failed on: [%.*s]\n", pidf.len,
 					pidf.s);
@@ -953,9 +959,55 @@ err:
 	return NULL;
 }
 
+/*
+ * lost_check_3d(node)
+ * checks if pos is 3D and returns 1 if true
+ * <gml:pos>-34.407 150.883 24.8</gml:pos>
+ */
+int lost_check_3d(xmlNodePtr node)
+{
+	xmlNodePtr cur = NULL;
+
+	char *content = NULL;
+	int ret = 0;
+
+	cur = node;
+	/* find <pos> element */
+	content = xmlNodeGetNodeContentByName(cur, "pos", NULL);
+
+	if(content == NULL) {
+		LM_WARN("could not find pos element\n");
+		return -1;
+	}
+
+	int len = 0;
+	char *tmp = lost_trim_content(content, &len);
+
+	if(len == 0) {
+		LM_WARN("could not find pos element\n");
+		xmlFree(content); /* clean up */
+		return -1;
+	}
+
+	int i = 0;
+	while(*tmp) {
+		if(isspace(*tmp))
+			i++;
+		tmp++;
+	}
+
+	if(i > 1) {
+		ret = 1;
+	}
+	/* clean up */
+	xmlFree(content);
+
+	return ret;
+}
+
 /*
  * lost_parse_geo(node, loc)
- * parses locationResponse (pos|circle) and writes
+ * parses locationResponse (pos|circle) and writes 
  * results to location object
  */
 int lost_parse_geo(xmlNodePtr node, p_lost_loc_t loc)
@@ -964,12 +1016,14 @@ int lost_parse_geo(xmlNodePtr node, p_lost_loc_t loc)
 
 	char bufLat[BUFSIZE];
 	char bufLon[BUFSIZE];
+	char bufAlt[BUFSIZE];
 	char *content = NULL;
 
-	char s_profile[] = LOST_PRO_GEO2D;
+	char *s_profile = LOST_PRO_GEO2D;
 
 	int iRadius = 0;
 	int len = 0;
+	int scan = 0;
 
 	cur = node;
 	/* find <pos> element */
@@ -980,9 +1034,14 @@ int lost_parse_geo(xmlNodePtr node, p_lost_loc_t loc)
 		return -1;
 	}
 
-	sscanf(content, "%s %s", bufLat, bufLon);
+	scan = sscanf(content, "%s %s %s", bufLat, bufLon, bufAlt);
 	xmlFree(content);
 
+	if(scan < 2) {
+		LM_WARN("invalid pos element\n");
+		return -1;
+	}
+	/* latitude */
 	len = strlen((char *)bufLat);
 	loc->latitude = (char *)pkg_malloc(len + 1);
 	if(loc->latitude == NULL)
@@ -990,6 +1049,7 @@ int lost_parse_geo(xmlNodePtr node, p_lost_loc_t loc)
 
 	snprintf(loc->latitude, len, "%s", (char *)bufLat);
 
+	/* logitude */
 	len = strlen((char *)bufLon);
 	loc->longitude = (char *)pkg_malloc(len + 1);
 	if(loc->longitude == NULL) {
@@ -999,15 +1059,40 @@ int lost_parse_geo(xmlNodePtr node, p_lost_loc_t loc)
 
 	snprintf(loc->longitude, len, "%s", (char *)bufLon);
 
+	/* altitude */
+	if(scan == 3) {
+		LM_INFO("3d geolocation in pos element\n");
+
+		len = strlen((char *)bufAlt);
+		loc->altitude = (char *)pkg_malloc(len + 1);
+		if(loc->altitude == NULL) {
+			pkg_free(loc->latitude);
+			pkg_free(loc->longitude);
+			goto err;
+		}
+		
+		snprintf(loc->altitude, len, "%s", (char *)bufAlt);
+	}
+
+	/* geolocation */
 	len = strlen((char *)bufLat) + strlen((char *)bufLon) + 1;
+	if((scan == 3) && (lost_geoloc_3d == 1)) {
+		len += strlen((char *)bufAlt);
+	}
 	loc->geodetic = (char *)pkg_malloc(len + 1);
-	if(loc->longitude == NULL) {
+	if(loc->geodetic == NULL) {
 		pkg_free(loc->latitude);
 		pkg_free(loc->longitude);
+		if(loc->altitude)
+			pkg_free(loc->altitude);
 		goto err;
 	}
-
-	snprintf(loc->geodetic, len, "%s %s", (char *)bufLat, (char *)bufLon);
+	if((scan == 3) && (lost_geoloc_3d == 1)) {
+		s_profile = LOST_PRO_GEO3D;
+		snprintf(loc->geodetic, len, "%s %s %s", (char *)bufLat, (char *)bufLon, (char *)bufAlt);
+	} else {
+		snprintf(loc->geodetic, len, "%s %s", (char *)bufLat, (char *)bufLon);
+	}
 
 	/* find <radius> element */
 	content = xmlNodeGetNodeContentByName(cur, "radius", NULL);
@@ -1030,7 +1115,7 @@ err:
 
 /*
  * lost_xpath_location(doc, path, loc)
- * performs xpath expression on locationResponse and writes
+ * performs xpath expression on locationResponse and writes 
  * results (location-info child element) to location object
  */
 int lost_xpath_location(xmlDocPtr doc, char *path, p_lost_loc_t loc)
@@ -1044,8 +1129,15 @@ int lost_xpath_location(xmlDocPtr doc, char *path, p_lost_loc_t loc)
 	xmlChar *xmlbuff = NULL;
 	xmlChar *cname = NULL;
 
+	/* shape representation RFC 5491 */
 	const unsigned char s_point[] = LOST_PNT;
+	const unsigned char s_polygon[] = LOST_POL;
 	const unsigned char s_circle[] = LOST_CIR;
+	const unsigned char s_ellipse[] = LOST_ELL;
+	const unsigned char s_arcband[] = LOST_ARC;
+	const unsigned char s_sphere[] = LOST_SPH;
+	const unsigned char s_ellipsoid[] = LOST_OID;
+	const unsigned char s_prism[] = LOST_PSM;
 	const unsigned char s_civic[] = LOST_CIV;
 
 	char *ptr = NULL;
@@ -1082,7 +1174,7 @@ int lost_xpath_location(xmlDocPtr doc, char *path, p_lost_loc_t loc)
 			}
 			if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
 				cur = nodes->nodeTab[i];
-				/* check if child element is point, circle or civic */
+				/* check if child element is point, circle, ... or civic */
 				while(nok < LOST_XPATH_DPTH) {
 					if(cur->children == NULL) {
 						/* no additional DOM level */
@@ -1092,15 +1184,39 @@ int lost_xpath_location(xmlDocPtr doc, char *path, p_lost_loc_t loc)
 						nok++;
 						cname = BAD_CAST cur->name;
 						if(xmlStrcasecmp(cname, s_point) == 0) {
+							if((lost_check_3d(cur) == 1)
+								&& (lost_geoloc_3d == 1)) {
+								s_profile = LOST_PRO_GEO3D;
+								selgeo = i;
+								break;
+							}
+							if(lost_check_3d(cur) == 0) {
+								s_profile = LOST_PRO_GEO2D;
+								selgeo = i;
+								break;
+							}
+						}
+						if(xmlStrcasecmp(cname, s_circle) == 0) {
 							s_profile = LOST_PRO_GEO2D;
 							selgeo = i;
 							break;
 						}
-						if(xmlStrcasecmp(cname, s_circle) == 0) {
+						if((xmlStrcasecmp(cname, s_polygon) == 0)
+							|| (xmlStrcasecmp(cname, s_ellipse) == 0)
+							|| (xmlStrcasecmp(cname, s_arcband) == 0)) {
 							s_profile = LOST_PRO_GEO2D;
 							selgeo = i;
 							break;
 						}
+						if((xmlStrcasecmp(cname, s_sphere) == 0)
+							|| (xmlStrcasecmp(cname, s_ellipsoid) == 0)
+							|| (xmlStrcasecmp(cname, s_prism) == 0)) {
+							if(lost_geoloc_3d == 1) {
+								s_profile = LOST_PRO_GEO3D;
+								selgeo = i;
+								break;
+							}
+						}
 						if(xmlStrcasecmp(cname, s_civic) == 0) {
 							s_profile = LOST_PRO_CIVIC;
 							selciv = i;
@@ -1115,8 +1231,8 @@ int lost_xpath_location(xmlDocPtr doc, char *path, p_lost_loc_t loc)
 					LM_DBG("xpath '%s' returned valid element (level %d/%d)\n",
 							xpath, nok, LOST_XPATH_DPTH);
 				} else if(nok < LOST_XPATH_DPTH) {
-					/* malformed pidf-lo but still ok */
-					LM_WARN("xpath '%s' returned malformed pidf-lo (level "
+					/* no matching location ... pidf-lo still ok */
+					LM_WARN("xpath '%s' shape representation not found (level "
 							"%d/%d)\n",
 							xpath, nok, LOST_XPATH_DPTH);
 				} else {
@@ -1205,8 +1321,9 @@ int lost_xpath_location(xmlDocPtr doc, char *path, p_lost_loc_t loc)
 					} else {
 						xmlFree(xmlbuff); /* clean up */
 						xmlFreeDoc(new);
+						LM_DBG("xpath '%s' no valid profile found\n", xpath);
 						xmlXPathFreeObject(result);
-						goto err;
+						return -1;
 					}
 					/* remove xml header from location element */
 					remove = strlen("<?xml version='1.0'?>\n");
@@ -1241,7 +1358,7 @@ int lost_xpath_location(xmlDocPtr doc, char *path, p_lost_loc_t loc)
 					pkg_free(ptr); /* clean up */
 					ptr = NULL;
 				} else {
-					LM_WARN("xpath location-info element(%d) ignored\n", i + 1);
+					LM_WARN("location-info element[%d] dropped!\n", i + 1);
 				}
 				/* clean up */
 				xmlFree(xmlbuff);
@@ -1251,7 +1368,7 @@ int lost_xpath_location(xmlDocPtr doc, char *path, p_lost_loc_t loc)
 			}
 		}
 	} else {
-		LM_WARN("xpath '%s' failed\n", xpath);
+		LM_WARN("xpath '%s' error\n", xpath);
 		xmlXPathFreeObject(result);
 		return -1;
 	}

+ 10 - 1
src/modules/lost/utilities.h

@@ -1,7 +1,7 @@
 /*
  * lost module utility functions
  *
- * Copyright (C) 2021 Wolfgang Kampichler
+ * Copyright (C) 2023 Wolfgang Kampichler
  * DEC112, FREQUENTIS AG
  *
  * This file is part of Kamailio, a free SIP server.
@@ -57,10 +57,18 @@
 	"gm=http://www.opengis.net/gml"
 
 #define LOST_PRO_GEO2D "geodetic-2d"
+#define LOST_PRO_GEO3D "geodetic-3d"
 #define LOST_PRO_CIVIC "civic"
 
+/* shape representation RFC 5491 */
 #define LOST_PNT "Point"
+#define LOST_POL "Polygon"
 #define LOST_CIR "Circle"
+#define LOST_ELL "Ellipse"
+#define LOST_ARC "ArcBand"
+#define LOST_SPH "Sphere"
+#define LOST_OID "Ellipsoid"
+#define LOST_PSM "Prism"
 #define LOST_CIV "civicAddress"
 
 #define HELD_TYPE_ANY "any"
@@ -89,6 +97,7 @@ typedef struct lost_loc
 	char *geodetic;	 /* geodetic location (findServiceRequest) */
 	char *longitude; /* geo longitude */
 	char *latitude;	 /* geo latitude */
+	char *altitude;  /* geo altitude */
 	char *profile;	 /* location profile (findServiceRequest) */
 	int radius;		 /* geo radius (findServiceRequest) */
 	int recursive;	 /* recursion true|false (findServiceRequest)*/