78fb45caab5abb5f08008c9f819734c11421f5f1
[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  * freess 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 void lost_free_string(str *string)\r
110 {\r
111         str ptr = *string;\r
112 \r
113         if(ptr.s) {\r
114                 pkg_free(ptr.s);\r
115                 ptr.s = NULL;\r
116                 ptr.len = 0;\r
117         }\r
118 }\r
119 \r
120 /*\r
121  * lost_new_loc(urn)\r
122  * creates a new location object in private memory and returns a pointer\r
123  */\r
124 p_loc_t lost_new_loc(str rurn)\r
125 {\r
126         s_loc_t *ptr = NULL;;\r
127         char *id = NULL;\r
128         char *urn = NULL;\r
129 \r
130         ptr = (s_loc_t *)pkg_malloc(sizeof(s_loc_t));\r
131         if(ptr == NULL) {\r
132                 goto err;\r
133         }\r
134 \r
135         id = (char *)pkg_malloc(RANDSTRSIZE * sizeof(char) + 1);\r
136         if(id == NULL) {\r
137                 goto err;\r
138         }\r
139 \r
140         urn = (char *)pkg_malloc(rurn.len + 1);\r
141         if(urn == NULL) {\r
142                 goto err;\r
143         }\r
144 \r
145         memset(urn, 0, rurn.len + 1);\r
146         memcpy(urn, rurn.s, rurn.len);\r
147         urn[rurn.len] = '\0';\r
148 \r
149         lost_rand_str(id, RANDSTRSIZE);\r
150 \r
151         ptr->identity = id;\r
152         ptr->urn = urn;\r
153         ptr->longitude = NULL;\r
154         ptr->latitude = NULL;\r
155         ptr->radius = 0;\r
156         ptr->recursive = 0;\r
157 \r
158         return ptr;\r
159 \r
160 err:    \r
161         LM_ERR("no more private memory\n");\r
162         return NULL;\r
163 }\r
164 \r
165 /*\r
166  * lost_get_content(node, name, lgth)\r
167  * gets a nodes "name" content and returns string allocated in private memory\r
168  */\r
169 char *lost_get_content(xmlNodePtr node, const char *name, int *lgth)\r
170 {\r
171         xmlNodePtr cur = node;\r
172         char *content;\r
173         char *cnt = NULL;\r
174         int len;\r
175 \r
176         *lgth = 0;\r
177         content = xmlNodeGetNodeContentByName(cur, name, NULL);\r
178         len = strlen(content);\r
179 \r
180         cnt = (char *)pkg_malloc((len + 1) * sizeof(char));\r
181         if(cnt == NULL) {\r
182                 LM_ERR("No more private memory\n");\r
183                 return cnt;\r
184         }\r
185 \r
186         memset(cnt, 0, len + 1);\r
187         memcpy(cnt, content, len);\r
188         cnt[len] = '\0';\r
189 \r
190         *lgth = strlen(cnt);\r
191 \r
192         xmlFree(content);\r
193 \r
194         return cnt;\r
195 }\r
196 \r
197 /*\r
198  * lost_get_property(node, name, lgth)\r
199  * gets a nodes property "name" and returns string allocated in private memory\r
200  */\r
201 char *lost_get_property(xmlNodePtr node, const char *name, int *lgth)\r
202 {\r
203         xmlNodePtr cur = node;\r
204         char *content;\r
205         char *cnt = NULL;\r
206         int len;\r
207 \r
208         *lgth = 0;\r
209         content = xmlNodeGetAttrContentByName(cur, name);\r
210         len = strlen(content);\r
211 \r
212         cnt = (char *)pkg_malloc((len + 1) * sizeof(char));\r
213         if(cnt == NULL) {\r
214                 LM_ERR("No more private memory\n");\r
215                 return cnt;\r
216         }\r
217 \r
218         memset(cnt, 0, len + 1);\r
219         memcpy(cnt, content, len);\r
220         cnt[len] = '\0';\r
221 \r
222         *lgth = strlen(cnt);\r
223 \r
224         xmlFree(content);\r
225 \r
226         return cnt;\r
227 }\r
228 \r
229 /*\r
230  * lost_get_childname(name, lgth)\r
231  * gets a nodes child name and returns string allocated in private memory\r
232  */\r
233 char *lost_get_childname(xmlNodePtr node, const char *name, int *lgth)\r
234 {\r
235         xmlNodePtr cur = node;\r
236         xmlNodePtr parent = NULL;\r
237         xmlNodePtr child = NULL;\r
238         char *cnt = NULL;\r
239         int len;\r
240 \r
241         *lgth = 0;\r
242         parent = xmlNodeGetNodeByName(cur, name, NULL);\r
243         child = parent->children;\r
244 \r
245         if(child) {\r
246                 len = strlen((char *)child->name);\r
247                 cnt = (char *)pkg_malloc((len + 1) * sizeof(char));\r
248                 if(cnt == NULL) {\r
249                         LM_ERR("no more private memory\n");\r
250                         return cnt;\r
251                 }\r
252 \r
253                 memset(cnt, 0, len + 1);\r
254                 memcpy(cnt, child->name, len);\r
255                 cnt[len] = '\0';\r
256 \r
257                 *lgth = strlen(cnt);\r
258         }\r
259         return cnt;\r
260 }\r
261 \r
262 /*\r
263  * lost_get_geolocation_header(msg, lgth)\r
264  * gets the Geolocation header value and returns string allocated in\r
265  * private memory\r
266  */\r
267 char *lost_get_geolocation_header(struct sip_msg *msg, int *lgth)\r
268 {\r
269         struct hdr_field *hf;\r
270         char *res = NULL;\r
271 \r
272         *lgth = 0;\r
273 \r
274         parse_headers(msg, HDR_EOH_F, 0);\r
275 \r
276         for(hf = msg->headers; hf; hf = hf->next) {\r
277                 if((hf->type == HDR_OTHER_T)\r
278                                 && (hf->name.len == LOST_GEOLOC_HEADER_SIZE - 2)) {\r
279                         /* possible hit */\r
280                         if(strncasecmp(\r
281                                            hf->name.s, LOST_GEOLOC_HEADER, LOST_GEOLOC_HEADER_SIZE)\r
282                                         == 0) {\r
283 \r
284                                 res = (char *)pkg_malloc((hf->body.len + 1) * sizeof(char));\r
285                                 if(res == NULL) {\r
286                                         LM_ERR("no more private memory\n");\r
287                                         return res;\r
288                                 } else {\r
289                                         memset(res, 0, hf->body.len + 1);\r
290                                         memcpy(res, hf->body.s, hf->body.len + 1);\r
291                                         res[hf->body.len] = '\0';\r
292 \r
293                                         *lgth = strlen(res);\r
294                                 }\r
295                         } else {\r
296                                 LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,\r
297                                                 hf->body.len);\r
298                         }\r
299                         break;\r
300                 }\r
301         }\r
302         return res;\r
303 }\r
304 \r
305 /*\r
306  * lost_get_pai_header(msg, lgth)\r
307  * gets the P-A-I header value and returns string allocated in\r
308  * private memory\r
309  */\r
310 char *lost_get_pai_header(struct sip_msg *msg, int *lgth)\r
311 {\r
312         struct hdr_field *hf;\r
313         char *res = NULL;\r
314 \r
315         *lgth = 0;\r
316 \r
317         parse_headers(msg, HDR_PAI_F, 0);\r
318 \r
319         for(hf = msg->headers; hf; hf = hf->next) {\r
320                 if((hf->type == HDR_PAI_T)\r
321                                 && (hf->name.len == LOST_PAI_HEADER_SIZE - 2)) {\r
322                         /* possible hit */\r
323                         if(strncasecmp(hf->name.s, LOST_PAI_HEADER, LOST_PAI_HEADER_SIZE)\r
324                                         == 0) {\r
325                                 res = (char *)pkg_malloc((hf->body.len + 1) * sizeof(char));\r
326                                 if(res == NULL) {\r
327                                         LM_ERR("no more private memory\n");\r
328                                         return res;\r
329                                 } else {\r
330 \r
331                                         memset(res, 0, hf->body.len + 1);\r
332                                         memcpy(res, hf->body.s, hf->body.len + 1);\r
333                                         res[hf->body.len] = '\0';\r
334 \r
335                                         *lgth = strlen(res);\r
336                                 }\r
337                         } else {\r
338                                 LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,\r
339                                                 hf->body.len);\r
340                         }\r
341                         break;\r
342                 }\r
343         }\r
344         return res;\r
345 }\r
346 \r
347 /*\r
348  * lost_get_from_header(msg, lgth)\r
349  * gets the From header value and returns string allocated in\r
350  * private memory\r
351  */\r
352 char *lost_get_from_header(struct sip_msg *msg, int *lgth)\r
353 {\r
354         to_body_t *f_body;\r
355         char *res = NULL;\r
356 \r
357         *lgth = 0;\r
358 \r
359         parse_headers(msg, HDR_FROM_F, 0);\r
360 \r
361         if(msg->from == NULL || get_from(msg) == NULL) {\r
362                 LM_ERR("From header not found\n");\r
363                 return res;\r
364         }\r
365         f_body = get_from(msg);\r
366         res = (char *)pkg_malloc((f_body->uri.len + 1) * sizeof(char));\r
367         if(res == NULL) {\r
368                 LM_ERR("no more private memory\n");\r
369                 return res;\r
370         } else {\r
371                 memset(res, 0, f_body->uri.len + 1);\r
372                 memcpy(res, f_body->uri.s, f_body->uri.len + 1);\r
373                 res[f_body->uri.len] = '\0';\r
374 \r
375                 *lgth = strlen(res);\r
376         }\r
377         return res;\r
378 }\r
379 \r
380 /*\r
381  * lost_parse_location_info(node, loc)\r
382  * parses locationResponse and writes results to location object\r
383  */\r
384 int lost_parse_location_info(xmlNodePtr node, p_loc_t loc)\r
385 {\r
386         char bufLat[BUFSIZE];\r
387         char bufLon[BUFSIZE];\r
388         int iRadius;\r
389         char *content = NULL;\r
390         int ret = -1;\r
391 \r
392         xmlNodePtr cur = node;\r
393 \r
394         content = xmlNodeGetNodeContentByName(cur, "pos", NULL);\r
395         if(content) {\r
396                 sscanf(content, "%s %s", bufLat, bufLon);\r
397 \r
398                 loc->latitude = (char *)pkg_malloc(strlen((char *)bufLat) + 1);\r
399                 snprintf(loc->latitude, strlen((char *)bufLat) + 1, "%s",\r
400                                 (char *)bufLat);\r
401 \r
402                 loc->longitude = (char *)pkg_malloc(strlen((char *)bufLon) + 1);\r
403                 snprintf(loc->longitude, strlen((char *)bufLon) + 1, "%s",\r
404                                 (char *)bufLon);\r
405 \r
406                 loc->radius = 0;\r
407                 ret = 0;\r
408         }\r
409 \r
410         content = xmlNodeGetNodeContentByName(cur, "radius", NULL);\r
411         if(content) {\r
412                 iRadius = 0;\r
413 \r
414                 sscanf(content, "%d", &iRadius);\r
415                 loc->radius = iRadius;\r
416                 ret = 0;\r
417         }\r
418 \r
419         if(ret < 0) {\r
420                 LM_ERR("could not parse location information\n");\r
421         }\r
422         return ret;\r
423 }\r
424 \r
425 /*\r
426  * lost_held_location_request(id, lgth)\r
427  * assembles and returns locationRequest string (allocated in private memory)\r
428  */\r
429 char *lost_held_location_request(char *id, int *lgth)\r
430 {\r
431         int buffersize = 0;\r
432 \r
433         char buf[BUFSIZE];\r
434         char *doc = NULL;\r
435 \r
436         xmlChar *xmlbuff = NULL;\r
437         xmlDocPtr request = NULL;\r
438 \r
439         xmlNodePtr ptrLocationRequest = NULL;\r
440         xmlNodePtr ptrLocationType = NULL;\r
441         xmlNodePtr ptrDevice = NULL;\r
442 \r
443         xmlKeepBlanksDefault(1);\r
444         *lgth = 0;\r
445 \r
446         /*\r
447 https://tools.ietf.org/html/rfc6155\r
448 \r
449 <?xml version="1.0" encoding="UTF-8"?>\r
450 <locationRequest xmlns="urn:ietf:params:xml:ns:geopriv:held" responseTime="8">\r
451     <locationType exact="true">geodetic locationURI</locationType>\r
452     <device xmlns="urn:ietf:params:xml:ns:geopriv:held:id">\r
453         <uri>sip:user@example.net</uri>\r
454     </device>\r
455 </locationRequest>\r
456 */\r
457 \r
458         /* create request */\r
459         request = xmlNewDoc(BAD_CAST "1.0");\r
460         if(!request) {\r
461                 LM_ERR("locationRequest xmlNewDoc() failed\n");\r
462                 return doc;\r
463         }\r
464         /* locationRequest - element */\r
465         ptrLocationRequest = xmlNewNode(NULL, BAD_CAST "locationRequest");\r
466         if(!ptrLocationRequest) {\r
467                 LM_ERR("locationRequest xmlNewNode() failed\n");\r
468                 return doc;\r
469         }\r
470         xmlDocSetRootElement(request, ptrLocationRequest);\r
471         /* properties */\r
472         xmlNewProp(ptrLocationRequest, BAD_CAST "xmlns",\r
473                         BAD_CAST "urn:ietf:params:xml:ns:geopriv:held");\r
474         xmlNewProp(ptrLocationRequest, BAD_CAST "responseTime", BAD_CAST "8");\r
475         /* locationType - element */\r
476         ptrLocationType = xmlNewChild(ptrLocationRequest, NULL,\r
477                         BAD_CAST "locationType", BAD_CAST "geodetic locationURI");\r
478         /* properties */\r
479         xmlNewProp(ptrLocationType, BAD_CAST "exact", BAD_CAST "false");\r
480         /* device - element */\r
481         ptrDevice = xmlNewChild(ptrLocationRequest, NULL, BAD_CAST "device", NULL);\r
482         if(!ptrDevice) {\r
483                 LM_ERR("locationRequest xmlNewChild() failed\n");\r
484                 return doc;\r
485         }\r
486         /* properties */\r
487         xmlNewProp(ptrDevice, BAD_CAST "xmlns",\r
488                         BAD_CAST "urn:ietf:params:xml:ns:geopriv:held:id");\r
489         /* uri - element */\r
490         snprintf(buf, BUFSIZE, "%s", id);\r
491         xmlNewChild(ptrDevice, NULL, BAD_CAST "uri", BAD_CAST buf);\r
492 \r
493         xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);\r
494         if(!xmlbuff) {\r
495                 LM_ERR("locationRequest xmlDocDumpFormatMemory() failed\n");\r
496                 return doc;\r
497         }\r
498 \r
499         doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));\r
500         if(doc == NULL) {\r
501                 LM_ERR("no more private memory\n");\r
502                 return doc;\r
503         }\r
504 \r
505         memset(doc, 0, buffersize + 1);\r
506         memcpy(doc, (char *)xmlbuff, buffersize);\r
507         doc[buffersize] = '\0';\r
508 \r
509         *lgth = strlen(doc);\r
510 \r
511         xmlFree(xmlbuff);\r
512         xmlFreeDoc(request);\r
513 \r
514         return doc;\r
515 }\r
516 \r
517 /*\r
518  * lost_find_service_request(loc, lgth)\r
519  * assembles and returns findService request string (allocated in private memory)\r
520  */\r
521 char *lost_find_service_request(p_loc_t loc, int *lgth)\r
522 {\r
523         int buffersize = 0;\r
524 \r
525         char buf[BUFSIZE];\r
526         char *doc = NULL;\r
527 \r
528         xmlChar *xmlbuff = NULL;\r
529         xmlDocPtr request = NULL;\r
530 \r
531         xmlNodePtr ptrFindService = NULL;\r
532         xmlNodePtr ptrLocation = NULL;\r
533         xmlNodePtr ptrPoint = NULL;\r
534         xmlNodePtr ptrCircle = NULL;\r
535         xmlNodePtr ptrRadius = NULL;\r
536 \r
537         xmlKeepBlanksDefault(1);\r
538         *lgth = 0;\r
539 \r
540         /*\r
541 https://tools.ietf.org/html/rfc5222\r
542 \r
543 <?xml version="1.0" encoding="UTF-8"?>\r
544 <findService\r
545  xmlns="urn:ietf:params:xml:ns:lost1"\r
546  xmlns:p2="http://www.opengis.net/gml"\r
547  serviceBoundary="value"\r
548  recursive="true">\r
549     <location id="6020688f1ce1896d" profile="geodetic-2d">\r
550         <p2:Point id="point1" srsName="urn:ogc:def:crs:EPSG::4326">\r
551             <p2:pos>37.775 -122.422</p2:pos>\r
552         </p2:Point>\r
553     </location>\r
554     <service>urn:service:sos.police</service>\r
555 </findService>\r
556  */\r
557         /* create request */\r
558         request = xmlNewDoc(BAD_CAST "1.0");\r
559         if(!request) {\r
560                 LM_ERR("findService request xmlNewDoc() failed\n");\r
561                 return doc;\r
562         }\r
563         /* findService - element */\r
564         ptrFindService = xmlNewNode(NULL, BAD_CAST "findService");\r
565         if(!ptrFindService) {\r
566                 LM_ERR("findService xmlNewNode() failed\n");\r
567                 return doc;\r
568         }\r
569         xmlDocSetRootElement(request, ptrFindService);\r
570         /* set properties */\r
571         xmlNewProp(ptrFindService, BAD_CAST "xmlns",\r
572                         BAD_CAST "urn:ietf:params:xml:ns:lost1");\r
573         xmlNewProp(ptrFindService, BAD_CAST "xmlns:p2",\r
574                         BAD_CAST "http://www.opengis.net/gml");\r
575         xmlNewProp(\r
576                         ptrFindService, BAD_CAST "serviceBoundary", BAD_CAST "reference");\r
577         xmlNewProp(ptrFindService, BAD_CAST "recursive", BAD_CAST "true");\r
578         /* location - element */\r
579         ptrLocation = xmlNewChild(ptrFindService, NULL, BAD_CAST "location", NULL);\r
580         xmlNewProp(ptrLocation, BAD_CAST "id", BAD_CAST loc->identity);\r
581         xmlNewProp(ptrLocation, BAD_CAST "profile", BAD_CAST "geodetic-2d");\r
582         /* set pos */\r
583         snprintf(buf, BUFSIZE, "%s %s", loc->latitude, loc->longitude);\r
584         /* Point */\r
585         if(loc->radius == 0) {\r
586                 ptrPoint = xmlNewChild(ptrLocation, NULL, BAD_CAST "Point", NULL);\r
587                 if(!ptrPoint) {\r
588                         LM_ERR("locationRequest xmlNewChild() failed\n");\r
589                         return doc;\r
590                 }\r
591                 xmlNewProp(ptrPoint, BAD_CAST "xmlns",\r
592                                 BAD_CAST "http://www.opengis.net/gml");\r
593                 xmlNewProp(ptrPoint, BAD_CAST "srsName",\r
594                                 BAD_CAST "urn:ogc:def:crs:EPSG::4326");\r
595                 /* pos */\r
596                 xmlNewChild(ptrPoint, NULL, BAD_CAST "pos", BAD_CAST buf);\r
597         } else {\r
598                 /* circle - Point */\r
599                 ptrCircle = xmlNewChild(ptrLocation, NULL, BAD_CAST "gs:Circle", NULL);\r
600                 if(!ptrCircle) {\r
601                         LM_ERR("locationRequest xmlNewChild() failed\n");\r
602                         return doc;\r
603                 }\r
604                 xmlNewProp(ptrCircle, BAD_CAST "xmlns:gml",\r
605                                 BAD_CAST "http://www.opengis.net/gml");\r
606                 xmlNewProp(ptrCircle, BAD_CAST "xmlns:gs",\r
607                                 BAD_CAST "http://www.opengis.net/pidflo/1.0");\r
608                 xmlNewProp(ptrCircle, BAD_CAST "srsName",\r
609                                 BAD_CAST "urn:ogc:def:crs:EPSG::4326");\r
610                 /* pos */\r
611                 xmlNewChild(ptrCircle, NULL, BAD_CAST "gml:pos", BAD_CAST buf);\r
612                 /* circle - radius */\r
613                 snprintf(buf, BUFSIZE, "%d", loc->radius);\r
614                 ptrRadius = xmlNewChild(\r
615                                 ptrCircle, NULL, BAD_CAST "gs:radius", BAD_CAST buf);\r
616                 if(!ptrRadius) {\r
617                         LM_ERR("locationRequest xmlNewChild() failed\n");\r
618                         return doc;\r
619                 }\r
620                 xmlNewProp(ptrRadius, BAD_CAST "uom",\r
621                                 BAD_CAST "urn:ogc:def:uom:EPSG::9001");\r
622         }\r
623         /* service - element */\r
624         snprintf(buf, BUFSIZE, "%s", loc->urn);\r
625         xmlNewChild(ptrFindService, NULL, BAD_CAST "service", BAD_CAST buf);\r
626 \r
627         xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);\r
628         if(!xmlbuff) {\r
629                 LM_ERR("findService request xmlDocDumpFormatMemory() failed\n");\r
630                 return doc;\r
631         }\r
632 \r
633         doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));\r
634         if(doc == NULL) {\r
635                 LM_ERR("no more private memory\n");\r
636                 return doc;\r
637         }\r
638 \r
639         memset(doc, 0, buffersize + 1);\r
640         memcpy(doc, (char *)xmlbuff, buffersize);\r
641         doc[buffersize] = '\0';\r
642 \r
643         *lgth = strlen(doc);\r
644 \r
645         xmlFree(xmlbuff);\r
646         xmlFreeDoc(request);\r
647 \r
648         return doc;\r
649 }