pua: convert to PKG/SHM memory logging helper functions
[kamailio] / src / modules / pua / send_subscribe.c
1 /*
2  * pua module - presence user agent 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
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <libxml/parser.h>
29
30 #include "../../core/mem/mem.h"
31 #include "../../core/dprint.h"
32 #include "../../core/ut.h"
33 #include "../../modules/tm/tm_load.h"
34 #include "../../modules/tm/dlg.h"
35 #include "../../core/parser/msg_parser.h"
36 #include "../../core/parser/contact/parse_contact.h"
37 #include "../../core/parser/parse_from.h"
38 #include "../../core/parser/parse_expires.h"
39 #include "../presence/hash.h"
40 #include "../../core/hashes.h"
41 #include "hash.h"
42 #include "pua.h"
43 #include "send_subscribe.h"
44 #include "pua_callback.h"
45 #include "event_list.h"
46 #include "pua_db.h"
47 #include "../presence/subscribe.h"
48
49 extern db_locking_t db_table_lock;
50
51 void print_subs(subs_info_t* subs)
52 {
53         LM_DBG("pres_uri= %.*s - len: %d\n",
54                         subs->pres_uri->len,  subs->pres_uri->s, subs->pres_uri->len );
55         LM_DBG("watcher_uri= %.*s - len: %d\n",
56                         subs->watcher_uri->len,  subs->watcher_uri->s,
57                         subs->watcher_uri->len);
58
59 }
60
61 str* subs_build_hdr(str* contact, int expires, int event, str* extra_headers)
62 {
63         str* str_hdr= NULL;
64         static char buf[3000];
65         char* subs_expires= NULL;
66         int len= 1;
67         pua_event_t* ev;
68
69         str_hdr= (str*)pkg_malloc(sizeof(str));
70         if(str_hdr== NULL)
71         {
72                 PKG_MEM_ERROR;
73                 return NULL;
74         }
75         memset(str_hdr, 0, sizeof(str));
76         str_hdr->s= buf;
77
78         ev= get_event(event);
79         if(ev== NULL)
80         {
81                 LM_ERR("getting event from list\n");
82                 goto error;
83         }
84
85         memcpy(str_hdr->s ,"Max-Forwards: ", 14);
86         str_hdr->len = 14;
87         str_hdr->len+= sprintf(str_hdr->s+ str_hdr->len,"%d", MAX_FORWARD);
88         memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
89         str_hdr->len += CRLF_LEN;
90
91         memcpy(str_hdr->s+ str_hdr->len ,"Event: ", 7);
92         str_hdr->len+= 7;
93         memcpy(str_hdr->s+ str_hdr->len, ev->name.s, ev->name.len);
94         str_hdr->len+= ev->name.len;
95         memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
96         str_hdr->len += CRLF_LEN;
97
98         memcpy(str_hdr->s+ str_hdr->len ,"Contact: <", 10);
99         str_hdr->len += 10;
100         memcpy(str_hdr->s +str_hdr->len, contact->s,
101                         contact->len);
102         str_hdr->len+= contact->len;
103         memcpy(str_hdr->s+ str_hdr->len, ">", 1);
104         str_hdr->len+= 1;
105         memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
106         str_hdr->len += CRLF_LEN;
107
108         memcpy(str_hdr->s+ str_hdr->len ,"Expires: ", 9);
109         str_hdr->len += 9;
110
111         if( expires<= min_expires)
112                 subs_expires= int2str(min_expires, &len);
113         else
114                 subs_expires= int2str(expires+ 10, &len);
115
116         if(subs_expires == NULL || len == 0)
117         {
118                 LM_ERR("while converting int to str\n");
119                 pkg_free(str_hdr);
120                 return NULL;
121         }
122         memcpy(str_hdr->s+str_hdr->len, subs_expires, len);
123         str_hdr->len += len;
124         memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
125         str_hdr->len += CRLF_LEN;
126
127         if(extra_headers && extra_headers->len)
128         {
129                 memcpy(str_hdr->s+str_hdr->len, extra_headers->s, extra_headers->len);
130                 str_hdr->len += extra_headers->len;
131         }
132
133         str_hdr->s[str_hdr->len]= '\0';
134
135         return str_hdr;
136
137 error:
138         if(str_hdr)
139                 pkg_free(str_hdr);
140         return NULL;
141 }
142
143 dlg_t* pua_build_dlg_t(ua_pres_t* presentity)
144 {
145         dlg_t* td =NULL;
146         int size;
147
148         size= sizeof(dlg_t)+ presentity->call_id.len+ presentity->to_tag.len+
149                 presentity->from_tag.len+ presentity->watcher_uri->len+
150                 presentity->pres_uri->len+ presentity->remote_contact.len;
151
152         td = (dlg_t*)pkg_malloc(size);
153         if(td == NULL)
154         {
155                 PKG_MEM_ERROR;
156                 return NULL;
157         }
158         memset(td, 0, size);
159         size= sizeof(dlg_t);
160
161         td->id.call_id.s = (char*)td+ size;
162         memcpy(td->id.call_id.s, presentity->call_id.s, presentity->call_id.len);
163         td->id.call_id.len= presentity->call_id.len;
164         size+= presentity->call_id.len;
165
166         td->id.rem_tag.s = (char*)td+ size;
167         memcpy(td->id.rem_tag.s, presentity->to_tag.s, presentity->to_tag.len);
168         td->id.rem_tag.len = presentity->to_tag.len;
169         size+= presentity->to_tag.len;
170
171         td->id.loc_tag.s = (char*)td+ size;
172         memcpy(td->id.loc_tag.s, presentity->from_tag.s, presentity->from_tag.len);
173         td->id.loc_tag.len =presentity->from_tag.len;
174         size+= presentity->from_tag.len;
175
176         td->loc_uri.s = (char*)td+ size;
177         memcpy(td->loc_uri.s, presentity->watcher_uri->s,
178                         presentity->watcher_uri->len) ;
179         td->loc_uri.len = presentity->watcher_uri->len;
180         size+= td->loc_uri.len;
181
182         td->rem_uri.s = (char*)td+ size;
183         memcpy(td->rem_uri.s, presentity->pres_uri->s, presentity->pres_uri->len) ;
184         td->rem_uri.len = presentity->pres_uri->len;
185         size+= td->rem_uri.len;
186
187         td->rem_target.s = (char*)td+ size;
188         memcpy(td->rem_target.s, presentity->remote_contact.s,
189                         presentity->remote_contact.len) ;
190         td->rem_target.len = presentity->remote_contact.len;
191         size+= td->rem_target.len;
192
193         if(presentity->record_route.s && presentity->record_route.len)
194         {
195                 if(parse_rr_body(presentity->record_route.s, presentity->record_route.len,
196                                 &td->route_set)< 0)
197                 {
198                         LM_ERR("ERROR in function parse_rr_body\n");
199                         pkg_free(td);
200                         return NULL;
201                 }
202         }
203
204         td->loc_seq.value = presentity->cseq;
205         td->loc_seq.is_set = 1;
206         td->state= DLG_CONFIRMED ;
207
208         LM_DBG("size = %d\n", size);
209
210         return td;
211 }
212
213 /**
214  * free the field in dlg_t as filled/allocated by this module
215  */
216 static int pua_free_tm_dlg(dlg_t *td)
217 {
218         if(td)
219         {
220                 if(td->route_set)
221                         free_rr(&td->route_set);
222                 pkg_free(td);
223         }
224         return 0;
225 }
226
227 static void find_and_delete_dialog(ua_pres_t *dialog, int hash_code)
228 {
229         ua_pres_t *presentity;
230
231         if (dbmode == PUA_DB_ONLY)
232         {
233                 delete_dialog_puadb(dialog);
234         }
235         else
236         {
237                 lock_get(&HashT->p_records[hash_code].lock);
238                 presentity= get_dialog(dialog, hash_code);
239                 if (presentity == NULL)
240                 {
241                         presentity = get_temporary_dialog(dialog, hash_code);
242                         if(presentity== NULL)
243                         {
244                                 LM_ERR("no record found\n");
245                                 lock_release(&HashT->p_records[hash_code].lock);
246                                 return;
247                         }
248                 }
249
250                 delete_htable(presentity, hash_code);
251                 lock_release(&HashT->p_records[hash_code].lock);
252         }
253 }
254
255 static void find_and_update_dialog(ua_pres_t *dialog, int hash_code, int lexpire, str *contact)
256 {
257         ua_pres_t *presentity;
258
259         if (dbmode == PUA_DB_ONLY)
260         {
261                 update_dialog_puadb(dialog, lexpire, contact);
262         }
263         else
264         {
265                 lock_get(&HashT->p_records[hash_code].lock);
266                 presentity= get_dialog(dialog, hash_code);
267                 if (presentity == NULL)
268                 {
269                         LM_ERR("no record found\n");
270                         lock_release(&HashT->p_records[hash_code].lock);
271                         return;
272                 }
273
274                 update_htable(presentity, dialog->desired_expires, lexpire, NULL, hash_code, contact);
275                 lock_release(&HashT->p_records[hash_code].lock);
276         }
277 }
278
279 void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps)
280 {
281         struct sip_msg* msg= NULL;
282         int lexpire= 0;
283         unsigned int cseq;
284         ua_pres_t* presentity= NULL, *hentity= NULL;
285         struct to_body *pto = NULL, TO = {0}, *pfrom = NULL;
286         int size= 0;
287         unsigned int hash_code;
288         int flag ;
289         str record_route= {0, 0};
290         int rt;
291         str contact;
292         int initial_request = 0;
293         int end_transaction = 1;
294
295         if( ps->param== NULL || *ps->param== NULL )
296         {
297                 LM_ERR("null callback parameter\n");
298                 return;
299         }
300
301         if (dbmode == PUA_DB_ONLY && pua_dbf.start_transaction)
302         {
303                 if (pua_dbf.start_transaction(pua_db, db_table_lock) < 0)
304                 {
305                         LM_ERR("in start_transaction\n");
306                         goto error;
307                 }
308         }
309
310         LM_DBG("completed with status %d\n",ps->code) ;
311         hentity= (ua_pres_t*)(*ps->param);
312         hash_code= core_hash(hentity->pres_uri,hentity->watcher_uri,
313                                 HASH_SIZE);
314         flag= hentity->flag;
315         if(hentity->flag & XMPP_INITIAL_SUBS)
316                 hentity->flag= XMPP_SUBSCRIBE;
317
318         /* get dialog information from reply message: callid, to_tag, from_tag */
319         msg= ps->rpl;
320         if(msg == NULL)
321         {
322                 LM_ERR("no reply message found\n ");
323                 goto error;
324         }
325
326         if(msg== FAKED_REPLY)
327         {
328                 struct hdr_field *callid = NULL, *from = NULL;
329                 struct to_body FROM = {0};
330
331                 callid = (struct hdr_field *) pkg_malloc(sizeof(struct hdr_field));
332                 if (callid == NULL)
333                 {
334                         PKG_MEM_ERROR;
335                         goto faked_error;
336                 }
337                 memset(callid, 0, sizeof(struct hdr_field));
338                 get_hdr_field(t->callid.s, t->callid.s + t->callid.len, callid);
339                 hentity->call_id = callid->body;
340
341                 from = (struct hdr_field *) pkg_malloc(sizeof(struct hdr_field));
342                 if (from == NULL)
343                 {
344                         PKG_MEM_ERROR;
345                         goto faked_error;
346                 }
347                 memset(from, 0, sizeof(struct hdr_field));
348                 get_hdr_field(t->from.s, t->from.s + t->from.len, from);
349                 parse_to(from->body.s, from->body.s + from->body.len + 1, &FROM);
350                 if(FROM.uri.len <= 0)
351                 {
352                         LM_ERR("'From' header NOT parsed\n");
353                         goto faked_error;
354                 }
355
356                 hentity->call_id = callid->body;
357                 hentity->from_tag = (&FROM)->tag_value;
358                 hentity->to_tag.s = NULL;
359                 hentity->to_tag.len = 0;
360
361                 find_and_delete_dialog(hentity, hash_code);
362 faked_error:
363                 if (callid) pkg_free(callid);
364                 free_to_params(&FROM);
365                 if (from) pkg_free(from);
366                 goto done;
367         }
368
369         if ( parse_headers(msg,HDR_EOH_F, 0)==-1 )
370         {
371                 LM_ERR("when parsing headers\n");
372                 goto error;
373         }
374
375         if(ps->rpl->expires && msg->expires->body.len > 0)
376         {
377                 if (!msg->expires->parsed && (parse_expires(msg->expires) < 0))
378                 {
379                         LM_ERR("cannot parse Expires header\n");
380                         goto error;
381                 }
382                 lexpire = ((exp_body_t*)msg->expires->parsed)->val;
383                 LM_DBG("lexpire= %d\n", lexpire);
384         }
385
386         /*if initial request */
387         if(hentity->call_id.s== NULL)
388         {
389                 initial_request = 1;
390
391                 if( msg->callid==NULL || msg->callid->body.s==NULL)
392                 {
393                         LM_ERR("cannot parse callid header\n");
394                         goto error;
395                 }
396
397                 if (!msg->from || !msg->from->body.s)
398                 {
399                         LM_ERR("cannot find 'from' header!\n");
400                         goto error;
401                 }
402                 if (msg->from->parsed == NULL)
403                 {
404                         if ( parse_from_header( msg )<0 )
405                         {
406                                 LM_ERR("cannot parse From header\n");
407                                 goto error;
408                         }
409                 }
410                 pfrom = (struct to_body*)msg->from->parsed;
411
412                 if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0)
413                 {
414                         LM_ERR("no from tag value present\n");
415                         goto error;
416                 }
417
418                 hentity->call_id=  msg->callid->body;
419                 hentity->from_tag= pfrom->tag_value;
420
421                 if(ps->code >= 300 || lexpire == 0)
422                 {
423                         hentity->to_tag.s = NULL;
424                         hentity->to_tag.len = 0;
425                         find_and_delete_dialog(hentity, hash_code);
426                         goto done;
427                 }
428
429                 if( msg->to==NULL || msg->to->body.s==NULL)
430                 {
431                         LM_ERR("cannot parse TO header\n");
432                         goto error;
433                 }
434                 if(msg->to->parsed != NULL)
435                 {
436                         pto = (struct to_body*)msg->to->parsed;
437                         LM_DBG("'To' header ALREADY PARSED: <%.*s>\n",pto->uri.len,pto->uri.s);
438                 }
439                 else
440                 {
441                         parse_to(msg->to->body.s,msg->to->body.s +
442                                 msg->to->body.len + 1, &TO);
443                         if(TO.uri.len <= 0)
444                         {
445                                 LM_ERR("'To' header NOT parsed\n");
446                                 goto error;
447                         }
448                         pto = &TO;
449                 }
450                 if( pto->tag_value.s ==NULL || pto->tag_value.len == 0)
451                 {
452                         LM_ERR("no to tag value present\n");
453                         goto error;
454                 }
455                 hentity->to_tag= pto->tag_value;
456         }
457
458         if(ps->code >= 300 )
459         {       /* if an error code and a stored dialog delete it and try to send
460                    a subscription with type= INSERT_TYPE, else return*/
461
462                 subs_info_t subs;
463
464                 hentity->to_tag.s = NULL;
465                 hentity->to_tag.len = 0;
466                 find_and_delete_dialog(hentity, hash_code);
467
468                 if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction)
469                 {
470                         if (pua_dbf.end_transaction(pua_db) < 0)
471                         {
472                                 LM_ERR("in end_transaction\n");
473                                 goto error;
474                         }
475                 }
476
477                 end_transaction = 0;
478
479                 /* Redirect if the response 3XX */
480                 memset(&subs, 0, sizeof(subs_info_t));
481                 subs.pres_uri= hentity->pres_uri;
482                 subs.watcher_uri= hentity->watcher_uri;
483                 subs.contact= &hentity->contact;
484
485                 if(hentity->remote_contact.s)
486                         subs.remote_target= &hentity->remote_contact;
487
488                 if(hentity->desired_expires== 0)
489                         subs.expires= -1;
490                 else
491                 if(hentity->desired_expires< (int)time(NULL))
492                         subs.expires= 0;
493                 else
494                         subs.expires= hentity->desired_expires- (int)time(NULL)+ 3;
495
496                 subs.flag= INSERT_TYPE;
497                 subs.source_flag= flag;
498                 subs.event= hentity->event;
499                 subs.id= hentity->id;
500                 subs.outbound_proxy= hentity->outbound_proxy;
501                 subs.extra_headers= hentity->extra_headers;
502                 subs.cb_param= hentity->cb_param;
503
504                 if(send_subscribe(&subs)< 0)
505                 {
506                         LM_ERR("when trying to send SUBSCRIBE\n");
507                         goto error;
508                 }
509                 goto done;
510         }
511
512         if(lexpire== 0 )
513         {
514                 LM_DBG("lexpire= 0 Delete from hash table");
515                 find_and_delete_dialog(hentity, hash_code);
516                 goto done;
517         }
518
519         /* extract the contact */
520         if(msg->contact== NULL || msg->contact->body.s== NULL)
521         {
522                 LM_ERR("no contact header found");
523                 goto error;
524         }
525         if( parse_contact(msg->contact) <0 )
526         {
527                 LM_ERR(" cannot parse contact header\n");
528                 goto error;
529         }
530         if(msg->contact->parsed == NULL)
531         {
532                 LM_ERR("cannot parse contact header\n");
533                 goto error;
534         }
535         contact = ((contact_body_t* )msg->contact->parsed)->contacts->uri;
536
537         if( msg->cseq==NULL || msg->cseq->body.s==NULL)
538         {
539                 LM_ERR("cannot parse cseq header\n");
540                 goto error;
541         }
542
543         if( str2int( &(get_cseq(msg)->number), &cseq)< 0)
544         {
545                 LM_ERR("while converting str to int\n");
546                 goto error;
547         }
548
549         if(initial_request == 0)
550         {
551                 hentity->cseq = cseq;
552                 find_and_update_dialog(hentity, hash_code, lexpire, &contact);
553                 goto done;
554         }
555
556         /*process record route and add it to a string*/
557         if (msg->record_route!=NULL)
558         {
559                 rt = print_rr_body(msg->record_route, &record_route, 1, 0);
560                 if(rt != 0)
561                 {
562                         LM_ERR("parsing record route [%d]\n", rt);
563                         record_route.s=NULL;
564                         record_route.len=0;
565                 }
566         }
567
568         size= sizeof(ua_pres_t)+ 2*sizeof(str)+( pto->uri.len+
569                 pfrom->uri.len+ pto->tag_value.len+ pfrom->tag_value.len
570                 +msg->callid->body.len+ record_route.len+ hentity->contact.len+
571                 hentity->id.len )*sizeof(char);
572
573         if(hentity->extra_headers)
574                 size+= sizeof(str)+ hentity->extra_headers->len*sizeof(char);
575
576         presentity= (ua_pres_t*)shm_malloc(size);
577         if(presentity== NULL)
578         {
579                 SHM_MEM_ERROR;
580                 goto error;
581         }
582
583         memset(presentity, 0, size);
584         size= sizeof(ua_pres_t);
585
586         presentity->pres_uri= (str*)( (char*)presentity+ size);
587         size+= sizeof(str);
588         presentity->pres_uri->s= (char*)presentity+ size;
589         memcpy(presentity->pres_uri->s, pto->uri.s, pto->uri.len);
590         presentity->pres_uri->len= pto->uri.len;
591         size+= pto->uri.len;
592
593         presentity->watcher_uri= (str*)( (char*)presentity+ size);
594         size+= sizeof(str);
595         presentity->watcher_uri->s= (char*)presentity+ size;
596         memcpy(presentity->watcher_uri->s, pfrom->uri.s, pfrom->uri.len);
597         presentity->watcher_uri->len= pfrom->uri.len;
598         size+= pfrom->uri.len;
599
600         presentity->call_id.s= (char*)presentity + size;
601         memcpy(presentity->call_id.s,msg->callid->body.s,
602                 msg->callid->body.len);
603         presentity->call_id.len= msg->callid->body.len;
604         size+= presentity->call_id.len;
605
606         presentity->to_tag.s= (char*)presentity + size;
607         memcpy(presentity->to_tag.s,pto->tag_value.s,
608                         pto->tag_value.len);
609         presentity->to_tag.len= pto->tag_value.len;
610         size+= pto->tag_value.len;
611
612         presentity->from_tag.s= (char*)presentity + size;
613         memcpy(presentity->from_tag.s,pfrom->tag_value.s,
614                         pfrom->tag_value.len);
615         presentity->from_tag.len= pfrom->tag_value.len;
616         size+= pfrom->tag_value.len;
617
618         if(record_route.len && record_route.s)
619         {
620                 presentity->record_route.s= (char*)presentity + size;
621                 memcpy(presentity->record_route.s, record_route.s, record_route.len);
622                 presentity->record_route.len= record_route.len;
623                 size+= record_route.len;
624                 pkg_free(record_route.s);
625                 record_route.s = NULL;
626         }
627
628         presentity->contact.s= (char*)presentity + size;
629         memcpy(presentity->contact.s, hentity->contact.s, hentity->contact.len);
630         presentity->contact.len= hentity->contact.len;
631         size+= hentity->contact.len;
632
633         if(hentity->id.s)
634         {
635                 presentity->id.s=(char*)presentity+ size;
636                 memcpy(presentity->id.s, hentity->id.s,
637                         hentity->id.len);
638                 presentity->id.len= hentity->id.len;
639                 size+= presentity->id.len;
640         }
641
642         if(hentity->extra_headers)
643         {
644                 presentity->extra_headers= (str*)((char*)presentity+ size);
645                 size+= sizeof(str);
646                 presentity->extra_headers->s=(char*)presentity+ size;
647                 memcpy(presentity->extra_headers->s, hentity->extra_headers->s,
648                         hentity->extra_headers->len);
649                 presentity->extra_headers->len= hentity->extra_headers->len;
650                 size+= hentity->extra_headers->len;
651         }
652
653         /* write the remote contact filed */
654         presentity->remote_contact.s= (char*)shm_malloc(contact.len* sizeof(char));
655         if(presentity->remote_contact.s==NULL)
656         {
657                 ERR_MEM(SHARE_MEM);
658         }
659         memcpy(presentity->remote_contact.s, contact.s, contact.len);
660         presentity->remote_contact.len= contact.len;
661
662         presentity->event|= hentity->event;
663         presentity->flag= hentity->flag;
664         presentity->etag.s= NULL;
665         presentity->cseq= cseq;
666         presentity->desired_expires= hentity->desired_expires;
667         presentity->expires= lexpire+ (int)time(NULL);
668         if(BLA_SUBSCRIBE & presentity->flag)
669         {
670                 LM_DBG("BLA_SUBSCRIBE FLAG inserted\n");
671         }
672         LM_DBG("record for subscribe from %.*s to %.*s inserted in database\n",
673                         presentity->watcher_uri->len, presentity->watcher_uri->s,
674                         presentity->pres_uri->len, presentity->pres_uri->s);
675
676         if (dbmode==PUA_DB_ONLY)
677         {
678                 if (pua_dbf.end_transaction)
679                 {
680                         if (pua_dbf.end_transaction(pua_db) < 0)
681                         {
682                                 LM_ERR("in end_transaction\n");
683                                 goto error;
684                         }
685                 }
686
687                 if (pua_dbf.start_transaction)
688                 {
689                         if (pua_dbf.start_transaction(pua_db, db_table_lock) < 0)
690                         {
691                                 LM_ERR("in start_transaction\n");
692                                 goto error;
693                         }
694                 }
695
696                 if (convert_temporary_dialog_puadb(presentity) < 0)
697                 {
698                         LM_ERR("Could not convert temporary dialog into a dialog\n");
699                         goto error;
700                 }
701         }
702         else
703         {
704                 if (convert_temporary_dialog(presentity) < 0)
705                 {
706                         LM_ERR("Could not convert temporary dialog into a dialog\n");
707                         goto error;
708                 }
709         }
710
711 done:
712         if(hentity->ua_flag == REQ_OTHER)
713         {
714                 hentity->flag= flag;
715                 run_pua_callbacks( hentity, msg);
716         }
717
718         if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction && end_transaction)
719         {
720                 if (pua_dbf.end_transaction(pua_db) < 0)
721                 {
722                         LM_ERR("in end_transaction\n");
723                         goto error;
724                 }
725         }
726
727         goto end;
728
729 error:
730         if (presentity)
731         {
732                 if (presentity->remote_contact.s) shm_free(presentity->remote_contact.s);
733                 shm_free(presentity);
734         }
735
736         if(record_route.s)
737                 pkg_free(record_route.s);
738
739         if (dbmode == PUA_DB_ONLY && pua_dbf.abort_transaction)
740         {
741                 if (pua_dbf.abort_transaction(pua_db) < 0)
742                         LM_ERR("in abort_transaction\n");
743         }
744
745 end:
746
747         if(hentity)
748         {
749                 shm_free(hentity);
750                 hentity= NULL;
751         }
752
753         free_to_params(&TO);
754         return;
755 }
756
757 ua_pres_t* subscribe_cbparam(subs_info_t* subs, int ua_flag)
758 {
759         ua_pres_t* hentity= NULL;
760         int size;
761
762         size= sizeof(ua_pres_t)+ 2*sizeof(str)+(subs->pres_uri->len+
763                 subs->watcher_uri->len+ subs->contact->len+ subs->id.len+ 1)*
764                 sizeof(char);
765
766         if(subs->outbound_proxy && subs->outbound_proxy->len && subs->outbound_proxy->s )
767                 size+= sizeof(str)+ subs->outbound_proxy->len* sizeof(char);
768
769         if(subs->extra_headers && subs->extra_headers->s)
770                 size+= sizeof(str)+ subs->extra_headers->len* sizeof(char);
771
772         hentity= (ua_pres_t*)shm_malloc(size);
773         if(hentity== NULL)
774         {
775                 SHM_MEM_ERROR;
776                 return NULL;
777         }
778         memset(hentity, 0, size);
779
780         size= sizeof(ua_pres_t);
781
782         hentity->pres_uri = (str*)((char*)hentity + size);
783         size+= sizeof(str);
784
785         hentity->pres_uri->s = (char*)hentity+ size;
786         memcpy(hentity->pres_uri->s, subs->pres_uri->s ,
787                 subs->pres_uri->len ) ;
788         hentity->pres_uri->len= subs->pres_uri->len;
789         size+= subs->pres_uri->len;
790
791         hentity->watcher_uri = (str*)((char*)hentity + size);
792         size+= sizeof(str);
793
794         hentity->watcher_uri->s = (char*)hentity+ size;
795         memcpy(hentity->watcher_uri->s, subs->watcher_uri->s ,
796                 subs->watcher_uri->len ) ;
797         hentity->watcher_uri->len= subs->watcher_uri->len;
798         size+= subs->watcher_uri->len;
799
800         hentity->contact.s = (char*)hentity+ size;
801         memcpy(hentity->contact.s, subs->contact->s ,
802                 subs->contact->len );
803         hentity->contact.len= subs->contact->len;
804         size+= subs->contact->len;
805
806         if(subs->outbound_proxy && subs->outbound_proxy->s)
807         {
808                 hentity->outbound_proxy= (str*)((char*)hentity+ size);
809                 size+= sizeof(str);
810                 hentity->outbound_proxy->s= (char*)hentity+ size;
811                 memcpy(hentity->outbound_proxy->s, subs->outbound_proxy->s, subs->outbound_proxy->len);
812                 hentity->outbound_proxy->len= subs->outbound_proxy->len;
813                 size+= subs->outbound_proxy->len;
814         }
815         if(subs->expires< 0)
816                 hentity->desired_expires= 0;
817         else
818                 hentity->desired_expires=subs->expires+ (int)time(NULL);
819
820         if(subs->id.s)
821         {
822                 CONT_COPY(hentity, hentity->id, subs->id);
823         }
824         if(subs->extra_headers && subs->extra_headers->s)
825         {
826                 hentity->extra_headers= (str*)((char*)hentity+ size);
827                 size+= sizeof(str);
828                 hentity->extra_headers->s= (char*)hentity+ size;
829                 memcpy(hentity->extra_headers->s, subs->extra_headers->s,
830                                 subs->extra_headers->len);
831                 hentity->extra_headers->len= subs->extra_headers->len;
832                 size+= subs->extra_headers->len;
833         }
834         hentity->flag= subs->source_flag;
835         hentity->event= subs->event;
836         hentity->ua_flag= ua_flag;
837         hentity->cb_param= subs->cb_param;
838         return hentity;
839
840 }
841
842 ua_pres_t* subs_cbparam_indlg(ua_pres_t* subs, int expires, int ua_flag)
843 {
844         ua_pres_t* hentity= NULL;
845         int size;
846
847         size= sizeof(ua_pres_t)+ 2*sizeof(str)+subs->pres_uri->len+
848                 subs->watcher_uri->len+ subs->contact.len+ subs->id.len+
849                 subs->to_tag.len+ subs->call_id.len+ subs->from_tag.len+ 1;
850
851         if(subs->outbound_proxy && subs->outbound_proxy->len && subs->outbound_proxy->s )
852                 size+= sizeof(str)+ subs->outbound_proxy->len;
853
854         if(subs->extra_headers && subs->extra_headers->s)
855                 size+= sizeof(str)+ subs->extra_headers->len;
856
857         if(subs->remote_contact.s)
858                 size+= subs->remote_contact.len;
859
860         hentity= (ua_pres_t*)shm_malloc(size);
861         if(hentity== NULL)
862         {
863                 SHM_MEM_ERROR;
864                 return NULL;
865         }
866         memset(hentity, 0, size);
867
868         size= sizeof(ua_pres_t);
869
870         hentity->pres_uri = (str*)((char*)hentity + size);
871         size+= sizeof(str);
872
873         hentity->pres_uri->s = (char*)hentity+ size;
874         memcpy(hentity->pres_uri->s, subs->pres_uri->s ,
875                 subs->pres_uri->len ) ;
876         hentity->pres_uri->len= subs->pres_uri->len;
877         size+= subs->pres_uri->len;
878
879         hentity->watcher_uri = (str*)((char*)hentity + size);
880         size+= sizeof(str);
881
882         hentity->watcher_uri->s = (char*)hentity+ size;
883         memcpy(hentity->watcher_uri->s, subs->watcher_uri->s ,
884                 subs->watcher_uri->len ) ;
885         hentity->watcher_uri->len= subs->watcher_uri->len;
886         size+= subs->watcher_uri->len;
887
888         CONT_COPY(hentity, hentity->contact, subs->contact);
889
890         if(subs->outbound_proxy && subs->outbound_proxy->len && subs->outbound_proxy->s)
891         {
892                 hentity->outbound_proxy= (str*)((char*)hentity+ size);
893                 size+= sizeof(str);
894                 hentity->outbound_proxy->s= (char*)hentity+ size;
895                 memcpy(hentity->outbound_proxy->s, subs->outbound_proxy->s, subs->outbound_proxy->len);
896                 hentity->outbound_proxy->len= subs->outbound_proxy->len;
897                 size+= subs->outbound_proxy->len;
898         }
899
900         if(subs->id.s)
901         {
902                 CONT_COPY(hentity, hentity->id, subs->id);
903         }
904
905         if(subs->remote_contact.s)
906         {
907                 CONT_COPY(hentity, hentity->remote_contact, subs->remote_contact);
908         }
909
910         if(subs->extra_headers && subs->extra_headers->s)
911         {
912                 hentity->extra_headers= (str*)((char*)hentity+ size);
913                 size+= sizeof(str);
914                 hentity->extra_headers->s= (char*)hentity+ size;
915                 memcpy(hentity->extra_headers->s, subs->extra_headers->s,
916                                 subs->extra_headers->len);
917                 hentity->extra_headers->len= subs->extra_headers->len;
918                 size+= subs->extra_headers->len;
919         }
920         /* copy dialog information */
921
922         CONT_COPY(hentity, hentity->to_tag, subs->to_tag);
923         CONT_COPY(hentity, hentity->from_tag, subs->from_tag);
924         CONT_COPY(hentity, hentity->call_id, subs->call_id);
925
926         if(expires< 0)
927                 hentity->desired_expires= 0;
928         else
929                 hentity->desired_expires=expires+ (int)time(NULL);
930
931         hentity->flag= subs->flag;
932         hentity->event= subs->event;
933         hentity->ua_flag= ua_flag;
934         hentity->cb_param= subs->cb_param;
935
936         return hentity;
937
938 }
939
940
941 /**
942  *
943  */
944 int send_subscribe(subs_info_t* subs)
945 {
946         ua_pres_t* presentity= NULL;
947         str met= {"SUBSCRIBE", 9};
948         str* str_hdr= NULL;
949         int ret= -1;
950         unsigned int hash_code=0;
951         ua_pres_t* hentity= NULL;
952         int expires;
953         int flag;
954         int result;
955         uac_req_t uac_r;
956         db1_res_t *res=NULL;
957         ua_pres_t dbpres;
958         str pres_uri={0,0}, watcher_uri={0,0}, extra_headers={0,0};
959         dlg_t* td= NULL;
960
961
962         memset(&dbpres, 0, sizeof(dbpres));
963         dbpres.pres_uri = &pres_uri;
964         dbpres.watcher_uri = &watcher_uri;
965         dbpres.extra_headers = &extra_headers;
966
967         print_subs(subs);
968
969         flag= subs->source_flag;
970         if(subs->source_flag & XMPP_INITIAL_SUBS)
971                 subs->source_flag= XMPP_SUBSCRIBE;
972
973         if(subs->expires< 0)
974                 expires= 3600;
975         else
976                 expires= subs->expires;
977
978         str_hdr= subs_build_hdr(subs->contact, expires, subs->event,
979                         subs->extra_headers);
980         if(str_hdr== NULL || str_hdr->s== NULL)
981         {
982                 LM_ERR("while building extra headers\n");
983                 if(str_hdr) pkg_free(str_hdr);
984                 return -1;
985         }
986
987         if (dbmode == PUA_DB_ONLY && pua_dbf.start_transaction)
988         {
989                 if (pua_dbf.start_transaction(pua_db, db_table_lock) < 0)
990                 {
991                         LM_ERR("in start_transaction\n");
992                         goto error;
993                 }
994         }
995
996         /* generation of hash and getting lock moved from here to further down */
997
998         if (dbmode==PUA_DB_ONLY)
999         {
1000                 presentity = get_dialog_puadb(subs->id, subs->pres_uri, &dbpres, &res);
1001         }
1002         else
1003         {
1004                 ua_pres_t pres;
1005
1006                 memset(&pres, 0, sizeof(ua_pres_t));
1007                 pres.pres_uri = subs->pres_uri;
1008                 pres.watcher_uri = subs->watcher_uri;
1009                 pres.flag = subs->source_flag;
1010                 pres.id = subs->id;
1011                 pres.event = subs->event;
1012                 if (subs->remote_target)
1013                         pres.remote_contact = *subs->remote_target;
1014
1015                 hash_code=core_hash(subs->pres_uri, subs->watcher_uri, HASH_SIZE);
1016                 lock_get(&HashT->p_records[hash_code].lock);
1017                 presentity= search_htable(&pres, hash_code);
1018         }
1019
1020         /* if flag == INSERT_TYPE insert no matter what the search result is */
1021         if(subs->flag & INSERT_TYPE)
1022         {
1023                 LM_DBG("A subscription request with insert type\n");
1024                 goto insert;
1025         }
1026
1027         if(presentity== NULL )
1028         {
1029                 int size;
1030 insert:
1031
1032                 if (subs->expires == 0)
1033                 {
1034                         /* Don't create a new dialog when expires == 0 */
1035                         if (dbmode != PUA_DB_ONLY)
1036                                 lock_release(&HashT->p_records[hash_code].lock);
1037                         goto done;
1038                 }
1039
1040                 if(subs->flag & UPDATE_TYPE)
1041                 {
1042                         LM_DBG("request for a subscription with update type"
1043                                         " and no record found\n");
1044                         subs->flag= INSERT_TYPE;
1045                 }
1046                 hentity= subscribe_cbparam(subs, REQ_OTHER);
1047                 if(hentity== NULL)
1048                 {
1049                         LM_ERR("while building callback"
1050                                         " param\n");
1051                         if (dbmode != PUA_DB_ONLY)
1052                                 lock_release(&HashT->p_records[hash_code].lock);
1053                         goto error;
1054                 }
1055                 hentity->flag= flag;
1056
1057                 set_uac_req(&uac_r, &met, str_hdr, 0, 0, TMCB_LOCAL_COMPLETED,
1058                                 subs_cback_func, (void*)hentity);
1059                 result= tmb.t_request_outside
1060                         (&uac_r,                                                  /* Type of the message */
1061                 subs->remote_target?subs->remote_target:subs->pres_uri,/* Request-URI*/
1062                         subs->pres_uri,                           /* To */
1063                         subs->watcher_uri,                        /* From */
1064                         subs->outbound_proxy              /* Outbound_proxy */
1065                         );
1066                 if(result< 0)
1067                 {
1068                         LM_ERR("while sending request with t_request\n");
1069                         if (uac_r.dialog != NULL)
1070                         {
1071                                 uac_r.dialog->rem_target.s = 0;
1072                                 uac_r.dialog->dst_uri.s = 0;
1073                                 tmb.free_dlg(uac_r.dialog);
1074                                 uac_r.dialog = 0;
1075                         }
1076                         shm_free(hentity);
1077                         if (dbmode != PUA_DB_ONLY)
1078                                 lock_release(&HashT->p_records[hash_code].lock);
1079
1080                         /* Although this is an error must not return -1 as the
1081                            calling function must continue processing. */
1082                         ret = 0;
1083                         goto error;
1084                 }
1085
1086                 /* Now create a temporary hash table entry.
1087                    This is needed to deal with the race-hazard when NOTIFYs
1088                    arrive before the 2xx response to the SUBSCRIBE. */
1089                 size = sizeof(ua_pres_t)+ 2 * sizeof(str) + (
1090                         subs->pres_uri->len +
1091                         subs->watcher_uri->len +
1092                         uac_r.dialog->id.loc_tag.len +
1093                         uac_r.dialog->id.call_id.len +
1094                         subs->id.len) * sizeof(char);
1095
1096                 presentity= (ua_pres_t*)shm_malloc(size);
1097                 if(presentity== NULL)
1098                 {
1099                         SHM_MEM_ERROR;
1100                         if (dbmode != PUA_DB_ONLY)
1101                                 lock_release(&HashT->p_records[hash_code].lock);
1102                         goto error;
1103                 }
1104                 memset(presentity, 0, size);
1105                 size= sizeof(ua_pres_t);
1106
1107                 presentity->pres_uri = (str *) ((char *) presentity + size);
1108                 size += sizeof(str);
1109                 presentity->pres_uri->s= (char *) presentity + size;
1110                 memcpy(presentity->pres_uri->s, subs->pres_uri->s, subs->pres_uri->len);
1111                 presentity->pres_uri->len= subs->pres_uri->len;
1112                 size+= subs->pres_uri->len;
1113
1114                 presentity->watcher_uri= (str *) ((char *) presentity + size);
1115                 size += sizeof(str);
1116                 presentity->watcher_uri->s= (char *) presentity + size;
1117                 memcpy(presentity->watcher_uri->s, subs->watcher_uri->s, subs->watcher_uri->len);
1118                 presentity->watcher_uri->len = subs->watcher_uri->len;
1119                 size += subs->watcher_uri->len;
1120
1121                 presentity->call_id.s = (char *) presentity + size;
1122                 memcpy(presentity->call_id.s, uac_r.dialog->id.call_id.s, uac_r.dialog->id.call_id.len);
1123                 presentity->call_id.len = uac_r.dialog->id.call_id.len;
1124                 size += uac_r.dialog->id.call_id.len;
1125
1126                 presentity->from_tag.s = (char *) presentity + size;
1127                 memcpy(presentity->from_tag.s, uac_r.dialog->id.loc_tag.s, uac_r.dialog->id.loc_tag.len);
1128                 presentity->from_tag.len= uac_r.dialog->id.loc_tag.len;
1129                 size += uac_r.dialog->id.loc_tag.len;
1130
1131                 presentity->id.s = (char *) presentity+ size;
1132                 memcpy(presentity->id.s, subs->id.s, subs->id.len);
1133                 presentity->id.len = subs->id.len;
1134                 size += subs->id.len;
1135
1136                 presentity->event = subs->event;
1137                 presentity->flag = subs->source_flag;
1138                 presentity->cseq = uac_r.dialog->loc_seq.value;
1139
1140                 /* Set the temporary record expiry for 2 * 64T1 seconds from now */
1141                 presentity->expires= (int)time(NULL) + 64;
1142                 presentity->desired_expires= presentity->expires;
1143
1144                 if (dbmode==PUA_DB_ONLY)
1145                 {
1146                         insert_dialog_puadb(presentity);
1147                         shm_free(presentity);
1148                 }
1149                 else
1150                 {
1151                         insert_htable(presentity, hash_code);
1152                         lock_release(&HashT->p_records[hash_code].lock);
1153                 }
1154
1155                 uac_r.dialog->rem_target.s = 0;
1156                 uac_r.dialog->dst_uri.s = 0;
1157                 tmb.free_dlg(uac_r.dialog);
1158                 uac_r.dialog = 0;
1159         }
1160         else
1161         {
1162                 if (subs->internal_update_flag == INTERNAL_UPDATE_TRUE)
1163                 {
1164                         LM_INFO("attempting to re-SUBSCRIBE on internal (rls_update_subs()) update - skipping\n");
1165                         if (dbmode != PUA_DB_ONLY)
1166                                 lock_release(&HashT->p_records[hash_code].lock);
1167                         goto done;
1168                 }
1169
1170                 if (presentity->to_tag.len == 0)
1171                 {
1172                         if (subs->expires > 0)
1173                                 LM_WARN("attempting to re-SUBSCRIBE to a temporary (non-established) dialog - skipping\n");
1174                         else
1175                         {
1176                                 LM_WARN("attempting to un-SUBSCRIBE from a temporary (non-established) dialog - skipping and deleting dialog\n");
1177                                 if (dbmode==PUA_DB_ONLY)
1178                                         delete_dialog_puadb(presentity);
1179                                 else
1180                                         delete_htable(presentity, hash_code);
1181                         }
1182
1183                         if (dbmode != PUA_DB_ONLY)
1184                                 lock_release(&HashT->p_records[hash_code].lock);
1185                         goto done;
1186                 }
1187
1188                 td= pua_build_dlg_t(presentity);
1189                 if(td== NULL)
1190                 {
1191                         LM_ERR("while building tm dlg_t structure");
1192                         if (dbmode!=PUA_DB_ONLY)
1193                                 lock_release(&HashT->p_records[hash_code].lock);
1194                         goto error;
1195                 }
1196
1197                 hentity= subs_cbparam_indlg(presentity, expires, REQ_OTHER);
1198                 if(hentity== NULL)
1199                 {
1200                         LM_ERR("while building callback param\n");
1201                         if (dbmode!=PUA_DB_ONLY)
1202                                 lock_release(&HashT->p_records[hash_code].lock);
1203                         goto error;
1204                 }
1205                 if (dbmode!=PUA_DB_ONLY)
1206                         lock_release(&HashT->p_records[hash_code].lock);
1207
1208                 LM_DBG("event parameter: %d\n", hentity->event);
1209
1210                 set_uac_req(&uac_r, &met, str_hdr, 0, td, TMCB_LOCAL_COMPLETED,
1211                                 subs_cback_func, (void*)hentity);
1212                 result= tmb.t_request_within(&uac_r);
1213                 if(result< 0)
1214                 {
1215                         shm_free(hentity);
1216                         hentity= NULL;
1217                         LM_ERR("while sending request with t_request\n");
1218                         goto error;
1219                 }
1220         }
1221
1222
1223 done:
1224         if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction)
1225         {
1226                 if (pua_dbf.end_transaction(pua_db) < 0)
1227                 {
1228                         LM_ERR("in end_transaction\n");
1229                         goto error;
1230                 }
1231         }
1232
1233         ret = 0;
1234
1235 error:
1236         pua_free_tm_dlg(td);
1237         pkg_free(str_hdr);
1238         free_results_puadb(res);
1239
1240         if (dbmode == PUA_DB_ONLY && pua_dbf.abort_transaction)
1241         {
1242                 if (pua_dbf.abort_transaction(pua_db) < 0)
1243                         LM_ERR("in abort_transaction\n");
1244         }
1245
1246         return ret;
1247 }