dialog: free old outbound buffer inside SREV_NET_DATA_OUT callback
[kamailio] / src / modules / dialog / dlg_cseq.c
1 /*
2  * Copyright (C) 2014 Daniel-Constantin Mierla (asipto.com)
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23
24 /*!
25  * \file
26  * \brief Cseq handling
27  * \ingroup dialog
28  * Module: \ref dialog
29  */
30
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "../../core/events.h"
37 #include "../../core/ut.h"
38 #include "../../core/trim.h"
39 #include "../../core/data_lump.h"
40 #include "../../core/srapi.h"
41 #include "../../core/parser/parse_to.h"
42 #include "../../core/parser/parse_from.h"
43 #include "../../core/parser/parse_cseq.h"
44 #include "../../modules/tm/tm_load.h"
45
46 #include "dlg_handlers.h"
47 #include "dlg_var.h"
48 #include "dlg_cseq.h"
49
50 extern struct tm_binds d_tmb;
51
52 static str _dlg_cseq_diff_var_name = str_init("cseq_diff");
53
54 /**
55  *
56  */
57 static int dlg_cseq_prepare_msg(sip_msg_t *msg)
58 {
59         LM_DBG("prepare msg for cseq update operations\n");
60
61         if(msg->first_line.type==SIP_REQUEST) {
62                 if(!IS_SIP(msg)) {
63                         LM_DBG("non sip request message\n");
64                         return 1;
65                 }
66         } else if(msg->first_line.type==SIP_REPLY) {
67                 if(!IS_SIP_REPLY(msg)) {
68                         LM_DBG("non sip reply message\n");
69                         return 1;
70                 }
71         } else {
72                 LM_DBG("non sip message\n");
73                 return 1;
74         }
75
76         if((!msg->cseq && (parse_headers(msg,HDR_CSEQ_F,0)<0 || !msg->cseq))
77                 || !msg->cseq->parsed){
78                 LM_DBG("parsing cseq header failed\n");
79                 return 2;
80         }
81
82         if(msg->first_line.type==SIP_REPLY) {
83                 /* reply to local transaction -- nothing to do */
84                 if (parse_headers(msg, HDR_VIA2_F, 0)==-1
85                                 || (msg->via2==0) || (msg->via2->error!=PARSE_OK)) {
86                         if(get_cseq(msg)->method_id != METHOD_CANCEL) {
87                                 LM_DBG("no second via in this message \n");
88                                 return 3;
89                         }
90                 }
91         }
92
93         if(parse_from_header(msg)<0) {
94                 LM_ERR("cannot parse FROM header\n");
95                 return 3;
96         }
97
98         if(parse_to_header(msg)<0 || msg->to==NULL) {
99                 LM_ERR("cannot parse TO header\n");
100                 return 3;
101         }
102
103         if(get_to(msg)==NULL) {
104                 LM_ERR("cannot get TO header\n");
105                 return 3;
106         }
107
108         return 0;
109 }
110
111 /**
112  *
113  */
114 static int dlg_cseq_prepare_new_msg(sip_msg_t *msg)
115 {
116         LM_DBG("prepare new msg for cseq update operations\n");
117         if (parse_msg(msg->buf, msg->len, msg)!=0) {
118                 LM_DBG("outbuf buffer parsing failed!");
119                 return 1;
120         }
121         return dlg_cseq_prepare_msg(msg);
122 }
123
124 /**
125  *
126  */
127 int dlg_cseq_update(sip_msg_t *msg)
128 {
129         dlg_cell_t *dlg = NULL;
130         unsigned int direction;
131         unsigned int ninc = 0;
132         unsigned int vinc = 0;
133         str nval;
134         str *pval;
135         sr_cfgenv_t *cenv = NULL;
136
137         if(dlg_cseq_prepare_msg(msg)!=0) {
138                 return -1;
139         }
140         if(msg->first_line.type==SIP_REPLY) {
141                 /* nothing to do for outgoing replies */
142                 goto done;
143         }
144
145         LM_DBG("initiating cseq updates\n");
146
147         direction = DLG_DIR_NONE;
148         dlg = dlg_lookup_msg_dialog(msg, &direction);
149
150         if(dlg == NULL) {
151                 LM_DBG("no dialog for this request\n");
152                 goto done;
153         }
154
155         /* supported only for downstrem direction */
156         if(direction != DLG_DIR_DOWNSTREAM) {
157                 LM_DBG("request not going downstream (%u)\n", direction);
158                 goto done;
159         }
160
161         cenv = sr_cfgenv_get();
162         ninc = 1;
163
164         /* take the increment value from dialog */
165         if((dlg->iflags&DLG_IFLAG_CSEQ_DIFF)==DLG_IFLAG_CSEQ_DIFF) {
166                 /* get dialog variable holding cseq diff */
167                 pval = get_dlg_variable(dlg, &_dlg_cseq_diff_var_name);
168                 if(pval==NULL || pval->s==NULL || pval->len<=0) {
169                         LM_DBG("dialog marked with cseq diff but no variable set yet\n");
170                         goto done;
171                 }
172                 if(str2int(pval, &vinc)<0) {
173                         LM_ERR("invalid dlg cseq diff var value: %.*s\n",
174                                         pval->len, pval->s);
175                         goto done;
176                 }
177         }
178         vinc += ninc;
179         if(vinc==0) {
180                 LM_DBG("nothing to increment\n");
181                 goto done;
182         }
183         nval.s = int2str(vinc, &nval.len);
184         if(set_dlg_variable(dlg, &_dlg_cseq_diff_var_name, &nval) <0) {
185                 LM_ERR("failed to set the dlg cseq diff var\n");
186                 goto done;
187         }
188         str2int(&get_cseq(msg)->number, &ninc);
189         vinc += ninc;
190         nval.s = int2str(vinc, &nval.len);
191         trim(&nval);
192
193         LM_DBG("adding auth cseq header value: %.*s\n", nval.len, nval.s);
194         if(parse_headers(msg, HDR_EOH_F, 0)==-1) {
195                 LM_ERR("failed to parse all headers\n");
196         }
197         sr_hdr_add_zs(msg, cenv->uac_cseq_auth.s, &nval);
198
199 done:
200         if(dlg!=NULL) dlg_release(dlg);
201         return 0;
202 }
203
204
205 /**
206  *
207  */
208 int dlg_cseq_refresh(sip_msg_t *msg, dlg_cell_t *dlg,
209                 unsigned int direction)
210 {
211         unsigned int ninc = 0;
212         unsigned int vinc = 0;
213         str nval;
214         str *pval;
215         sr_cfgenv_t *cenv = NULL;
216
217         if(dlg_cseq_prepare_msg(msg)!=0) {
218                 goto error;
219         }
220         if(msg->first_line.type==SIP_REPLY) {
221                 /* nothing to do for outgoing replies */
222                 goto done;
223         }
224
225         LM_DBG("initiating cseq refresh\n");
226
227         /* supported only for downstrem direction */
228         if(direction != DLG_DIR_DOWNSTREAM) {
229                 LM_DBG("request not going downstream (%u)\n", direction);
230                 goto done;
231         }
232
233         /* take the increment value from dialog */
234         if(!((dlg->iflags&DLG_IFLAG_CSEQ_DIFF)==DLG_IFLAG_CSEQ_DIFF)) {
235                 LM_DBG("no cseq refresh required\n");
236                 goto done;
237         }
238
239         /* get dialog variable holding cseq diff */
240         pval = get_dlg_variable(dlg, &_dlg_cseq_diff_var_name);
241         if(pval==NULL || pval->s==NULL || pval->len<=0) {
242                 LM_DBG("dialog marked with cseq diff but no variable set yet\n");
243                 goto done;
244         }
245
246         if(str2int(pval, &vinc)<0) {
247                 LM_ERR("invalid dlg cseq diff var value: %.*s\n",
248                                         pval->len, pval->s);
249                 goto done;
250         }
251         if(vinc==0) {
252                 LM_DBG("nothing to increment\n");
253                 goto done;
254         }
255
256         str2int(&get_cseq(msg)->number, &ninc);
257         vinc += ninc;
258         nval.s = int2str(vinc, &nval.len);
259         trim(&nval);
260
261         LM_DBG("adding cseq refresh header value: %.*s\n", nval.len, nval.s);
262         if(parse_headers(msg, HDR_EOH_F, 0)==-1) {
263                 LM_ERR("failed to parse all headers\n");
264         }
265         cenv = sr_cfgenv_get();
266         sr_hdr_add_zs(msg, cenv->uac_cseq_refresh.s, &nval);
267
268 done:
269         return 0;
270
271 error:
272         return -1;
273 }
274
275 /**
276  *
277  */
278 int dlg_cseq_msg_received(sr_event_param_t *evp)
279 {
280         sip_msg_t msg;
281         str *obuf;
282         struct via_body *via;
283         str vcseq;
284
285         obuf = (str*)evp->data;
286         memset(&msg, 0, sizeof(sip_msg_t));
287         msg.buf = obuf->s;
288         msg.len = obuf->len;
289
290         if(dlg_cseq_prepare_new_msg(&msg)!=0) {
291                 goto done;
292         }
293
294         if(msg.first_line.type==SIP_REQUEST) {
295                 /* nothing to do for incoming requests */
296                 goto done;
297         }
298
299         via = (struct via_body*)msg.h_via1->parsed;
300
301         if(via->branch==NULL || via->branch->value.len<=0) {
302                 LM_DBG("no branch parameter in top via\n");
303                 goto done;
304         }
305         vcseq.s = via->branch->value.s + via->branch->value.len - 1;
306         vcseq.len = 0;
307         while(vcseq.s>via->branch->value.s) {
308                 if(*vcseq.s=='.') {
309                         if(vcseq.len<3) {
310                                 LM_DBG("no matching the starting point length\n");
311                                 goto done;
312                         }
313                         if(vcseq.s[1]!='c' || vcseq.s[2]!='s') {
314                                 LM_DBG("no matching the starting placeholder\n");
315                                 goto done;
316                         }
317                         vcseq.len++;
318                         break;
319                 }
320                 vcseq.len++;
321                 vcseq.s--;
322         }
323         LM_DBG("via cseq cookie [%.*s] val [%.*s]\n", vcseq.len, vcseq.s,
324                         vcseq.len-3, vcseq.s+3);
325         if(vcseq.len-3>get_cseq(&msg)->number.len) {
326                 /* higher length to update - wrong */
327                 LM_DBG("cseq in message (%d) shorter than in via (%d)\n",
328                                 get_cseq(&msg)->number.len, vcseq.len-3);
329                 goto done;
330         }
331         if(vcseq.len-3==get_cseq(&msg)->number.len) {
332                 /* same length - overwrite in the buffer */
333                 memcpy(get_cseq(&msg)->number.s, vcseq.s+3, vcseq.len-3);
334         } else {
335                 /* pad beginning with space */
336                 strncpy(get_cseq(&msg)->number.s, "                  ",
337                                 get_cseq(&msg)->number.len - vcseq.len + 3);
338                 memcpy(get_cseq(&msg)->number.s + get_cseq(&msg)->number.len
339                                 - vcseq.len + 3, vcseq.s+3, vcseq.len-3);
340         }
341         /* our via, will be removed anyhow - let's change cseq part of branch
342          * to a z parameter instead of shifting content to remove it */
343         vcseq.s[0] = ';';
344         vcseq.s[1] = 'z';
345         vcseq.s[2] = '=';
346
347 done:
348         free_sip_msg(&msg);
349         return 0;
350 }
351
352 /**
353  *
354  */
355 int dlg_cseq_msg_sent(sr_event_param_t *evp)
356 {
357         sip_msg_t msg;
358         str *obuf;
359         unsigned int direction;
360         dlg_cell_t *dlg = NULL;
361         str nval = STR_NULL;
362         char tbuf[BUF_SIZE];
363         int tbuf_len = 0;
364         struct via_body *via;
365         hdr_field_t *hfk = NULL;
366         sr_cfgenv_t *cenv = NULL;
367         str nbuf = STR_NULL;
368
369         obuf = (str*)evp->data;
370         memset(&msg, 0, sizeof(sip_msg_t));
371         msg.buf = obuf->s;
372         msg.len = obuf->len;
373         cenv = sr_cfgenv_get();
374
375         if(dlg_cseq_prepare_new_msg(&msg)!=0) {
376                 goto done;
377         }
378
379         if(msg.first_line.type==SIP_REPLY) {
380                 /* nothing to do for outgoing replies */
381                 goto done;
382         }
383
384         LM_DBG("traking cseq updates\n");
385         via = (struct via_body*)msg.h_via1->parsed;
386
387         if(via->branch==NULL || via->branch->value.len<=0) {
388                 LM_DBG("no branch parameter in top via\n");
389                 goto done;
390         }
391
392         direction = DLG_DIR_NONE;
393         dlg = dlg_lookup_msg_dialog(&msg, &direction);
394
395         if(dlg == NULL) {
396                 LM_DBG("no dialog for this request\n");
397                 goto done;
398         }
399
400         /* supported only for downstrem direction */
401         if(direction != DLG_DIR_DOWNSTREAM) {
402                 LM_DBG("request not going downstream (%u)\n", direction);
403                 goto done;
404         }
405
406         if(parse_headers(&msg, HDR_EOH_F, 0)==-1) {
407                 LM_ERR("failed to parse all headers\n");
408         }
409
410         /* check if transaction is marked for a new increment */
411         hfk = sr_hdr_get_z(&msg, cenv->uac_cseq_auth.s);
412         if(hfk!=NULL) {
413                 LM_DBG("new cseq inc requested\n");
414                 nval = hfk->body;
415                 trim(&nval);
416         } else {
417                 LM_DBG("new cseq inc not requested\n");
418         }
419
420         if(nval.len<=0) {
421                 hfk = sr_hdr_get_z(&msg, cenv->uac_cseq_refresh.s);
422                 if(hfk!=NULL) {
423                         LM_DBG("cseq refresh requested\n");
424                         nval = hfk->body;
425                         trim(&nval);
426                 } else {
427                         LM_DBG("cseq refresh not requested\n");
428                 }
429         }
430         if(nval.len<=0) {
431                 LM_DBG("cseq refresh requested, but no new value found\n");
432                 goto done;
433         }
434
435         if(msg.len + 3 + 2*nval.len>=BUF_SIZE) {
436                 LM_ERR("new messages is too big\n");
437                 goto done;
438         }
439         LM_DBG("updating cseq to: %.*s\n", nval.len, nval.s);
440
441         /* new cseq value */
442         dlg->iflags |= DLG_IFLAG_CSEQ_DIFF;
443
444         if(via->branch->value.s<get_cseq(&msg)->number.s) {
445                 /* Via is before CSeq */
446                 /* copy first part till after via branch */
447                 tbuf_len = via->branch->value.s + via->branch->value.len - msg.buf;
448                 memcpy(tbuf, msg.buf, tbuf_len);
449                 /* complete via branch */
450                 tbuf[tbuf_len++] = '.';
451                 tbuf[tbuf_len++] = 'c';
452                 tbuf[tbuf_len++] = 's';
453                 memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s, get_cseq(&msg)->number.len);
454                 tbuf_len += get_cseq(&msg)->number.len;
455                 /* copy till beginning of cseq number */
456                 memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len,
457                                 get_cseq(&msg)->number.s - via->branch->value.s
458                                 - via->branch->value.len);
459                 tbuf_len += get_cseq(&msg)->number.s - via->branch->value.s
460                                         - via->branch->value.len;
461                 /* add new value */
462                 memcpy(tbuf+tbuf_len, nval.s, nval.len);
463                 tbuf_len += nval.len;
464                 if(hfk && hfk->name.s > get_cseq(&msg)->number.s) {
465                         /* copy from after cseq number to the beginning of hfk */
466                         memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len,
467                                         hfk->name.s - get_cseq(&msg)->number.s
468                                         - get_cseq(&msg)->number.len);
469                         tbuf_len += hfk->name.s - get_cseq(&msg)->number.s
470                                         - get_cseq(&msg)->number.len;
471                         /* copy from after hfk to the end of sip message */
472                         memcpy(tbuf+tbuf_len,  hfk->name.s + hfk->len,
473                                         msg.buf + msg.len - hfk->name.s - hfk->len);
474                         tbuf_len += msg.buf + msg.len - hfk->name.s - hfk->len;
475                 } else {
476                         /* copy from after cseq number to the end of sip message */
477                         memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len,
478                                         msg.buf + msg.len - get_cseq(&msg)->number.s
479                                         - get_cseq(&msg)->number.len);
480                         tbuf_len += msg.buf+msg.len - get_cseq(&msg)->number.s
481                                         - get_cseq(&msg)->number.len;
482                 }
483         } else {
484                 /* CSeq is before Via */
485                 /* copy till beginning of cseq number */
486                 tbuf_len = get_cseq(&msg)->number.s - msg.buf;
487                 memcpy(tbuf, msg.buf, tbuf_len);
488                 /* add new value */
489                 memcpy(tbuf+tbuf_len, nval.s, nval.len);
490                 tbuf_len += nval.len;
491                 /* copy from after cseq number to the after via branch */
492                 memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len,
493                                 via->branch->value.s + via->branch->value.len
494                                 - get_cseq(&msg)->number.s - get_cseq(&msg)->number.len);
495                 tbuf_len += via->branch->value.s + via->branch->value.len
496                                 - get_cseq(&msg)->number.s - get_cseq(&msg)->number.len;
497                 /* complete via branch */
498                 tbuf[tbuf_len++] = '.';
499                 tbuf[tbuf_len++] = 'c';
500                 tbuf[tbuf_len++] = 's';
501                 memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s, get_cseq(&msg)->number.len);
502                 tbuf_len += get_cseq(&msg)->number.len;
503                 if(hfk && hfk->name.s > get_cseq(&msg)->number.s) {
504                         /* copy from after via to the beginning of hfk */
505                         memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len,
506                                         hfk->name.s - via->branch->value.s
507                                         - via->branch->value.len);
508                         tbuf_len += hfk->name.s - via->branch->value.s
509                                         - via->branch->value.len;
510                         /* copy from after hfk to the end of sip message */
511                         memcpy(tbuf+tbuf_len,  hfk->name.s + hfk->len,
512                                         msg.buf + msg.len - hfk->name.s - hfk->len);
513                         tbuf_len += msg.buf + msg.len - hfk->name.s - hfk->len;
514                 } else {
515                         /* copy from after via to the end of sip message */
516                         memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len,
517                                         msg.buf + msg.len - via->branch->value.s
518                                         - via->branch->value.len);
519                         tbuf_len += msg.buf+msg.len - via->branch->value.s
520                                         - via->branch->value.len;
521                 }
522         }
523         /* replace old msg content */
524         nbuf.s = pkg_malloc((tbuf_len+1)*sizeof(char));
525         if(nbuf.s==NULL) {
526                 LM_ERR("not enough memory for new message\n");
527                 goto done;
528         }
529         pkg_free(obuf->s);
530         obuf->s = nbuf.s;
531         memcpy(obuf->s, tbuf, tbuf_len);
532         obuf->s[tbuf_len] = 0;
533         obuf->len = tbuf_len;
534
535 done:
536         if(dlg!=NULL) dlg_release(dlg);
537         free_sip_msg(&msg);
538         return 0;
539 }
540
541 /**
542  *
543  */
544 int dlg_register_cseq_callbacks(void)
545 {
546         sr_event_register_cb(SREV_NET_DATA_IN, dlg_cseq_msg_received);
547         sr_event_register_cb(SREV_NET_DATA_OUT, dlg_cseq_msg_sent);
548         return 0;
549 }