diff --git a/src/modules/dlgs/dlgs_mod.c b/src/modules/dlgs/dlgs_mod.c index 93d85c577a5..499de845635 100644 --- a/src/modules/dlgs/dlgs_mod.c +++ b/src/modules/dlgs/dlgs_mod.c @@ -37,8 +37,9 @@ MODULE_VERSION -int _dlgs_lifetime = 10800; -int _dlgs_initlifetime = 180; +int _dlgs_active_lifetime = 10800; +int _dlgs_init_lifetime = 180; +int _dlgs_finish_lifetime = 10; static int _dlgs_timer_interval = 30; static int _dlgs_htsize_param = 9; @@ -51,15 +52,18 @@ static int mod_init(void); static int child_init(int); static void mod_destroy(void); -static int w_dlgs_manage(sip_msg_t *msg, char *psrc, char *pdst, char *pdata); -static int w_dlgs_tags_add(sip_msg_t *msg, char *ptags, char *str2); -static int w_dlgs_tags_rm(sip_msg_t *msg, char *ptags, char *str2); -static int w_dlgs_tags_count(sip_msg_t *msg, char *ptags, char *str2); +static int w_dlgs_init(sip_msg_t *msg, char *psrc, char *pdst, char *pdata); +static int w_dlgs_update(sip_msg_t *msg, char *p1, char *p2); +static int w_dlgs_tags_add(sip_msg_t *msg, char *ptags, char *p2); +static int w_dlgs_tags_rm(sip_msg_t *msg, char *ptags, char *p2); +static int w_dlgs_tags_count(sip_msg_t *msg, char *ptags, char *p2); /* clang-format off */ static cmd_export_t cmds[]={ - {"dlgs_manage", (cmd_function)w_dlgs_manage, 3, fixup_spve_all, + {"dlgs_init", (cmd_function)w_dlgs_init, 3, fixup_spve_all, fixup_free_spve_all, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE|ONSEND_ROUTE}, + {"dlgs_update", (cmd_function)w_dlgs_update, 0, 0, + 0, ONSEND_ROUTE}, {"dlgs_tags_add", (cmd_function)w_dlgs_tags_add, 1, fixup_spve_null, fixup_spve_null, ANY_ROUTE}, {"dlgs_tags_rm", (cmd_function)w_dlgs_tags_rm, 1, fixup_spve_null, @@ -70,10 +74,11 @@ static cmd_export_t cmds[]={ }; static param_export_t params[]={ - {"lifetime", PARAM_INT, &_dlgs_lifetime}, - {"initlifetime", PARAM_INT, &_dlgs_initlifetime}, - {"timer_interval", PARAM_INT, &_dlgs_timer_interval}, - {"hash_size", PARAM_INT, &_dlgs_htsize_param}, + {"active_lifetime", PARAM_INT, &_dlgs_active_lifetime}, + {"init_lifetime", PARAM_INT, &_dlgs_init_lifetime}, + {"finish_lifetime", PARAM_INT, &_dlgs_finish_lifetime}, + {"timer_interval", PARAM_INT, &_dlgs_timer_interval}, + {"hash_size", PARAM_INT, &_dlgs_htsize_param}, {0, 0, 0} }; @@ -153,23 +158,89 @@ static void mod_destroy(void) /** * */ -static int ki_dlgs_manage(sip_msg_t *msg, str *src, str *dst, str *data) +static int ki_dlgs_init(sip_msg_t *msg, str *src, str *dst, str *data) { + int rtype = 0; + int rmethod = 0; + int ret = 0; + + if(msg->first_line.type == SIP_REQUEST) { + rtype = SIP_REQUEST; + if(msg->first_line.u.request.method_value == METHOD_INVITE) { + rmethod = METHOD_INVITE; + } else { + rmethod = msg->first_line.u.request.method_value; + } + } else { + rtype = SIP_REPLY; + if(msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1) || + (msg->cseq==NULL))) { + LM_ERR("no CSEQ header\n"); + return -1; + } + rmethod = get_cseq(msg)->method_id; + } + + if(rmethod == METHOD_INVITE) { + ret = dlgs_add_item(msg, src, dst, data); + LM_DBG("added item return code: %d\n", ret); + if(rtype==SIP_REPLY) { + dlgs_update_item(msg); + } + } else { + dlgs_update_item(msg); + } + return 1; } /** * */ -static int w_dlgs_manage(sip_msg_t *msg, char *psrc, char *pdst, char *pdata) +static int w_dlgs_init(sip_msg_t *msg, char *psrc, char *pdst, char *pdata) { + str vsrc = STR_NULL; + str vdst = STR_NULL; + str vdata = str_init(""); + + if(fixup_get_svalue(msg, (gparam_t*)psrc, &vsrc) < 0) { + LM_ERR("failed to get p1\n"); + return -1; + } + if(fixup_get_svalue(msg, (gparam_t*)pdst, &vdst) < 0) { + LM_ERR("failed to get p2\n"); + return -1; + } + if(fixup_get_svalue(msg, (gparam_t*)pdata, &vdata) < 0) { + LM_ERR("failed to get p3\n"); + return -1; + } + + return ki_dlgs_init(msg, &vsrc, &vdst, &vdata); +} + +/** + * + */ +static int ki_dlgs_update(sip_msg_t *msg) +{ + dlgs_update_item(msg); + return 1; } /** * */ -static int w_dlgs_tags_add(sip_msg_t *msg, char *ptags, char *str2) +static int w_dlgs_update(sip_msg_t *msg, char *p1, char *p2) +{ + return ki_dlgs_update(msg); +} + +/** + * + */ +static int w_dlgs_tags_add(sip_msg_t *msg, char *ptags, char *p2) { return 1; } @@ -177,7 +248,7 @@ static int w_dlgs_tags_add(sip_msg_t *msg, char *ptags, char *str2) /** * */ -static int w_dlgs_tags_rm(sip_msg_t *msg, char *ptags, char *str2) +static int w_dlgs_tags_rm(sip_msg_t *msg, char *ptags, char *p2) { return 1; } @@ -185,7 +256,7 @@ static int w_dlgs_tags_rm(sip_msg_t *msg, char *ptags, char *str2) /** * */ -static int w_dlgs_tags_count(sip_msg_t *msg, char *ptags, char *str2) +static int w_dlgs_tags_count(sip_msg_t *msg, char *ptags, char *p2) { return 1; } @@ -195,11 +266,16 @@ static int w_dlgs_tags_count(sip_msg_t *msg, char *ptags, char *str2) */ /* clang-format off */ static sr_kemi_t sr_kemi_dlgs_exports[] = { - { str_init("dlgs"), str_init("dlgs_manage"), - SR_KEMIP_INT, ki_dlgs_manage, + { str_init("dlgs"), str_init("dlgs_init"), + SR_KEMIP_INT, ki_dlgs_init, { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } }, + { str_init("dlgs"), str_init("dlgs_update"), + SR_KEMIP_INT, ki_dlgs_update, + { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE, + SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } + }, { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } } }; diff --git a/src/modules/dlgs/dlgs_records.c b/src/modules/dlgs/dlgs_records.c index 2f73346c8ae..d837483ef41 100644 --- a/src/modules/dlgs/dlgs_records.c +++ b/src/modules/dlgs/dlgs_records.c @@ -42,20 +42,14 @@ #define dlgs_compute_hash(_s) core_case_hash(_s, 0, 0) #define dlgs_get_index(_h, _size) (_h) & ((_size)-1) -extern int _dlgs_lifetime; -extern int _dlgs_initlifetime; +extern int _dlgs_active_lifetime; +extern int _dlgs_init_lifetime; +extern int _dlgs_finish_lifetime; extern int _dlgs_htsize; extern sruid_t _dlgs_sruid; static dlgs_ht_t *_dlgs_htb = NULL; -typedef struct _dlgs_sipfields { - str callid; - str ftag; - str ttag; -} dlgs_sipfields_t; - - /** * */ @@ -64,7 +58,7 @@ int dlgs_init(void) if (_dlgs_htb!=NULL) { return 0; } - _dlgs_htb = dlgs_ht_init(_dlgs_htsize, _dlgs_lifetime, _dlgs_initlifetime); + _dlgs_htb = dlgs_ht_init(); if(_dlgs_htb==NULL) { return -1; } @@ -79,7 +73,7 @@ int dlgs_destroy(void) if (_dlgs_htb!=NULL) { return 0; } - dlgs_ht_destroy(_dlgs_htb); + dlgs_ht_destroy(); _dlgs_htb = NULL; return 0; @@ -200,7 +194,7 @@ int dlgs_item_free(dlgs_item_t *item) } -dlgs_ht_t *dlgs_ht_init(unsigned int htsize, int lifetime, int initlifetime) +dlgs_ht_t *dlgs_ht_init(void) { int i; dlgs_ht_t *dsht = NULL; @@ -211,9 +205,10 @@ dlgs_ht_t *dlgs_ht_init(unsigned int htsize, int lifetime, int initlifetime) return NULL; } memset(dsht, 0, sizeof(dlgs_ht_t)); - dsht->htsize = htsize; - dsht->htlifetime = lifetime; - dsht->htinitlifetime = initlifetime; + dsht->htsize = _dlgs_htsize; + dsht->alifetime = _dlgs_active_lifetime; + dsht->ilifetime = _dlgs_init_lifetime; + dsht->flifetime = _dlgs_finish_lifetime; dsht->slots = (dlgs_slot_t*)shm_malloc(dsht->htsize * sizeof(dlgs_slot_t)); if(dsht->slots == NULL) { @@ -242,11 +237,13 @@ dlgs_ht_t *dlgs_ht_init(unsigned int htsize, int lifetime, int initlifetime) return dsht; } -int dlgs_ht_destroy(dlgs_ht_t *dsht) +int dlgs_ht_destroy(void) { int i; dlgs_item_t *it, *it0; + dlgs_ht_t *dsht; + dsht = _dlgs_htb; if(dsht == NULL) { return -1; } @@ -269,13 +266,15 @@ int dlgs_ht_destroy(dlgs_ht_t *dsht) } -int dlgs_add_item(dlgs_ht_t *dsht, sip_msg_t *msg, str *src, str *dst, str *data) +int dlgs_add_item(sip_msg_t *msg, str *src, str *dst, str *data) { unsigned int idx; unsigned int hid; dlgs_item_t *it, *prev, *nitem; dlgs_sipfields_t sf; + dlgs_ht_t *dsht; + dsht = _dlgs_htb; if(dsht == NULL || dsht->slots == NULL) { LM_ERR("invalid parameters.\n"); return -1; @@ -301,9 +300,9 @@ int dlgs_add_item(dlgs_ht_t *dsht, sip_msg_t *msg, str *src, str *dst, str *data if(sf.callid.len == it->callid.len && strncmp(sf.callid.s, it->callid.s, sf.callid.len) == 0) { lock_release(&dsht->slots[idx].lock); - LM_WARN("call-id already in hash table [%.*s].\n", sf.callid.len, + LM_DBG("call-id already in hash table [%.*s].\n", sf.callid.len, sf.callid.s); - return -2; + return 1; } prev = it; it = it->next; @@ -334,13 +333,15 @@ int dlgs_add_item(dlgs_ht_t *dsht, sip_msg_t *msg, str *src, str *dst, str *data return 0; } -int dlgs_unlock_item(dlgs_ht_t *dsht, sip_msg_t *msg) +int dlgs_unlock_item(sip_msg_t *msg) { unsigned int idx; unsigned int hid; str *cid; dlgs_sipfields_t sf; + dlgs_ht_t *dsht; + dsht = _dlgs_htb; if(dsht == NULL || dsht->slots == NULL) { LM_ERR("invalid parameters\n"); return -1; @@ -364,14 +365,16 @@ int dlgs_unlock_item(dlgs_ht_t *dsht, sip_msg_t *msg) return 0; } -dlgs_item_t *dlgs_get_item(dlgs_ht_t *dsht, sip_msg_t *msg) +dlgs_item_t *dlgs_get_item(sip_msg_t *msg) { unsigned int idx; unsigned int hid; dlgs_item_t *it; str *cid; dlgs_sipfields_t sf; + dlgs_ht_t *dsht; + dsht = _dlgs_htb; if(dsht == NULL || dsht->slots == NULL) { LM_ERR("invalid parameters\n"); return NULL; @@ -408,14 +411,16 @@ dlgs_item_t *dlgs_get_item(dlgs_ht_t *dsht, sip_msg_t *msg) } -int dlgs_del_item(dlgs_ht_t *dsht, sip_msg_t *msg) +int dlgs_del_item(sip_msg_t *msg) { unsigned int idx; unsigned int hid; dlgs_item_t *it; str *cid; dlgs_sipfields_t sf; + dlgs_ht_t *dsht; + dsht = _dlgs_htb; if(dsht == NULL || dsht->slots == NULL) { LM_ERR("invalid parameters\n"); return -1; @@ -463,11 +468,13 @@ int dlgs_del_item(dlgs_ht_t *dsht, sip_msg_t *msg) /** * */ -int dlgs_ht_dbg(dlgs_ht_t *dsht) +int dlgs_ht_dbg(void) { int i; dlgs_item_t *it; + dlgs_ht_t *dsht; + dsht = _dlgs_htb; for(i = 0; i < dsht->htsize; i++) { lock_get(&dsht->slots[i].lock); LM_ERR("htable[%d] -- <%d>\n", i, dsht->slots[i].esize); @@ -489,6 +496,98 @@ int dlgs_ht_dbg(dlgs_ht_t *dsht) return 0; } +/** + * + */ +int dlgs_update_item(sip_msg_t *msg) +{ + int rtype = 0; + int rmethod = 0; + int rcode = 0; + int ostate = 0; + int nstate = 0; + dlgs_item_t *it; + time_t tnow; + + if(msg->first_line.type == SIP_REQUEST) { + rtype = SIP_REQUEST; + if(msg->first_line.u.request.method_value == METHOD_INVITE) { + rmethod = METHOD_INVITE; + } else { + rmethod = msg->first_line.u.request.method_value; + } + } else { + rtype = SIP_REPLY; + if(msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1) || + (msg->cseq==NULL))) { + LM_ERR("no CSEQ header\n"); + return -1; + } + rmethod = get_cseq(msg)->method_id; + rcode = (int)msg->first_line.u.reply.statuscode; + } + + tnow = time(NULL); + + it = dlgs_get_item(msg); + if(it==NULL) { + LM_DBG("no matching item found\n"); + return 0; + } + ostate = it->state; + if(rtype == SIP_REQUEST) { + switch(rmethod) { + case METHOD_ACK: + if(it->state==DLGS_STATE_ANSWERED) { + it->state = DLGS_STATE_CONFIRMED; + } + break; + case METHOD_CANCEL: + if(it->statestate = DLGS_STATE_NOTANSWERED; + it->ts_finish = tnow; + } + break; + case METHOD_BYE: + if(it->state==DLGS_STATE_ANSWERED + || it->state==DLGS_STATE_CONFIRMED) { + it->state = DLGS_STATE_TERMINATED; + it->ts_finish = tnow; + } + break; + } + goto done; + } + + switch(rmethod) { + case METHOD_INVITE: + if(rcode>=100 && rcode<200) { + if(it->state==DLGS_STATE_INIT) { + it->state = DLGS_STATE_PROGRESS; + } + } else if(rcode>=200 && rcode<300) { + if(it->state==DLGS_STATE_INIT + || it->state==DLGS_STATE_PROGRESS) { + it->state = DLGS_STATE_ANSWERED; + it->ts_answer = tnow; + } + } else if(rcode>=300) { + if(it->state==DLGS_STATE_INIT + || it->state==DLGS_STATE_PROGRESS) { + it->state = DLGS_STATE_NOTANSWERED; + it->ts_finish = tnow; + } + } + break; + } + +done: + nstate = it->state; + dlgs_unlock_item(msg); + LM_DBG("old state %d - new state %d\n", ostate, nstate); + return 0; +} + /** * */ @@ -511,14 +610,17 @@ void dlgs_ht_timer(unsigned int ticks, void *param) while(it) { ite = NULL; if(it->state == DLGS_STATE_INIT || it->state == DLGS_STATE_PROGRESS - || it->state == DLGS_STATE_ANSWERED - || it->state == DLGS_STATE_NOTANSWERED) { - if(it->ts_init + _dlgs_htb->htinitlifetime < tnow) { + || it->state == DLGS_STATE_ANSWERED) { + if(it->ts_init + _dlgs_htb->ilifetime < tnow) { ite = it; } - } else if(it->state == DLGS_STATE_CONFIRMED + } else if(it->state == DLGS_STATE_CONFIRMED) { + if(it->ts_answer + _dlgs_htb->alifetime < tnow) { + ite = it; + } + } else if(it->state == DLGS_STATE_NOTANSWERED || it->state == DLGS_STATE_TERMINATED) { - if(it->ts_answer + _dlgs_htb->htlifetime < tnow) { + if(it->ts_finish + _dlgs_htb->flifetime < tnow) { ite = it; } } @@ -568,6 +670,41 @@ static const char *dlgs_rpc_list_doc[2] = { */ static void dlgs_rpc_list(rpc_t *rpc, void *ctx) { + dlgs_item_t *it; + int n = 0; + int i; + void *th; + + if(_dlgs_htb == NULL) { + return; + } + + for(i = 0; i < _dlgs_htb->htsize; i++) { + lock_get(&_dlgs_htb->slots[i].lock); + it = _dlgs_htb->slots[i].first; + while(it) { + if (rpc->add(ctx, "{", &th) < 0) { + lock_release(&_dlgs_htb->slots[i].lock); + rpc->fault(ctx, 500, "Internal error creating rpc"); + return; + } + if(rpc->struct_add(th, "dSSSSuuu", + "count", ++n, + "src", &it->src, + "dst", &it->dst, + "data", &it->data, + "ruid", &it->ruid, + "ts_init", (unsigned int)it->ts_init, + "ts_answer", (unsigned int)it->ts_answer, + "state", it->state)<0) { + lock_release(&_dlgs_htb->slots[i].lock); + rpc->fault(ctx, 500, "Internal error creating item"); + return; + } + it = it->next; + } + lock_release(&_dlgs_htb->slots[i].lock); + } } /* clang-format off */ @@ -575,7 +712,7 @@ rpc_export_t dlgs_rpc_cmds[] = { {"dlgs.stats", dlgs_rpc_stats, dlgs_rpc_stats_doc, 0}, {"dlgs.list", dlgs_rpc_list, - dlgs_rpc_list_doc, 0}, + dlgs_rpc_list_doc, RET_ARRAY}, {0, 0, 0, 0} }; diff --git a/src/modules/dlgs/dlgs_records.h b/src/modules/dlgs/dlgs_records.h index 9fbc7f9bb9c..6ecd668d767 100644 --- a/src/modules/dlgs/dlgs_records.h +++ b/src/modules/dlgs/dlgs_records.h @@ -38,6 +38,15 @@ #define DLGS_STATE_TERMINATED 4 #define DLGS_STATE_NOTANSWERED 5 +typedef struct _dlgs_stats { + unsigned int c_init; + unsigned int c_progress; + unsigned int c_answered; + unsigned int c_confirmed; + unsigned int c_terminted; + unsigned int c_notanswered; +} dlgs_stats_t; + typedef struct _dlgs_item { unsigned int hashid; /* item hash id */ str callid; /* sip call-id */ @@ -50,6 +59,7 @@ typedef struct _dlgs_item { int state; /* state */ time_t ts_init; time_t ts_answer; + time_t ts_finish; struct _dlgs_item *prev; struct _dlgs_item *next; } dlgs_item_t; @@ -62,30 +72,28 @@ typedef struct _dlgs_slot { typedef struct _dlgs_ht { unsigned int htsize; - unsigned int htlifetime; - unsigned int htinitlifetime; + unsigned int alifetime; + unsigned int ilifetime; + unsigned int flifetime; + dlgs_stats_t fstats; dlgs_slot_t *slots; } dlgs_ht_t; -typedef struct _dlgs_stats { - unsigned int c_init; - unsigned int c_progress; - unsigned int c_answered; - unsigned int c_confirmed; - unsigned int c_terminted; - unsigned int c_notanswered; -} dlgs_stats_t; - +typedef struct _dlgs_sipfields { + str callid; + str ftag; + str ttag; +} dlgs_sipfields_t; /* clang-format on */ -dlgs_ht_t *dlgs_ht_init(unsigned int htsize, int lifetime, int initlifetime); -int dlgs_ht_destroy(dlgs_ht_t *dsht); -int dlgs_add_item(dlgs_ht_t *dsht, sip_msg_t *msg, str *src, str *dst, str *data); -int dlgs_del_item(dlgs_ht_t *dsht, sip_msg_t *msg); -dlgs_item_t *dlgs_get_item(dlgs_ht_t *dsht, sip_msg_t *msg); -int dlgs_unlock_item(dlgs_ht_t *dsht, sip_msg_t *msg); +dlgs_ht_t *dlgs_ht_init(void); +int dlgs_ht_destroy(void); +int dlgs_add_item(sip_msg_t *msg, str *src, str *dst, str *data); +int dlgs_del_item(sip_msg_t *msg); +dlgs_item_t *dlgs_get_item(sip_msg_t *msg); +int dlgs_unlock_item(sip_msg_t *msg); -int dlgs_ht_dbg(dlgs_ht_t *dsht); +int dlgs_ht_dbg(void); int dlgs_item_free(dlgs_item_t *cell); void dlgs_ht_timer(unsigned int ticks, void *param); @@ -93,5 +101,6 @@ void dlgs_ht_timer(unsigned int ticks, void *param); int dlgs_init(void); int dlgs_destroy(void); int dlgs_rpc_init(void); +int dlgs_update_item(sip_msg_t *msg); #endif \ No newline at end of file