Fix relative paths to tm header files.
[sip-router] / modules_k / acc / acc_logic.c
1 /*
2  * $Id$
3  * 
4  * Accounting module logic
5  *
6  * Copyright (C) 2001-2003 FhG Fokus
7  * Copyright (C) 2006 Voice Sistem SRL
8  *
9  * This file is part of Kamailio, a free SIP server.
10  *
11  * Kamailio is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version
15  *
16  * Kamailio is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  * History:
26  * -------
27  * 2006-09-19  forked from the acc_mod.c file during a big re-structuring
28  *             of acc module (bogdan)
29  */
30
31 /*! \file
32  * \ingroup acc
33  * \brief Acc:: Logic
34  *
35  * - Module: \ref acc
36  */
37
38 #include <stdio.h>
39 #include <string.h>
40
41 #include "../../dprint.h"
42 #include "../../parser/parse_from.h"
43 #include "../../parser/parse_content.h"
44 #include "../../modules/tm/tm_load.h"
45 #include "../rr/api.h"
46 #include "../../lib/kcore/km_ut.h"
47 #include "../../flags.h"
48 #include "acc.h"
49 #include "acc_mod.h"
50 #include "acc_logic.h"
51
52 extern struct tm_binds tmb;
53 extern struct rr_binds rrb;
54
55 struct acc_enviroment acc_env;
56
57
58 #define is_acc_flag_set(_rq,_flag)  (((_flag) != -1) && (isflagset((_rq), (_flag)) == 1))
59 #define reset_acc_flag(_rq,_flag)   (resetflag((_rq), (_flag)))
60
61 #define is_failed_acc_on(_rq)  is_acc_flag_set(_rq,failed_transaction_flag)
62
63 #define is_log_acc_on(_rq)     is_acc_flag_set(_rq,log_flag)
64 #define is_log_mc_on(_rq)      is_acc_flag_set(_rq,log_missed_flag)
65
66 #ifdef SQL_ACC
67         #define is_db_acc_on(_rq)     is_acc_flag_set(_rq,db_flag)
68         #define is_db_mc_on(_rq)      is_acc_flag_set(_rq,db_missed_flag)
69 #else
70         #define is_db_acc_on(_rq)     (0)
71         #define is_db_mc_on(_rq)      (0)
72 #endif
73
74 #ifdef RAD_ACC
75         #define is_rad_acc_on(_rq)     is_acc_flag_set(_rq,radius_flag)
76         #define is_rad_mc_on(_rq)      is_acc_flag_set(_rq,radius_missed_flag)
77 #else
78         #define is_rad_acc_on(_rq)     (0)
79         #define is_rad_mc_on(_rq)      (0)
80 #endif
81
82
83 #ifdef DIAM_ACC
84         #define is_diam_acc_on(_rq)     is_acc_flag_set(_rq,diameter_flag)
85         #define is_diam_mc_on(_rq)      is_acc_flag_set(_rq,diameter_missed_flag)
86 #else
87         #define is_diam_acc_on(_rq)     (0)
88         #define is_diam_mc_on(_rq)      (0)
89 #endif
90
91 #define is_acc_on(_rq) \
92         ( (is_log_acc_on(_rq)) || (is_db_acc_on(_rq)) \
93         || (is_rad_acc_on(_rq)) || (is_diam_acc_on(_rq)) )
94
95 #define is_mc_on(_rq) \
96         ( (is_log_mc_on(_rq)) || (is_db_mc_on(_rq)) \
97         || (is_rad_mc_on(_rq)) || (is_diam_mc_on(_rq)) )
98
99 #define skip_cancel(_rq) \
100         (((_rq)->REQ_METHOD==METHOD_CANCEL) && report_cancels==0)
101
102
103
104
105 static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps );
106
107
108 static inline struct hdr_field* get_rpl_to( struct cell *t,
109                                                                                                                 struct sip_msg *reply)
110 {
111         if (reply==FAKED_REPLY || !reply || !reply->to)
112                 return t->uas.request->to;
113         else
114                 return reply->to;
115 }
116
117
118 static inline void env_set_to(struct hdr_field *to)
119 {
120         acc_env.to = to;
121 }
122
123
124 static inline void env_set_text(char *p, int len)
125 {
126         acc_env.text.s = p;
127         acc_env.text.len = len;
128 }
129
130
131 static inline void env_set_code_status( int code, struct sip_msg *reply)
132 {
133         static char code_buf[INT2STR_MAX_LEN];
134
135         acc_env.code = code;
136         if (reply==FAKED_REPLY || reply==NULL) {
137                 /* code */
138                 acc_env.code_s.s =
139                         int2bstr((unsigned long)code, code_buf, &acc_env.code_s.len);
140                 /* reason */
141                 acc_env.reason.s = error_text(code);
142                 acc_env.reason.len = strlen(acc_env.reason.s);
143         } else {
144                 acc_env.code_s = reply->first_line.u.reply.status;
145                 acc_env.reason = reply->first_line.u.reply.reason;
146         }
147 }
148
149
150 static inline void env_set_comment(struct acc_param *accp)
151 {
152         acc_env.code = accp->code;
153         acc_env.code_s = accp->code_s;
154         acc_env.reason = accp->reason;
155 }
156
157
158 static inline int acc_preparse_req(struct sip_msg *req)
159 {
160         if ( (parse_headers(req,HDR_CALLID_F|HDR_CSEQ_F|HDR_FROM_F|HDR_TO_F,0)<0)
161         || (parse_from_header(req)<0 ) ) {
162                 LM_ERR("failed to preparse request\n");
163                 return -1;
164         }
165         return 0;
166 }
167
168
169
170 int w_acc_log_request(struct sip_msg *rq, char *comment, char *foo)
171 {
172         if (acc_preparse_req(rq)<0)
173                 return -1;
174         env_set_to( rq->to );
175         env_set_comment((struct acc_param*)comment);
176         env_set_text( ACC_REQUEST, ACC_REQUEST_LEN);
177         return acc_log_request(rq);
178 }
179
180
181 #ifdef SQL_ACC
182 int w_acc_db_request(struct sip_msg *rq, char *comment, char *table)
183 {
184         if (!table) {
185                 LM_ERR("db support not configured\n");
186                 return -1;
187         }
188         if (acc_preparse_req(rq)<0)
189                 return -1;
190         env_set_to( rq->to );
191         env_set_comment((struct acc_param*)comment);
192         env_set_text(table, strlen(table));
193         return acc_db_request(rq);
194 }
195 #endif
196
197
198 #ifdef RAD_ACC
199 int w_acc_rad_request(struct sip_msg *rq, char *comment, char *foo)
200 {
201         if (acc_preparse_req(rq)<0)
202                 return -1;
203         env_set_to( rq->to );
204         env_set_comment((struct acc_param*)comment);
205         return acc_rad_request(rq);
206 }
207 #endif
208
209
210 #ifdef DIAM_ACC
211 int w_acc_diam_request(struct sip_msg *rq, char *comment, char *foo)
212 {
213         if (acc_preparse_req(rq)<0)
214                 return -1;
215         env_set_to( rq->to );
216         env_set_comment((struct acc_param*)comment);
217         return acc_diam_request(rq);
218 }
219 #endif
220
221
222 /* prepare message and transaction context for later accounting */
223 void acc_onreq( struct cell* t, int type, struct tmcb_params *ps )
224 {
225         int tmcb_types;
226         int is_invite;
227
228         if ( ps->req && !skip_cancel(ps->req) &&
229         (is_acc_on(ps->req) || is_mc_on(ps->req)) ) {
230                 /* do some parsing in advance */
231                 if (acc_preparse_req(ps->req)<0)
232                         return;
233                 is_invite = (ps->req->REQ_METHOD==METHOD_INVITE)?1:0;
234                 /* install additional handlers */
235                 tmcb_types =
236                         /* report on completed transactions */
237                         TMCB_RESPONSE_OUT |
238                         /* account e2e acks if configured to do so */
239                         ((report_ack && is_acc_on(ps->req))?TMCB_E2EACK_IN:0) |
240                         /* get incoming replies ready for processing */
241                         TMCB_RESPONSE_IN |
242                         /* report on missed calls */
243                         ((is_invite && is_mc_on(ps->req))?TMCB_ON_FAILURE:0) ;
244                 if (tmb.register_tmcb( 0, t, tmcb_types, tmcb_func, 0, 0 )<=0) {
245                         LM_ERR("cannot register additional callbacks\n");
246                         return;
247                 }
248                 /* if required, determine request direction */
249                 if( detect_direction && !rrb.is_direction(ps->req,RR_FLOW_UPSTREAM) ) {
250                         LM_DBG("detected an UPSTREAM req -> flaging it\n");
251                         ps->req->msg_flags |= FL_REQ_UPSTREAM;
252                 }
253         }
254 }
255
256
257
258 /* is this reply of interest for accounting ? */
259 static inline int should_acc_reply(struct sip_msg *req,struct sip_msg *rpl,
260                                                                                                                                         int code)
261 {
262         /* negative transactions reported otherwise only if explicitly 
263          * demanded */
264         if ( !is_failed_acc_on(req) && code >=300 )
265                 return 0;
266         if ( !is_acc_on(req) )
267                 return 0;
268         if ( code<200 && !(early_media &&
269         parse_headers(rpl,HDR_CONTENTLENGTH_F, 0)==0 && rpl->content_length &&
270         get_content_length(rpl)>0 ) )
271                 return 0;
272
273         return 1; /* seed is through, we will account this reply */
274 }
275
276
277
278 /* parse incoming replies before cloning */
279 static inline void acc_onreply_in(struct cell *t, struct sip_msg *req,
280                                                                                         struct sip_msg *reply, int code)
281 {
282         /* don't parse replies in which we are not interested */
283         /* missed calls enabled ? */
284         if ( (reply && reply!=FAKED_REPLY) && (should_acc_reply(req,reply,code)
285         || (is_invite(t) && code>=300 && is_mc_on(req))) ) {
286                 parse_headers(reply, HDR_TO_F, 0 );
287         }
288 }
289
290
291
292 /* initiate a report if we previously enabled MC accounting for this t */
293 static inline void on_missed(struct cell *t, struct sip_msg *req,
294                                                                                         struct sip_msg *reply, int code)
295 {
296         str new_uri_bk;
297         int flags_to_reset = 0;
298
299         /* set as new_uri the last branch */
300         new_uri_bk = req->new_uri;
301         req->new_uri = t->uac[t->nr_of_outgoings-1].uri;
302         req->parsed_uri_ok = 0;
303         /* set env variables */
304         env_set_to( get_rpl_to(t,reply) );
305         env_set_code_status( code, reply);
306
307         /* we report on missed calls when the first
308          * forwarding attempt fails; we do not wish to
309          * report on every attempt; so we clear the flags; 
310          */
311
312         if (is_log_mc_on(req)) {
313                 env_set_text( ACC_MISSED, ACC_MISSED_LEN);
314                 acc_log_request( req );
315                 flags_to_reset |= log_missed_flag;
316         }
317 #ifdef SQL_ACC
318         if (is_db_mc_on(req)) {
319                 env_set_text(db_table_mc.s, db_table_mc.len);
320                 acc_db_request( req );
321                 flags_to_reset |= db_missed_flag;
322         }
323 #endif
324 #ifdef RAD_ACC
325         if (is_rad_mc_on(req)) {
326                 acc_rad_request( req );
327                 flags_to_reset |= radius_missed_flag;
328         }
329 #endif
330 /* DIAMETER */
331 #ifdef DIAM_ACC
332         if (is_diam_mc_on(req)) {
333                 acc_diam_request( req );
334                 flags_to_reset |= diameter_missed_flag;
335         }
336 #endif
337
338         /* Reset the accounting missed_flags
339          * These can't be reset in the blocks above, because
340          * it would skip accounting if the flags are identical
341          */
342         reset_acc_flag( req, flags_to_reset );
343
344         req->new_uri = new_uri_bk;
345         req->parsed_uri_ok = 0;
346 }
347
348
349
350 /* initiate a report if we previously enabled accounting for this t */
351 static inline void acc_onreply( struct cell* t, struct sip_msg *req,
352                                                                                         struct sip_msg *reply, int code)
353 {
354         str new_uri_bk;
355
356         /* acc_onreply is bound to TMCB_REPLY which may be called
357            from _reply, like when FR hits; we should not miss this
358            event for missed calls either */
359         if (is_invite(t) && code>=300 && is_mc_on(req) )
360                 on_missed(t, req, reply, code);
361
362         if (!should_acc_reply(req, reply, code))
363                 return;
364
365         /* for reply processing, set as new_uri the winning branch */
366         if (t->relayed_reply_branch>=0) {
367                 new_uri_bk = req->new_uri;
368                 req->new_uri = t->uac[t->relayed_reply_branch].uri;
369                 req->parsed_uri_ok = 0;
370         } else {
371                 new_uri_bk.len = -1;
372                 new_uri_bk.s = 0;
373         }
374         /* set env variables */
375         env_set_to( get_rpl_to(t,reply) );
376         env_set_code_status( code, reply);
377
378         if ( is_log_acc_on(req) ) {
379                 env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
380                 acc_log_request(req);
381         }
382 #ifdef SQL_ACC
383         if (is_db_acc_on(req)) {
384                 env_set_text( db_table_acc.s, db_table_acc.len);
385                 acc_db_request(req);
386         }
387 #endif
388 #ifdef RAD_ACC
389         if (is_rad_acc_on(req))
390                 acc_rad_request(req);
391 #endif
392 /* DIAMETER */
393 #ifdef DIAM_ACC
394         if (is_diam_acc_on(req))
395                 acc_diam_request(req);
396 #endif
397
398         if (new_uri_bk.len>=0) {
399                 req->new_uri = new_uri_bk;
400                 req->parsed_uri_ok = 0;
401         }
402 }
403
404
405
406 static inline void acc_onack( struct cell* t, struct sip_msg *req,
407                 struct sip_msg *ack, int code)
408 {
409         if (acc_preparse_req(ack)<0)
410                 return;
411
412         /* set env variables */
413         env_set_to( ack->to?ack->to:req->to );
414         env_set_code_status( t->uas.status, 0 );
415
416         if (is_log_acc_on(req)) {
417                 env_set_text( ACC_ACKED, ACC_ACKED_LEN);
418                 acc_log_request( ack );
419         }
420 #ifdef SQL_ACC
421         if (is_db_acc_on(req)) {
422                 env_set_text( db_table_acc.s, db_table_acc.len);
423                 acc_db_request( ack );
424         }
425 #endif
426 #ifdef RAD_ACC
427         if (is_rad_acc_on(req)) {
428                 acc_rad_request(ack);
429         }
430 #endif
431 /* DIAMETER */
432 #ifdef DIAM_ACC
433         if (is_diam_acc_on(req)) {
434                 acc_diam_request(ack);
435         }
436 #endif
437         
438 }
439
440
441
442 static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps )
443 {
444         if (type&TMCB_RESPONSE_OUT) {
445                 acc_onreply( t, ps->req, ps->rpl, ps->code);
446         } else if (type&TMCB_E2EACK_IN) {
447                 acc_onack( t, t->uas.request, ps->req, ps->code);
448         } else if (type&TMCB_ON_FAILURE) {
449                 on_missed( t, ps->req, ps->rpl, ps->code);
450         } else if (type&TMCB_RESPONSE_IN) {
451                 acc_onreply_in( t, ps->req, ps->rpl, ps->code);
452         }
453 }
454