lost: adds HELD (RFC6155) and LOST (RFC5222) queries for location-based routing
[kamailio] / src / modules / lost / utilities.c
1 /*\r
2  * lost module utility functions\r
3  *\r
4  * Copyright (C) 2019 Wolfgang Kampichler\r
5  * DEC112, FREQUENTIS AG\r
6  *\r
7  * This file is part of Kamailio, a free SIP server.\r
8  *\r
9  * Kamailio is free software; you can redistribute it and/or modify\r
10  * it under the terms of the GNU General Public License as published by\r
11  * the Free Software Foundation; either version 2 of the License, or\r
12  * (at your option) any later version\r
13  *\r
14  * Kamailio is distributed in the hope that it will be useful,\r
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
17  * GNU General Public License for more details.\r
18  *\r
19  * You should have received a copy of the GNU General Public License\r
20  * along with this program; if not, write to the Free Software\r
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
22  *\r
23  */\r
24 \r
25 /*!\r
26  * \file\r
27  * \brief Kamailio lost :: utilities\r
28  * \ingroup lost\r
29  * Module: \ref lost\r
30  */\r
31 \r
32 #include <stdio.h>\r
33 #include <string.h>\r
34 #include <stdlib.h>\r
35 #include <ctype.h>\r
36 #include <time.h>\r
37 \r
38 #include <libxml/xmlmemory.h>\r
39 #include <libxml/parser.h>\r
40 #include "../../core/parser/msg_parser.h"\r
41 #include "../../core/parser/parse_content.h"\r
42 #include "../../core/parser/parse_uri.h"\r
43 #include "../../core/parser/parse_from.h"\r
44 #include "../../core/parser/parse_ppi_pai.h"\r
45 #include "../../core/dprint.h"\r
46 #include "../../core/mem/mem.h"\r
47 #include "../../core/mem/shm_mem.h"\r
48 \r
49 #include "pidf.h"\r
50 #include "utilities.h"\r
51 \r
52 /*\r
53  * lost_trim_content(dest, lgth)\r
54  * removes whitespace that my occur in a content of an xml element\r
55  */\r
56 char *lost_trim_content(char *str, int *lgth)\r
57 {\r
58         char *end;\r
59 \r
60         while(isspace(*str))\r
61                 str++;\r
62 \r
63         if(*str == 0)\r
64                 return NULL;\r
65 \r
66         end = str + strlen(str) - 1;\r
67 \r
68         while(end > str && isspace(*end))\r
69                 end--;\r
70 \r
71         *(end + 1) = '\0';\r
72 \r
73         *lgth = (end + 1) - str;\r
74 \r
75         return str;\r
76 }\r
77 \r
78 /*\r
79  * lost_rand_str(dest, length)\r
80  * creates a random string used as temporary id in a findService request\r
81  */\r
82 void lost_rand_str(char *dest, size_t lgth)\r
83 {\r
84         size_t index;\r
85         char charset[] = "0123456789"\r
86                                          "abcdefghijklmnopqrstuvwxyz"\r
87                                          "ABCDEFGHIJKLMNOPQRSTUVWXYZ";\r
88         srand(time(NULL));\r
89         while(lgth-- > 0) {\r
90                 index = (double)rand() / RAND_MAX * (sizeof charset - 1);\r
91                 *dest++ = charset[index];\r
92         }\r
93         *dest = '\0';\r
94 }\r
95 \r
96 /*\r
97  * lost_free_loc(ptr)\r
98  * frees a location object\r
99  */\r
100 void lost_free_loc(p_loc_t ptr)\r
101 {\r
102         pkg_free(ptr->identity);\r
103         pkg_free(ptr->urn);\r
104         pkg_free(ptr->longitude);\r
105         pkg_free(ptr->latitude);\r
106         pkg_free(ptr);\r
107 }\r
108 \r
109 /*\r
110  * lost_free_string(ptr)\r
111  * frees and resets a string\r
112  */\r
113 void lost_free_string(str *string)\r
114 {\r
115         str ptr = *string;\r
116 \r
117         if(ptr.s) {\r
118                 pkg_free(ptr.s);\r
119                 ptr.s = NULL;\r
120                 ptr.len = 0;\r
121         }\r
122 }\r
123 \r
124 /*\r
125  * lost_new_loc(urn)\r
126  * creates a new location object in private memory and returns a pointer\r
127  */\r
128 p_loc_t lost_new_loc(str rurn)\r
129 {\r
130         s_loc_t *ptr = NULL;;\r
131         char *id = NULL;\r
132         char *urn = NULL;\r
133 \r
134         ptr = (s_loc_t *)pkg_malloc(sizeof(s_loc_t));\r
135         if(ptr == NULL) {\r
136                 goto err;\r
137         }\r
138 \r
139         id = (char *)pkg_malloc(RANDSTRSIZE * sizeof(char) + 1);\r
140         if(id == NULL) {\r
141                 goto err;\r
142         }\r
143 \r
144         urn = (char *)pkg_malloc(rurn.len + 1);\r
145         if(urn == NULL) {\r
146                 goto err;\r
147         }\r
148 \r
149         memset(urn, 0, rurn.len + 1);\r
150         memcpy(urn, rurn.s, rurn.len);\r
151         urn[rurn.len] = '\0';\r
152 \r
153         lost_rand_str(id, RANDSTRSIZE);\r
154 \r
155         ptr->identity = id;\r
156         ptr->urn = urn;\r
157         ptr->longitude = NULL;\r
158         ptr->latitude = NULL;\r
159         ptr->radius = 0;\r
160         ptr->recursive = 0;\r
161 \r
162         return ptr;\r
163 \r
164 err:    \r
165         LM_ERR("no more private memory\n");\r
166         return NULL;\r
167 }\r
168 \r
169 /*\r
170  * lost_get_content(node, name, lgth)\r
171  * gets a nodes "name" content and returns string allocated in private memory\r
172  */\r
173 char *lost_get_content(xmlNodePtr node, const char *name, int *lgth)\r
174 {\r
175         xmlNodePtr cur = node;\r
176         char *content;\r
177         char *cnt = NULL;\r
178         int len;\r
179 \r
180         *lgth = 0;\r
181         content = xmlNodeGetNodeContentByName(cur, name, NULL);\r
182         len = strlen(content);\r
183 \r
184         cnt = (char *)pkg_malloc((len + 1) * sizeof(char));\r
185         if(cnt == NULL) {\r
186                 LM_ERR("No more private memory\n");\r
187                 return cnt;\r
188         }\r
189 \r
190         memset(cnt, 0, len + 1);\r
191         memcpy(cnt, content, len);\r
192         cnt[len] = '\0';\r
193 \r
194         *lgth = strlen(cnt);\r
195 \r
196         xmlFree(content);\r
197 \r
198         return cnt;\r
199 }\r
200 \r
201 /*\r
202  * lost_get_property(node, name, lgth)\r
203  * gets a nodes property "name" and returns string allocated in private memory\r
204  */\r
205 char *lost_get_property(xmlNodePtr node, const char *name, int *lgth)\r
206 {\r
207         xmlNodePtr cur = node;\r
208         char *content;\r
209         char *cnt = NULL;\r
210         int len;\r
211 \r
212         *lgth = 0;\r
213         content = xmlNodeGetAttrContentByName(cur, name);\r
214         len = strlen(content);\r
215 \r
216         cnt = (char *)pkg_malloc((len + 1) * sizeof(char));\r
217         if(cnt == NULL) {\r
218                 LM_ERR("No more private memory\n");\r
219                 return cnt;\r
220         }\r
221 \r
222         memset(cnt, 0, len + 1);\r
223         memcpy(cnt, content, len);\r
224         cnt[len] = '\0';\r
225 \r
226         *lgth = strlen(cnt);\r
227 \r
228         xmlFree(content);\r
229 \r
230         return cnt;\r
231 }\r
232 \r
233 /*\r
234  * lost_get_childname(name, lgth)\r
235  * gets a nodes child name and returns string allocated in private memory\r
236  */\r
237 char *lost_get_childname(xmlNodePtr node, const char *name, int *lgth)\r
238 {\r
239         xmlNodePtr cur = node;\r
240         xmlNodePtr parent = NULL;\r
241         xmlNodePtr child = NULL;\r
242         char *cnt = NULL;\r
243         int len;\r
244 \r
245         *lgth = 0;\r
246         parent = xmlNodeGetNodeByName(cur, name, NULL);\r
247         child = parent->children;\r
248 \r
249         if(child) {\r
250                 len = strlen((char *)child->name);\r
251                 cnt = (char *)pkg_malloc((len + 1) * sizeof(char));\r
252                 if(cnt == NULL) {\r
253                         LM_ERR("no more private memory\n");\r
254                         return cnt;\r
255                 }\r
256 \r
257                 memset(cnt, 0, len + 1);\r
258                 memcpy(cnt, child->name, len);\r
259                 cnt[len] = '\0';\r
260 \r
261                 *lgth = strlen(cnt);\r
262         }\r
263         return cnt;\r
264 }\r
265 \r
266 /*\r
267  * lost_get_geolocation_header(msg, lgth)\r
268  * gets the Geolocation header value and returns string allocated in\r
269  * private memory\r
270  */\r
271 char *lost_get_geolocation_header(struct sip_msg *msg, int *lgth)\r
272 {\r
273         struct hdr_field *hf;\r
274         char *res = NULL;\r
275 \r
276         *lgth = 0;\r
277 \r
278         parse_headers(msg, HDR_EOH_F, 0);\r
279 \r
280         for(hf = msg->headers; hf; hf = hf->next) {\r
281                 if((hf->type == HDR_OTHER_T)\r
282                                 && (hf->name.len == LOST_GEOLOC_HEADER_SIZE - 2)) {\r
283                         /* possible hit */\r
284                         if(strncasecmp(\r
285                                            hf->name.s, LOST_GEOLOC_HEADER, LOST_GEOLOC_HEADER_SIZE)\r
286                                         == 0) {\r
287 \r
288                                 res = (char *)pkg_malloc((hf->body.len + 1) * sizeof(char));\r
289                                 if(res == NULL) {\r
290                                         LM_ERR("no more private memory\n");\r
291                                         return res;\r
292                                 } else {\r
293                                         memset(res, 0, hf->body.len + 1);\r
294                                         memcpy(res, hf->body.s, hf->body.len + 1);\r
295                                         res[hf->body.len] = '\0';\r
296 \r
297                                         *lgth = strlen(res);\r
298                                 }\r
299                         } else {\r
300                                 LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,\r
301                                                 hf->body.len);\r
302                         }\r
303                         break;\r
304                 }\r
305         }\r
306         return res;\r
307 }\r
308 \r
309 /*\r
310  * lost_get_pai_header(msg, lgth)\r
311  * gets the P-A-I header value and returns string allocated in\r
312  * private memory\r
313  */\r
314 char *lost_get_pai_header(struct sip_msg *msg, int *lgth)\r
315 {\r
316         struct hdr_field *hf;\r
317         char *res = NULL;\r
318 \r
319         *lgth = 0;\r
320 \r
321         parse_headers(msg, HDR_PAI_F, 0);\r
322 \r
323         for(hf = msg->headers; hf; hf = hf->next) {\r
324                 if((hf->type == HDR_PAI_T)\r
325                                 && (hf->name.len == LOST_PAI_HEADER_SIZE - 2)) {\r
326                         /* possible hit */\r
327                         if(strncasecmp(hf->name.s, LOST_PAI_HEADER, LOST_PAI_HEADER_SIZE)\r
328                                         == 0) {\r
329                                 res = (char *)pkg_malloc((hf->body.len + 1) * sizeof(char));\r
330                                 if(res == NULL) {\r
331                                         LM_ERR("no more private memory\n");\r
332                                         return res;\r
333                                 } else {\r
334 \r
335                                         memset(res, 0, hf->body.len + 1);\r
336                                         memcpy(res, hf->body.s, hf->body.len + 1);\r
337                                         res[hf->body.len] = '\0';\r
338 \r
339                                         *lgth = strlen(res);\r
340                                 }\r
341                         } else {\r
342                                 LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,\r
343                                                 hf->body.len);\r
344                         }\r
345                         break;\r
346                 }\r
347         }\r
348         return res;\r
349 }\r
350 \r
351 /*\r
352  * lost_get_from_header(msg, lgth)\r
353  * gets the From header value and returns string allocated in\r
354  * private memory\r
355  */\r
356 char *lost_get_from_header(struct sip_msg *msg, int *lgth)\r
357 {\r
358         to_body_t *f_body;\r
359         char *res = NULL;\r
360 \r
361         *lgth = 0;\r
362 \r
363         parse_headers(msg, HDR_FROM_F, 0);\r
364 \r
365         if(msg->from == NULL || get_from(msg) == NULL) {\r
366                 LM_ERR("From header not found\n");\r
367                 return res;\r
368         }\r
369         f_body = get_from(msg);\r
370         res = (char *)pkg_malloc((f_body->uri.len + 1) * sizeof(char));\r
371         if(res == NULL) {\r
372                 LM_ERR("no more private memory\n");\r
373                 return res;\r
374         } else {\r
375                 memset(res, 0, f_body->uri.len + 1);\r
376                 memcpy(res, f_body->uri.s, f_body->uri.len + 1);\r
377                 res[f_body->uri.len] = '\0';\r
378 \r
379                 *lgth = strlen(res);\r
380         }\r
381         return res;\r
382 }\r
383 \r
384 /*\r
385  * lost_parse_location_info(node, loc)\r
386  * parses locationResponse and writes results to location object\r
387  */\r
388 int lost_parse_location_info(xmlNodePtr node, p_loc_t loc)\r
389 {\r
390         char bufLat[BUFSIZE];\r
391         char bufLon[BUFSIZE];\r
392         int iRadius;\r
393         char *content = NULL;\r
394         int ret = -1;\r
395 \r
396         xmlNodePtr cur = node;\r
397 \r
398         content = xmlNodeGetNodeContentByName(cur, "pos", NULL);\r
399         if(content) {\r
400                 sscanf(content, "%s %s", bufLat, bufLon);\r
401 \r
402                 loc->latitude = (char *)pkg_malloc(strlen((char *)bufLat) + 1);\r
403                 snprintf(loc->latitude, strlen((char *)bufLat) + 1, "%s",\r
404                                 (char *)bufLat);\r
405 \r
406                 loc->longitude = (char *)pkg_malloc(strlen((char *)bufLon) + 1);\r
407                 snprintf(loc->longitude, strlen((char *)bufLon) + 1, "%s",\r
408                                 (char *)bufLon);\r
409 \r
410                 loc->radius = 0;\r
411                 ret = 0;\r
412         }\r
413 \r
414         content = xmlNodeGetNodeContentByName(cur, "radius", NULL);\r
415         if(content) {\r
416                 iRadius = 0;\r
417 \r
418                 sscanf(content, "%d", &iRadius);\r
419                 loc->radius = iRadius;\r
420                 ret = 0;\r
421         }\r
422 \r
423         if(ret < 0) {\r
424                 LM_ERR("could not parse location information\n");\r
425         }\r
426         return ret;\r
427 }\r
428 \r
429 /*\r
430  * lost_held_location_request(id, lgth)\r
431  * assembles and returns locationRequest string (allocated in private memory)\r
432  */\r
433 char *lost_held_location_request(char *id, int *lgth)\r
434 {\r
435         int buffersize = 0;\r
436 \r
437         char buf[BUFSIZE];\r
438         char *doc = NULL;\r
439 \r
440         xmlChar *xmlbuff = NULL;\r
441         xmlDocPtr request = NULL;\r
442 \r
443         xmlNodePtr ptrLocationRequest = NULL;\r
444         xmlNodePtr ptrLocationType = NULL;\r
445         xmlNodePtr ptrDevice = NULL;\r
446 \r
447         xmlKeepBlanksDefault(1);\r
448         *lgth = 0;\r
449 \r
450         /*\r
451 https://tools.ietf.org/html/rfc6155\r
452 \r
453 <?xml version="1.0" encoding="UTF-8"?>\r
454 <locationRequest xmlns="urn:ietf:params:xml:ns:geopriv:held" responseTime="8">\r
455     <locationType exact="true">geodetic locationURI</locationType>\r
456     <device xmlns="urn:ietf:params:xml:ns:geopriv:held:id">\r
457         <uri>sip:user@example.net</uri>\r
458     </device>\r
459 </locationRequest>\r
460 */\r
461 \r
462         /* create request */\r
463         request = xmlNewDoc(BAD_CAST "1.0");\r
464         if(!request) {\r
465                 LM_ERR("locationRequest xmlNewDoc() failed\n");\r
466                 return doc;\r
467         }\r
468         /* locationRequest - element */\r
469         ptrLocationRequest = xmlNewNode(NULL, BAD_CAST "locationRequest");\r
470         if(!ptrLocationRequest) {\r
471                 LM_ERR("locationRequest xmlNewNode() failed\n");\r
472                 return doc;\r
473         }\r
474         xmlDocSetRootElement(request, ptrLocationRequest);\r
475         /* properties */\r
476         xmlNewProp(ptrLocationRequest, BAD_CAST "xmlns",\r
477                         BAD_CAST "urn:ietf:params:xml:ns:geopriv:held");\r
478         xmlNewProp(ptrLocationRequest, BAD_CAST "responseTime", BAD_CAST "8");\r
479         /* locationType - element */\r
480         ptrLocationType = xmlNewChild(ptrLocationRequest, NULL,\r
481                         BAD_CAST "locationType", BAD_CAST "geodetic locationURI");\r
482         /* properties */\r
483         xmlNewProp(ptrLocationType, BAD_CAST "exact", BAD_CAST "false");\r
484         /* device - element */\r
485         ptrDevice = xmlNewChild(ptrLocationRequest, NULL, BAD_CAST "device", NULL);\r
486         if(!ptrDevice) {\r
487                 LM_ERR("locationRequest xmlNewChild() failed\n");\r
488                 return doc;\r
489         }\r
490         /* properties */\r
491         xmlNewProp(ptrDevice, BAD_CAST "xmlns",\r
492                         BAD_CAST "urn:ietf:params:xml:ns:geopriv:held:id");\r
493         /* uri - element */\r
494         snprintf(buf, BUFSIZE, "%s", id);\r
495         xmlNewChild(ptrDevice, NULL, BAD_CAST "uri", BAD_CAST buf);\r
496 \r
497         xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);\r
498         if(!xmlbuff) {\r
499                 LM_ERR("locationRequest xmlDocDumpFormatMemory() failed\n");\r
500                 return doc;\r
501         }\r
502 \r
503         doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));\r
504         if(doc == NULL) {\r
505                 LM_ERR("no more private memory\n");\r
506                 return doc;\r
507         }\r
508 \r
509         memset(doc, 0, buffersize + 1);\r
510         memcpy(doc, (char *)xmlbuff, buffersize);\r
511         doc[buffersize] = '\0';\r
512 \r
513         *lgth = strlen(doc);\r
514 \r
515         xmlFree(xmlbuff);\r
516         xmlFreeDoc(request);\r
517 \r
518         return doc;\r
519 }\r
520 \r
521 /*\r
522  * lost_find_service_request(loc, lgth)\r
523  * assembles and returns findService request string (allocated in private memory)\r
524  */\r
525 char *lost_find_service_request(p_loc_t loc, int *lgth)\r
526 {\r
527         int buffersize = 0;\r
528 \r
529         char buf[BUFSIZE];\r
530         char *doc = NULL;\r
531 \r
532         xmlChar *xmlbuff = NULL;\r
533         xmlDocPtr request = NULL;\r
534 \r
535         xmlNodePtr ptrFindService = NULL;\r
536         xmlNodePtr ptrLocation = NULL;\r
537         xmlNodePtr ptrPoint = NULL;\r
538         xmlNodePtr ptrCircle = NULL;\r
539         xmlNodePtr ptrRadius = NULL;\r
540 \r
541         xmlKeepBlanksDefault(1);\r
542         *lgth = 0;\r
543 \r
544         /*\r
545 https://tools.ietf.org/html/rfc5222\r
546 \r
547 <?xml version="1.0" encoding="UTF-8"?>\r
548 <findService\r
549  xmlns="urn:ietf:params:xml:ns:lost1"\r
550  xmlns:p2="http://www.opengis.net/gml"\r
551  serviceBoundary="value"\r
552  recursive="true">\r
553     <location id="6020688f1ce1896d" profile="geodetic-2d">\r
554         <p2:Point id="point1" srsName="urn:ogc:def:crs:EPSG::4326">\r
555             <p2:pos>37.775 -122.422</p2:pos>\r
556         </p2:Point>\r
557     </location>\r
558     <service>urn:service:sos.police</service>\r
559 </findService>\r
560  */\r
561         /* create request */\r
562         request = xmlNewDoc(BAD_CAST "1.0");\r
563         if(!request) {\r
564                 LM_ERR("findService request xmlNewDoc() failed\n");\r
565                 return doc;\r
566         }\r
567         /* findService - element */\r
568         ptrFindService = xmlNewNode(NULL, BAD_CAST "findService");\r
569         if(!ptrFindService) {\r
570                 LM_ERR("findService xmlNewNode() failed\n");\r
571                 return doc;\r
572         }\r
573         xmlDocSetRootElement(request, ptrFindService);\r
574         /* set properties */\r
575         xmlNewProp(ptrFindService, BAD_CAST "xmlns",\r
576                         BAD_CAST "urn:ietf:params:xml:ns:lost1");\r
577         xmlNewProp(ptrFindService, BAD_CAST "xmlns:p2",\r
578                         BAD_CAST "http://www.opengis.net/gml");\r
579         xmlNewProp(\r
580                         ptrFindService, BAD_CAST "serviceBoundary", BAD_CAST "reference");\r
581         xmlNewProp(ptrFindService, BAD_CAST "recursive", BAD_CAST "true");\r
582         /* location - element */\r
583         ptrLocation = xmlNewChild(ptrFindService, NULL, BAD_CAST "location", NULL);\r
584         xmlNewProp(ptrLocation, BAD_CAST "id", BAD_CAST loc->identity);\r
585         xmlNewProp(ptrLocation, BAD_CAST "profile", BAD_CAST "geodetic-2d");\r
586         /* set pos */\r
587         snprintf(buf, BUFSIZE, "%s %s", loc->latitude, loc->longitude);\r
588         /* Point */\r
589         if(loc->radius == 0) {\r
590                 ptrPoint = xmlNewChild(ptrLocation, NULL, BAD_CAST "Point", NULL);\r
591                 if(!ptrPoint) {\r
592                         LM_ERR("locationRequest xmlNewChild() failed\n");\r
593                         return doc;\r
594                 }\r
595                 xmlNewProp(ptrPoint, BAD_CAST "xmlns",\r
596                                 BAD_CAST "http://www.opengis.net/gml");\r
597                 xmlNewProp(ptrPoint, BAD_CAST "srsName",\r
598                                 BAD_CAST "urn:ogc:def:crs:EPSG::4326");\r
599                 /* pos */\r
600                 xmlNewChild(ptrPoint, NULL, BAD_CAST "pos", BAD_CAST buf);\r
601         } else {\r
602                 /* circle - Point */\r
603                 ptrCircle = xmlNewChild(ptrLocation, NULL, BAD_CAST "gs:Circle", NULL);\r
604                 if(!ptrCircle) {\r
605                         LM_ERR("locationRequest xmlNewChild() failed\n");\r
606                         return doc;\r
607                 }\r
608                 xmlNewProp(ptrCircle, BAD_CAST "xmlns:gml",\r
609                                 BAD_CAST "http://www.opengis.net/gml");\r
610                 xmlNewProp(ptrCircle, BAD_CAST "xmlns:gs",\r
611                                 BAD_CAST "http://www.opengis.net/pidflo/1.0");\r
612                 xmlNewProp(ptrCircle, BAD_CAST "srsName",\r
613                                 BAD_CAST "urn:ogc:def:crs:EPSG::4326");\r
614                 /* pos */\r
615                 xmlNewChild(ptrCircle, NULL, BAD_CAST "gml:pos", BAD_CAST buf);\r
616                 /* circle - radius */\r
617                 snprintf(buf, BUFSIZE, "%d", loc->radius);\r
618                 ptrRadius = xmlNewChild(\r
619                                 ptrCircle, NULL, BAD_CAST "gs:radius", BAD_CAST buf);\r
620                 if(!ptrRadius) {\r
621                         LM_ERR("locationRequest xmlNewChild() failed\n");\r
622                         return doc;\r
623                 }\r
624                 xmlNewProp(ptrRadius, BAD_CAST "uom",\r
625                                 BAD_CAST "urn:ogc:def:uom:EPSG::9001");\r
626         }\r
627         /* service - element */\r
628         snprintf(buf, BUFSIZE, "%s", loc->urn);\r
629         xmlNewChild(ptrFindService, NULL, BAD_CAST "service", BAD_CAST buf);\r
630 \r
631         xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);\r
632         if(!xmlbuff) {\r
633                 LM_ERR("findService request xmlDocDumpFormatMemory() failed\n");\r
634                 return doc;\r
635         }\r
636 \r
637         doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));\r
638         if(doc == NULL) {\r
639                 LM_ERR("no more private memory\n");\r
640                 return doc;\r
641         }\r
642 \r
643         memset(doc, 0, buffersize + 1);\r
644         memcpy(doc, (char *)xmlbuff, buffersize);\r
645         doc[buffersize] = '\0';\r
646 \r
647         *lgth = strlen(doc);\r
648 \r
649         xmlFree(xmlbuff);\r
650         xmlFreeDoc(request);\r
651 \r
652         return doc;\r
653 }