Module: kamailio
Branch: master
Commit: 956be0edcd816134650c5efccb7965fccb4d5916
URL:
https://github.com/kamailio/kamailio/commit/956be0edcd816134650c5efccb7965f…
Author: jaybeepee <jason.penton(a)gmail.com>
Committer: jaybeepee <jason.penton(a)gmail.com>
Date: 2015-09-11T11:44:31+02:00
modules/cdp: fixed race condition between CCR update and CCR terminate - lean priority
towards T
---
Modified: modules/cdp/acctstatemachine.c
---
Diff:
https://github.com/kamailio/kamailio/commit/956be0edcd816134650c5efccb7965f…
Patch:
https://github.com/kamailio/kamailio/commit/956be0edcd816134650c5efccb7965f…
---
diff --git a/modules/cdp/acctstatemachine.c b/modules/cdp/acctstatemachine.c
index d4e524d..31304d2 100644
--- a/modules/cdp/acctstatemachine.c
+++ b/modules/cdp/acctstatemachine.c
@@ -210,29 +210,41 @@ inline int cc_acc_client_stateful_sm_process(cdp_session_t* s, int
event, AAAMes
}
break;
case ACC_CC_ST_PENDING_U:
- if (event == ACC_CC_EV_RECV_ANS && msg && !is_req(msg)) {
- rc = get_result_code(msg);
- if (rc >= 2000 && rc < 3000) {
- event = ACC_CC_EV_RECV_ANS_SUCCESS;
- } else {
- event = ACC_CC_EV_RECV_ANS_UNSUCCESS;
- }
- }
- switch (event) {
- case ACC_CC_EV_RECV_ANS_SUCCESS:
- x->state = ACC_CC_ST_OPEN;
- LM_DBG("success CCA for UPDATE\n");
- update_gsu_response_timers(x, msg);
- break;
- case ACC_CC_EV_RECV_ANS_UNSUCCESS:
- //TODO: check whether we grant or terminate service to callback clients
- x->state = ACC_CC_ST_DISCON;
- LM_ERR("update failed... going back to IDLE/DISCON\n");
- break;
- default:
- LM_ERR("Received unknown event [%d] in state [%d]\n", event,
x->state);
- break;
- }
+
+ /**Richard added Aug 5 - there is a potential race condition
where you may send a CCR-U immediately followed by CCR-T
+ * and then receive a CCA-T while in state ACC_CC_ST_PENDING_U
(e.g. if update timer and dialog termination at same time)
+ * In this event you would incorrectly ignore the CCR-T
+ * Solution is to change state to change state to
ACC_CC_ST_PENDING_T if CCR-T is sent while in this state */
+ if (event == ACC_CC_EV_SEND_REQ && msg &&
get_accounting_record_type(msg) == 4 /*TERMINATE RECORD*/) {
+ LM_ERR("Received CCR-T while in state
ACC_CC_ST_PENDING_U, just going to change to ACC_CC_ST_PENDING_T\n");
+ s->u.cc_acc.state = ACC_CC_ST_PENDING_T;
+ //update our reservation and its timers...
+ update_gsu_request_timers(x, msg);
+ } else {
+ if (event == ACC_CC_EV_RECV_ANS && msg &&
!is_req(msg)) {
+ rc = get_result_code(msg);
+ if (rc >= 2000 && rc < 3000) {
+ event = ACC_CC_EV_RECV_ANS_SUCCESS;
+ } else {
+ event = ACC_CC_EV_RECV_ANS_UNSUCCESS;
+ }
+ }
+ switch (event) {
+ case ACC_CC_EV_RECV_ANS_SUCCESS:
+ x->state = ACC_CC_ST_OPEN;
+ LM_DBG("success CCA for
UPDATE\n");
+ update_gsu_response_timers(x, msg);
+ break;
+ case ACC_CC_EV_RECV_ANS_UNSUCCESS:
+ //TODO: check whether we grant or terminate
service to callback clients
+ x->state = ACC_CC_ST_DISCON;
+ LM_ERR("update failed... going back to
IDLE/DISCON\n");
+ break;
+ default:
+ LM_ERR("Received unknown event [%d] in
state [%d]\n", event, x->state);
+ break;
+ }
+ }
break;
case ACC_CC_ST_DISCON:
switch (event) {