00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <stdio.h>
00039 #include <string.h>
00040
00041 #include "../../dprint.h"
00042 #include "../../parser/parse_from.h"
00043 #include "../../parser/parse_content.h"
00044 #include "../tm/tm_load.h"
00045 #include "../rr/api.h"
00046 #include "acc.h"
00047 #include "acc_mod.h"
00048 #include "acc_logic.h"
00049
00050 extern struct tm_binds tmb;
00051 extern struct rr_binds rrb;
00052
00053 struct acc_enviroment acc_env;
00054
00055
00056 #define is_acc_flag_set(_rq,_flag) (((_rq)->flags)&(_flag))
00057 #define reset_acc_flag(_rq,_flag) (_rq)->flags &= ~(_flag)
00058
00059 #define is_failed_acc_on(_rq) is_acc_flag_set(_rq,failed_transaction_flag)
00060
00061 #define is_log_acc_on(_rq) is_acc_flag_set(_rq,log_flag)
00062 #define is_log_mc_on(_rq) is_acc_flag_set(_rq,log_missed_flag)
00063
00064 #ifdef SQL_ACC
00065 #define is_db_acc_on(_rq) is_acc_flag_set(_rq,db_flag)
00066 #define is_db_mc_on(_rq) is_acc_flag_set(_rq,db_missed_flag)
00067 #else
00068 #define is_db_acc_on(_rq) (0)
00069 #define is_db_mc_on(_rq) (0)
00070 #endif
00071
00072 #ifdef RAD_ACC
00073 #define is_rad_acc_on(_rq) is_acc_flag_set(_rq,radius_flag)
00074 #define is_rad_mc_on(_rq) is_acc_flag_set(_rq,radius_missed_flag)
00075 #else
00076 #define is_rad_acc_on(_rq) (0)
00077 #define is_rad_mc_on(_rq) (0)
00078 #endif
00079
00080
00081 #ifdef DIAM_ACC
00082 #define is_diam_acc_on(_rq) is_acc_flag_set(_rq,diameter_flag)
00083 #define is_diam_mc_on(_rq) is_acc_flag_set(_rq,diameter_missed_flag)
00084 #else
00085 #define is_diam_acc_on(_rq) (0)
00086 #define is_diam_mc_on(_rq) (0)
00087 #endif
00088
00089 #define is_acc_on(_rq) \
00090 ( (is_log_acc_on(_rq)) || (is_db_acc_on(_rq)) \
00091 || (is_rad_acc_on(_rq)) || (is_diam_acc_on(_rq)) )
00092
00093 #define is_mc_on(_rq) \
00094 ( (is_log_mc_on(_rq)) || (is_db_mc_on(_rq)) \
00095 || (is_rad_mc_on(_rq)) || (is_diam_mc_on(_rq)) )
00096
00097 #define skip_cancel(_rq) \
00098 (((_rq)->REQ_METHOD==METHOD_CANCEL) && report_cancels==0)
00099
00100
00101
00102
00103 static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps );
00104
00105
00106 static inline struct hdr_field* get_rpl_to( struct cell *t,
00107 struct sip_msg *reply)
00108 {
00109 if (reply==FAKED_REPLY || !reply || !reply->to)
00110 return t->uas.request->to;
00111 else
00112 return reply->to;
00113 }
00114
00115
00116 static inline void env_set_to(struct hdr_field *to)
00117 {
00118 acc_env.to = to;
00119 }
00120
00121
00122 static inline void env_set_text(char *p, int len)
00123 {
00124 acc_env.text.s = p;
00125 acc_env.text.len = len;
00126 }
00127
00128
00129 static inline void env_set_code_status( int code, struct sip_msg *reply)
00130 {
00131 static char code_buf[INT2STR_MAX_LEN];
00132
00133 acc_env.code = code;
00134 if (reply==FAKED_REPLY || reply==NULL) {
00135
00136 acc_env.code_s.s =
00137 int2bstr((unsigned long)code, code_buf, &acc_env.code_s.len);
00138
00139 acc_env.reason.s = error_text(code);
00140 acc_env.reason.len = strlen(acc_env.reason.s);
00141 } else {
00142 acc_env.code_s = reply->first_line.u.reply.status;
00143 acc_env.reason = reply->first_line.u.reply.reason;
00144 }
00145 }
00146
00147
00148 static inline void env_set_comment(struct acc_param *accp)
00149 {
00150 acc_env.code = accp->code;
00151 acc_env.code_s = accp->code_s;
00152 acc_env.reason = accp->reason;
00153 }
00154
00155
00156 static inline int acc_preparse_req(struct sip_msg *req)
00157 {
00158 if ( (parse_headers(req,HDR_CALLID_F|HDR_CSEQ_F|HDR_FROM_F|HDR_TO_F,0)<0)
00159 || (parse_from_header(req)<0 ) ) {
00160 LM_ERR("failed to preparse request\n");
00161 return -1;
00162 }
00163 return 0;
00164 }
00165
00166
00167
00168 int w_acc_log_request(struct sip_msg *rq, char *comment, char *foo)
00169 {
00170 if (acc_preparse_req(rq)<0)
00171 return -1;
00172 env_set_to( rq->to );
00173 env_set_comment((struct acc_param*)comment);
00174 env_set_text( ACC_REQUEST, ACC_REQUEST_LEN);
00175 return acc_log_request(rq);
00176 }
00177
00178
00179 #ifdef SQL_ACC
00180 int w_acc_db_request(struct sip_msg *rq, char *comment, char *table)
00181 {
00182 if (!table) {
00183 LM_ERR("db support not configured\n");
00184 return -1;
00185 }
00186 if (acc_preparse_req(rq)<0)
00187 return -1;
00188 env_set_to( rq->to );
00189 env_set_comment((struct acc_param*)comment);
00190 env_set_text(table, strlen(table));
00191 return acc_db_request(rq);
00192 }
00193 #endif
00194
00195
00196 #ifdef RAD_ACC
00197 int w_acc_rad_request(struct sip_msg *rq, char *comment, char *foo)
00198 {
00199 if (acc_preparse_req(rq)<0)
00200 return -1;
00201 env_set_to( rq->to );
00202 env_set_comment((struct acc_param*)comment);
00203 return acc_rad_request(rq);
00204 }
00205 #endif
00206
00207
00208 #ifdef DIAM_ACC
00209 int w_acc_diam_request(struct sip_msg *rq, char *comment, char *foo)
00210 {
00211 if (acc_preparse_req(rq)<0)
00212 return -1;
00213 env_set_to( rq->to );
00214 env_set_comment((struct acc_param*)comment);
00215 return acc_diam_request(rq);
00216 }
00217 #endif
00218
00219
00220
00221 void acc_onreq( struct cell* t, int type, struct tmcb_params *ps )
00222 {
00223 int tmcb_types;
00224 int is_invite;
00225
00226 if ( ps->req && !skip_cancel(ps->req) &&
00227 (is_acc_on(ps->req) || is_mc_on(ps->req)) ) {
00228
00229 if (acc_preparse_req(ps->req)<0)
00230 return;
00231 is_invite = (ps->req->REQ_METHOD==METHOD_INVITE)?1:0;
00232
00233 tmcb_types =
00234
00235 TMCB_RESPONSE_OUT |
00236
00237 ((report_ack && is_acc_on(ps->req))?TMCB_E2EACK_IN:0) |
00238
00239 TMCB_RESPONSE_IN |
00240
00241 ((is_invite && is_mc_on(ps->req))?TMCB_ON_FAILURE:0) ;
00242 if (tmb.register_tmcb( 0, t, tmcb_types, tmcb_func, 0, 0 )<=0) {
00243 LM_ERR("cannot register additional callbacks\n");
00244 return;
00245 }
00246
00247 if( detect_direction && !rrb.is_direction(ps->req,RR_FLOW_UPSTREAM) ) {
00248 LM_DBG("detected an UPSTREAM req -> flaging it\n");
00249 ps->req->msg_flags |= FL_REQ_UPSTREAM;
00250 }
00251 }
00252 }
00253
00254
00255
00256
00257 static inline int should_acc_reply(struct sip_msg *req,struct sip_msg *rpl,
00258 int code)
00259 {
00260
00261
00262 if ( !is_failed_acc_on(req) && code >=300 )
00263 return 0;
00264 if ( !is_acc_on(req) )
00265 return 0;
00266 if ( code<200 && !(early_media &&
00267 parse_headers(rpl,HDR_CONTENTLENGTH_F, 0)==0 && rpl->content_length &&
00268 get_content_length(rpl)>0 ) )
00269 return 0;
00270
00271 return 1;
00272 }
00273
00274
00275
00276
00277 static inline void acc_onreply_in(struct cell *t, struct sip_msg *req,
00278 struct sip_msg *reply, int code)
00279 {
00280
00281
00282 if ( (reply && reply!=FAKED_REPLY) && (should_acc_reply(req,reply,code)
00283 || (is_invite(t) && code>=300 && is_mc_on(req))) ) {
00284 parse_headers(reply, HDR_TO_F, 0 );
00285 }
00286 }
00287
00288
00289
00290
00291 static inline void on_missed(struct cell *t, struct sip_msg *req,
00292 struct sip_msg *reply, int code)
00293 {
00294 str new_uri_bk;
00295 int flags_to_reset = 0;
00296
00297
00298 new_uri_bk = req->new_uri;
00299 req->new_uri = t->uac[t->nr_of_outgoings-1].uri;
00300 req->parsed_uri_ok = 0;
00301
00302 env_set_to( get_rpl_to(t,reply) );
00303 env_set_code_status( code, reply);
00304
00305
00306
00307
00308
00309
00310 if (is_log_mc_on(req)) {
00311 env_set_text( ACC_MISSED, ACC_MISSED_LEN);
00312 acc_log_request( req );
00313 flags_to_reset |= log_missed_flag;
00314 }
00315 #ifdef SQL_ACC
00316 if (is_db_mc_on(req)) {
00317 env_set_text(db_table_mc.s, db_table_mc.len);
00318 acc_db_request( req );
00319 flags_to_reset |= db_missed_flag;
00320 }
00321 #endif
00322 #ifdef RAD_ACC
00323 if (is_rad_mc_on(req)) {
00324 acc_rad_request( req );
00325 flags_to_reset |= radius_missed_flag;
00326 }
00327 #endif
00328
00329 #ifdef DIAM_ACC
00330 if (is_diam_mc_on(req)) {
00331 acc_diam_request( req );
00332 flags_to_reset |= diameter_missed_flag;
00333 }
00334 #endif
00335
00336
00337
00338
00339
00340 reset_acc_flag( req, flags_to_reset );
00341
00342 req->new_uri = new_uri_bk;
00343 req->parsed_uri_ok = 0;
00344 }
00345
00346
00347
00348
00349 static inline void acc_onreply( struct cell* t, struct sip_msg *req,
00350 struct sip_msg *reply, int code)
00351 {
00352 str new_uri_bk;
00353
00354
00355
00356
00357 if (is_invite(t) && code>=300 && is_mc_on(req) )
00358 on_missed(t, req, reply, code);
00359
00360 if (!should_acc_reply(req, reply, code))
00361 return;
00362
00363
00364 if (t->relayed_reply_branch>=0) {
00365 new_uri_bk = req->new_uri;
00366 req->new_uri = t->uac[t->relayed_reply_branch].uri;
00367 req->parsed_uri_ok = 0;
00368 } else {
00369 new_uri_bk.len = -1;
00370 new_uri_bk.s = 0;
00371 }
00372
00373 env_set_to( get_rpl_to(t,reply) );
00374 env_set_code_status( code, reply);
00375
00376 if ( is_log_acc_on(req) ) {
00377 env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
00378 acc_log_request(req);
00379 }
00380 #ifdef SQL_ACC
00381 if (is_db_acc_on(req)) {
00382 env_set_text( db_table_acc.s, db_table_acc.len);
00383 acc_db_request(req);
00384 }
00385 #endif
00386 #ifdef RAD_ACC
00387 if (is_rad_acc_on(req))
00388 acc_rad_request(req);
00389 #endif
00390
00391 #ifdef DIAM_ACC
00392 if (is_diam_acc_on(req))
00393 acc_diam_request(req);
00394 #endif
00395
00396 if (new_uri_bk.len>=0) {
00397 req->new_uri = new_uri_bk;
00398 req->parsed_uri_ok = 0;
00399 }
00400 }
00401
00402
00403
00404 static inline void acc_onack( struct cell* t, struct sip_msg *req,
00405 struct sip_msg *ack, int code)
00406 {
00407 if (acc_preparse_req(ack)<0)
00408 return;
00409
00410
00411 env_set_to( ack->to?ack->to:req->to );
00412 env_set_code_status( t->uas.status, 0 );
00413
00414 if (is_log_acc_on(req)) {
00415 env_set_text( ACC_ACKED, ACC_ACKED_LEN);
00416 acc_log_request( ack );
00417 }
00418 #ifdef SQL_ACC
00419 if (is_db_acc_on(req)) {
00420 env_set_text( db_table_acc.s, db_table_acc.len);
00421 acc_db_request( ack );
00422 }
00423 #endif
00424 #ifdef RAD_ACC
00425 if (is_rad_acc_on(req)) {
00426 acc_rad_request(ack);
00427 }
00428 #endif
00429
00430 #ifdef DIAM_ACC
00431 if (is_diam_acc_on(req)) {
00432 acc_diam_request(ack);
00433 }
00434 #endif
00435
00436 }
00437
00438
00439
00440 static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps )
00441 {
00442 if (type&TMCB_RESPONSE_OUT) {
00443 acc_onreply( t, ps->req, ps->rpl, ps->code);
00444 } else if (type&TMCB_E2EACK_IN) {
00445 acc_onack( t, t->uas.request, ps->req, ps->code);
00446 } else if (type&TMCB_ON_FAILURE) {
00447 on_missed( t, ps->req, ps->rpl, ps->code);
00448 } else if (type&TMCB_RESPONSE_IN) {
00449 acc_onreply_in( t, ps->req, ps->rpl, ps->code);
00450 }
00451 }
00452