1 /*
2 * pua_usrloc module - usrloc pua module
3 *
4 * Copyright (C) 2006 Voice Sistem S.R.L.
5 *
6 * This file is part of Kamailio, a free SIP server.
7 *
8 * Kamailio is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version
12 *
13 * Kamailio is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <libxml/parser.h>
27 #include <time.h>
28
29 #include "../../core/parser/parse_expires.h"
30 #include "../../core/parser/msg_parser.h"
31 #include "../../core/str.h"
32 #include "../../core/str_list.h"
33 #include "../../core/name_alias.h"
34 #include "../../core/socket_info.h"
35 #include "../usrloc/usrloc.h"
36 #include "../usrloc/ul_callback.h"
37 #include "../../modules/tm/tm_load.h"
38 #include "../pua/pua.h"
39 #include "pua_dialoginfo.h"
40
41 /* global modul parameters */
42 extern int include_callid;
43 extern int include_localremote;
44 extern int include_tags;
45
46
47 /* for debug purpose only */
print_publ(publ_info_t * p)48 void print_publ(publ_info_t* p)
49 {
50 LM_DBG("publ:\n");
51 LM_DBG("uri= %.*s\n", p->pres_uri->len, p->pres_uri->s);
52 LM_DBG("id= %.*s\n", p->id.len, p->id.s);
53 LM_DBG("expires= %d\n", p->expires);
54 }
55
build_dialoginfo(char * state,str * entity,str * peer,str * callid,unsigned int initiator,str * localtag,str * remotetag,str * localtarget,str * remotetarget)56 str* build_dialoginfo(char *state, str *entity, str *peer, str *callid,
57 unsigned int initiator, str *localtag, str *remotetag,
58 str *localtarget, str *remotetarget)
59 {
60 xmlDocPtr doc = NULL;
61 xmlNodePtr root_node = NULL;
62 xmlNodePtr dialog_node = NULL;
63 xmlNodePtr state_node = NULL;
64 xmlNodePtr remote_node = NULL;
65 xmlNodePtr local_node = NULL;
66 xmlNodePtr tag_node = NULL;
67 str *body= NULL;
68 char buf[MAX_URI_SIZE+1];
69
70 if (entity->len > MAX_URI_SIZE) {
71 LM_ERR("entity URI '%.*s' too long, maximum=%d\n",entity->len,
72 entity->s, MAX_URI_SIZE);
73 return NULL;
74 }
75 memcpy(buf, entity->s, entity->len);
76 buf[entity->len]= '\0';
77
78 /* create the Publish body */
79 doc = xmlNewDoc(BAD_CAST "1.0");
80 if(doc==0)
81 return NULL;
82
83 root_node = xmlNewNode(NULL, BAD_CAST "dialog-info");
84 if(root_node==0)
85 goto error;
86
87 xmlDocSetRootElement(doc, root_node);
88
89 xmlNewProp(root_node, BAD_CAST "xmlns",
90 BAD_CAST "urn:ietf:params:xml:ns:dialog-info");
91 /* we set the version to 0 but it should be set to the correct value
92 * in the pua module */
93 xmlNewProp(root_node, BAD_CAST "version",
94 BAD_CAST "0");
95 xmlNewProp(root_node, BAD_CAST "state",
96 BAD_CAST "full" );
97 xmlNewProp(root_node, BAD_CAST "entity",
98 BAD_CAST buf);
99
100 /* RFC 3245 differs between id and call-id. For example if a call
101 * is forked and 2 early dialogs are established, we should send 2
102 * PUBLISH requests, both have the same call-id but different id.
103 * Thus, id could be for example derived from the totag.
104 *
105 * Currently the dialog module does not support multiple dialogs.
106 * Thus, it does no make sense to differ here between multiple dialog.
107 * Thus, id and call-id will be populated identically */
108
109 /* dialog tag */
110 dialog_node =xmlNewChild(root_node, NULL, BAD_CAST "dialog", NULL) ;
111 if( dialog_node ==NULL)
112 {
113 LM_ERR("while adding child\n");
114 goto error;
115 }
116
117 if (callid->len > MAX_URI_SIZE) {
118 LM_ERR("call-id '%.*s' too long, maximum=%d\n", callid->len,
119 callid->s, MAX_URI_SIZE);
120 goto error;
121 }
122 memcpy(buf, callid->s, callid->len);
123 buf[callid->len]= '\0';
124
125 xmlNewProp(dialog_node, BAD_CAST "id", BAD_CAST buf);
126 if (include_callid) {
127 xmlNewProp(dialog_node, BAD_CAST "call-id", BAD_CAST buf);
128 }
129 if (include_tags) {
130 if (localtag && localtag->s) {
131 if (localtag->len > MAX_URI_SIZE) {
132 LM_ERR("localtag '%.*s' too long, maximum=%d\n",
133 localtag->len, localtag->s, MAX_URI_SIZE);
134 goto error;
135 }
136 memcpy(buf, localtag->s, localtag->len);
137 buf[localtag->len]= '\0';
138 xmlNewProp(dialog_node, BAD_CAST "local-tag", BAD_CAST buf);
139 }
140 if (remotetag && remotetag->s) {
141 if (remotetag->len > MAX_URI_SIZE) {
142 LM_ERR("remotetag '%.*s' too long, maximum=%d\n",
143 remotetag->len, remotetag->s, MAX_URI_SIZE);
144 goto error;
145 }
146 memcpy(buf, remotetag->s, remotetag->len);
147 buf[remotetag->len]= '\0';
148 xmlNewProp(dialog_node, BAD_CAST "remote-tag", BAD_CAST buf);
149 }
150 }
151
152 if (initiator) {
153 xmlNewProp(dialog_node, BAD_CAST "direction", BAD_CAST "initiator");
154 }else {
155 xmlNewProp(dialog_node, BAD_CAST "direction", BAD_CAST "recipient");
156 }
157
158 /* state tag */
159 state_node = xmlNewChild(dialog_node, NULL, BAD_CAST "state",
160 BAD_CAST state) ;
161 if( state_node ==NULL)
162 {
163 LM_ERR("while adding child\n");
164 goto error;
165 }
166
167 if (include_localremote) {
168 /* remote tag*/
169 remote_node = xmlNewChild(dialog_node, NULL, BAD_CAST "remote", NULL) ;
170 if( remote_node ==NULL)
171 {
172 LM_ERR("while adding child\n");
173 goto error;
174 }
175
176 if (peer->len > MAX_URI_SIZE) {
177 LM_ERR("peer '%.*s' too long, maximum=%d\n", peer->len, peer->s,
178 MAX_URI_SIZE);
179 goto error;
180 }
181 memcpy(buf, peer->s, peer->len);
182 buf[peer->len]= '\0';
183
184 tag_node = xmlNewChild(remote_node, NULL, BAD_CAST "identity",
185 BAD_CAST buf) ;
186 if( tag_node ==NULL)
187 {
188 LM_ERR("while adding child\n");
189 goto error;
190 }
191 tag_node = xmlNewChild(remote_node, NULL, BAD_CAST "target", NULL);
192 if( tag_node ==NULL)
193 {
194 LM_ERR("while adding child\n");
195 goto error;
196 }
197 if (remotetarget && remotetarget->s) {
198 memcpy(buf, remotetarget->s, remotetarget->len);
199 buf[remotetarget->len]= '\0';
200 }
201 xmlNewProp(tag_node, BAD_CAST "uri", BAD_CAST buf);
202
203 /* local tag*/
204 local_node = xmlNewChild(dialog_node, NULL, BAD_CAST "local", NULL);
205 if( local_node ==NULL)
206 {
207 LM_ERR("while adding child\n");
208 goto error;
209 }
210
211 if (entity->len > MAX_URI_SIZE) {
212 LM_ERR("entity '%.*s' too long, maximum=%d\n",
213 entity->len, entity->s, MAX_URI_SIZE);
214 goto error;
215 }
216 memcpy(buf, entity->s, entity->len);
217 buf[entity->len]= '\0';
218
219 tag_node = xmlNewChild(local_node, NULL, BAD_CAST "identity",
220 BAD_CAST buf) ;
221 if( tag_node ==NULL)
222 {
223 LM_ERR("while adding child\n");
224 goto error;
225 }
226 tag_node = xmlNewChild(local_node, NULL, BAD_CAST "target", NULL);
227 if( tag_node ==NULL)
228 {
229 LM_ERR("while adding child\n");
230 goto error;
231 }
232 if (localtarget && localtarget->s) {
233 memcpy(buf, localtarget->s, localtarget->len);
234 buf[localtarget->len]= '\0';
235 }
236 xmlNewProp(tag_node, BAD_CAST "uri", BAD_CAST buf);
237 }
238
239 /* create the body */
240 body = (str*)pkg_malloc(sizeof(str));
241 if(body == NULL)
242 {
243 PKG_MEM_ERROR;
244 goto error;
245 }
246 memset(body, 0, sizeof(str));
247
248 xmlDocDumpFormatMemory(doc,(unsigned char**)(void*)&body->s,&body->len,1);
249
250 if(body->s==NULL || body->len==0) {
251 LM_ERR("failure formatting xml doc from memory or empty doc\n");
252 goto error;
253 }
254
255 LM_DBG("new_body:\n%.*s\n", body->len, body->s);
256
257 /*free the document */
258 xmlFreeDoc(doc);
259 xmlCleanupParser();
260
261 return body;
262
263 error:
264 if(body)
265 {
266 if(body->s)
267 xmlFree(body->s);
268 pkg_free(body);
269 }
270 if(doc) {
271 xmlFreeDoc(doc);
272 xmlCleanupParser();
273 }
274
275 return NULL;
276 }
277
dialog_publish(char * state,str * ruri,str * entity,str * peer,str * callid,unsigned int initiator,unsigned int lifetime,str * localtag,str * remotetag,str * localtarget,str * remotetarget,unsigned short do_pubruri_localcheck)278 void dialog_publish(char *state, str* ruri, str *entity, str *peer, str *callid,
279 unsigned int initiator, unsigned int lifetime, str *localtag,
280 str *remotetag, str *localtarget, str *remotetarget,
281 unsigned short do_pubruri_localcheck)
282 {
283 str* body= NULL;
284 str uri= {NULL, 0};
285 publ_info_t* publ= NULL;
286 int size= 0;
287 str content_type;
288 struct sip_uri ruri_uri;
289
290
291 if (parse_uri(ruri->s, ruri->len, &ruri_uri) < 0) {
292 LM_ERR("failed to parse the PUBLISH R-URI\n");
293 return;
294 }
295
296 if(do_pubruri_localcheck) {
297
298 /* send PUBLISH only if the receiver PUBLISH R-URI is local*/
299 if (!check_self(&(ruri_uri.host), 0, 0)) {
300 LM_DBG("do not send PUBLISH to external URI %.*s\n",
301 ruri->len, ruri->s);
302 return;
303 }
304
305 }
306
307 content_type.s= "application/dialog-info+xml";
308 content_type.len= 27;
309
310 body= build_dialoginfo(state, entity, peer, callid, initiator, localtag,
311 remotetag, localtarget, remotetarget);
312 if(body == NULL || body->s == NULL)
313 goto error;
314
315 LM_DBG("publish uri= %.*s\n", ruri->len, ruri->s);
316
317 size= sizeof(publ_info_t)
318 + sizeof(str) /* *pres_uri */
319 + ( ruri->len /* pres_uri->s */
320 + callid->len + 16 /* id.s */
321 + content_type.len /* content_type.s */
322 )*sizeof(char);
323
324 if(body)
325 size+= sizeof(str)+ body->len* sizeof(char);
326
327 publ= (publ_info_t*)pkg_malloc(size);
328 if(publ== NULL)
329 {
330 PKG_MEM_ERROR;
331 goto error;
332 }
333 memset(publ, 0, size);
334 size= sizeof(publ_info_t);
335
336 publ->pres_uri= (str*)((char*)publ + size);
337 size+= sizeof(str);
338 publ->pres_uri->s= (char*)publ+ size;
339 memcpy(publ->pres_uri->s, ruri->s, ruri->len);
340 publ->pres_uri->len= ruri->len;
341 size+= ruri->len;
342
343 if(body)
344 {
345 publ->body= (str*)( (char*)publ + size);
346 size+= sizeof(str);
347
348 publ->body->s= (char*)publ + size;
349 memcpy(publ->body->s, body->s, body->len);
350 publ->body->len= body->len;
351 size+= body->len;
352 }
353 publ->id.s= (char*)publ+ size;
354 memcpy(publ->id.s, "DIALOG_PUBLISH.", 15);
355 memcpy(publ->id.s+15, callid->s, callid->len);
356 publ->id.len= 15+ callid->len;
357 size+= publ->id.len;
358
359 publ->content_type.s= (char*)publ+ size;
360 memcpy(publ->content_type.s, content_type.s, content_type.len);
361 publ->content_type.len= content_type.len;
362 size+= content_type.len;
363
364 publ->expires= lifetime;
365
366 /* make UPDATE_TYPE, as if this "publish dialog" is not found
367 * by pua it will fallback to INSERT_TYPE anyway */
368 publ->flag|= UPDATE_TYPE;
369
370 publ->source_flag|= DIALOG_PUBLISH;
371 publ->event|= DIALOG_EVENT;
372 publ->extra_headers= NULL;
373 print_publ(publ);
374 if(pua_send_publish(publ)< 0)
375 {
376 LM_ERR("while sending publish\n");
377 }
378
379 error:
380
381 if(publ)
382 pkg_free(publ);
383
384 if(body)
385 {
386 if(body->s)
387 xmlFree(body->s);
388 pkg_free(body);
389 }
390
391 if(uri.s)
392 pkg_free(uri.s);
393
394 return;
395 }
396
397
398
dialog_publish_multi(char * state,struct str_list * ruris,str * entity,str * peer,str * callid,unsigned int initiator,unsigned int lifetime,str * localtag,str * remotetag,str * localtarget,str * remotetarget,unsigned short do_pubruri_localcheck)399 void dialog_publish_multi(char *state, struct str_list* ruris, str *entity,
400 str *peer, str *callid, unsigned int initiator, unsigned int lifetime,
401 str *localtag, str *remotetag,
402 str *localtarget, str *remotetarget, unsigned short
403 do_pubruri_localcheck)
404 {
405 while(ruris) {
406 LM_DBG("CALLING dialog_publish for URI %.*s\n",
407 ruris->s.len, ruris->s.s);
408 dialog_publish(state,&(ruris->s),entity,peer,callid,initiator,
409 lifetime,localtag,remotetag,localtarget,remotetarget,
410 do_pubruri_localcheck);
411 ruris=ruris->next;
412 }
413 }
414