From 4b4edbc4ac95c6e9632c5447ccf06a3e16a5c37c Mon Sep 17 00:00:00 2001 From: Joey Golan Date: Mon, 28 Nov 2022 16:46:35 +0200 Subject: [PATCH 1/8] imc: add support to modify member role --- src/modules/imc/doc/imc.xml | 7 ++ src/modules/imc/doc/imc_admin.xml | 14 ++++ src/modules/imc/imc_cmd.c | 120 ++++++++++++++++++++++++++++++ src/modules/imc/imc_cmd.h | 9 +++ src/modules/imc/imc_mng.c | 34 ++++++++- src/modules/imc/imc_mng.h | 5 ++ 6 files changed, 187 insertions(+), 2 deletions(-) diff --git a/src/modules/imc/doc/imc.xml b/src/modules/imc/doc/imc.xml index 99f97a5eed3..f0f4a73d1b0 100644 --- a/src/modules/imc/doc/imc.xml +++ b/src/modules/imc/doc/imc.xml @@ -37,6 +37,13 @@ anca@voice-system.ro + + Joey + Golan +
+ joeygo@gmail.com +
+
2006 diff --git a/src/modules/imc/doc/imc_admin.xml b/src/modules/imc/doc/imc_admin.xml index 85a31a844a1..6f7f5a02582 100644 --- a/src/modules/imc/doc/imc_admin.xml +++ b/src/modules/imc/doc/imc_admin.xml @@ -453,6 +453,20 @@ if(is_method("MESSAGE) -eg: #add sip:john@kamailio.org sip:chat-000@kamailio.org or #add john@kamailio.org sent to sip:chat-000@kamailio.org -error case: return codes: -50 -- -59 + +11.modify + -modify user role in a room + -takes 3 parameters: + 1)the complete address of the user + 2)the role of the user + 3)the address of the room -if not present it will be considered + to be the address in the To header of the message + -only certain users have the right to invite other user: the owner + and the administrators + -roles: owner, admin, member + -eg: #invite sip:john@kamailio.org admin sip:chat-000@kamailio.org + or #invite john@kamailio.org admin sent to sip:chat-000@kamailio.org + -error case: return codes: -120 -- -129 ... diff --git a/src/modules/imc/imc_cmd.c b/src/modules/imc/imc_cmd.c index 8d9c6f3ea18..4f8a1501425 100644 --- a/src/modules/imc/imc_cmd.c +++ b/src/modules/imc/imc_cmd.c @@ -62,6 +62,7 @@ static str msg_join_attempt_bcast = STR_STATIC_INIT(PREFIX "%.*s attempted to jo static str msg_join_attempt_ucast = STR_STATIC_INIT(PREFIX "Private rooms are by invitation only. Room owners have been notified."); static str msg_invite = STR_STATIC_INIT(PREFIX "%.*s invites you to join the room (send '%.*saccept' or '%.*sreject')"); static str msg_add_reject = STR_STATIC_INIT(PREFIX "You don't have the permmission to add members to this room"); +static str msg_modify_reject = STR_STATIC_INIT(PREFIX "You don't have the permmission to modify members in this room"); #if 0 static str msg_rejected = STR_STATIC_INIT(PREFIX "%.*s has rejected invitation"); #endif @@ -289,6 +290,9 @@ int imc_parse_cmd(char *buf, int len, imc_cmd_p cmd) } else if(cmd->name.len==(sizeof("destroy")-1) && !strncasecmp(cmd->name.s, "destroy", cmd->name.len)) { cmd->type = IMC_CMDID_DESTROY; + } else if(cmd->name.len==(sizeof("modify")-1) + && !strncasecmp(cmd->name.s, "modify", cmd->name.len)) { + cmd->type = IMC_CMDID_MODIFY; } else if(cmd->name.len==(sizeof("help")-1) && !strncasecmp(cmd->name.s, "help", cmd->name.len)) { cmd->type = IMC_CMDID_HELP; @@ -1295,6 +1299,122 @@ int imc_handle_message(struct sip_msg* msg, str *msgbody, return rv; } +int imc_handle_modify(struct sip_msg* msg, imc_cmd_t *cmd, + struct imc_uri *src, struct imc_uri *dst) +{ + int rv = -1; + imc_room_p rm = 0; + imc_member_p member = 0; + int flag_member = 0; + str body; + struct imc_uri user, room; + int params = 0; + + memset(&user, '\0', sizeof(user)); + memset(&room, '\0', sizeof(room)); + + if (cmd->param[0].s) { + params++; + if (cmd->param[1].s) { + params++; + if (cmd->param[2].s) { + params++; + } + } + } + + switch(params) { + case 0: + LM_INFO("Modify command with missing argument from [%.*s]\n", STR_FMT(&src->uri)); + goto error; + case 1: + LM_INFO("Modify command with missing argument role\n"); + goto error; + case 2: + case 3: + /* identify the role */ + if(cmd->param[1].len==(sizeof(IMC_MEMBER_OWNER_STR)-1) + && !strncasecmp(cmd->param[1].s, IMC_MEMBER_OWNER_STR, cmd->param[1].len)) + { + flag_member |= IMC_MEMBER_OWNER; + } else if(cmd->param[1].len==(sizeof(IMC_MEMBER_ADMIN_STR)-1) + && !strncasecmp(cmd->param[1].s, IMC_MEMBER_ADMIN_STR, cmd->param[1].len)) + { + flag_member |= IMC_MEMBER_ADMIN; + } else if(cmd->param[1].len==(sizeof(IMC_MEMBER_INVITED_STR)-1) + && !strncasecmp(cmd->param[1].s, IMC_MEMBER_INVITED_STR, cmd->param[1].len)) + { + flag_member |= IMC_MEMBER_INVITED; + } else { + LM_INFO("Modify command with unknown argument role [%.*s]\n", STR_FMT(&cmd->param[1])); + goto error; + } + + if (build_imc_uri(&room, cmd->param[3].s ? cmd->param[3] : dst->parsed.user, &dst->parsed)) + goto error; + break; + default: + LM_ERR("Invalid number of parameters %d\n", params); + goto error; + } + + if (build_imc_uri(&user, cmd->param[0], &dst->parsed)) + goto error; + + rm = imc_get_room(&room.parsed.user, &room.parsed.host); + if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) { + LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri)); + goto error; + } + member = imc_get_member(rm, &src->parsed.user, &src->parsed.host); + + if (member == NULL) { + LM_ERR("User [%.*s] is not member of room [%.*s]!\n", STR_FMT(&src->uri), STR_FMT(&room.uri)); + goto error; + } + + if (!(member->flags & IMC_MEMBER_OWNER) && + !(member->flags & IMC_MEMBER_ADMIN)) { + LM_ERR("User [%.*s] has no right to modify others role!\n", STR_FMT(&member->uri)); + imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_modify_reject); + goto done; + } + + member = imc_get_member(rm, &user.parsed.user, &user.parsed.host); + if (member == NULL) { + LM_ERR("User [%.*s] is not member of room [%.*s]!\n", STR_FMT(&member->uri), STR_FMT(&room.uri)); + goto error; + } + + rv = imc_modify_member(rm, &src->parsed.user, &src->parsed.host, flag_member); + + if (rv == -1) { + LM_ERR("Failed to modify member [%.*s] role [%.*s]\n", STR_FMT(&member->uri), STR_FMT(&cmd->param[1])); + goto error; + } + + body.s = imc_body_buf; + body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(member->uri))); + + if (body.len < 0) { + LM_ERR("Error while building response\n"); + goto error; + } + + if (body.len > 0) + imc_room_broadcast(rm, build_headers(msg), &body); + + if (body.len >= sizeof(imc_body_buf)) + LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body)); + +done: + rv = 0; +error: + if (user.uri.s != NULL) pkg_free(user.uri.s); + if (room.uri.s != NULL) pkg_free(room.uri.s); + if (rm != NULL) imc_release_room(rm); + return rv; +} int imc_room_broadcast(imc_room_p room, str *ctype, str *body) { diff --git a/src/modules/imc/imc_cmd.h b/src/modules/imc/imc_cmd.h index 64f444d715c..b35dfe7dcf6 100644 --- a/src/modules/imc/imc_cmd.h +++ b/src/modules/imc/imc_cmd.h @@ -48,6 +48,7 @@ #define IMC_CMDID_UNKNOWN 11 #define IMC_CMDID_ADD 12 #define IMC_CMDID_ROOMS 13 +#define IMC_CMDID_MODIFY 14 #define IMC_CMD_CREATE "create" @@ -61,10 +62,14 @@ #define IMC_CMD_MEMBERS "members" #define IMC_CMD_ADD "add" #define IMC_CMD_ROOMS "rooms" +#define IMC_CMD_MODIFY "modify" #define IMC_ROOM_PRIVATE "private" #define IMC_ROOM_PRIVATE_LEN (sizeof(IMC_ROOM_PRIVATE)-1) +#define IMC_ROOM_ROLE "role" +#define IMC_ROLE_LEN (sizeof(IMC_ROOM_ROLE)-1) + #define IMC_HELP_MSG "\r\n"IMC_CMD_START_STR IMC_CMD_CREATE" - \ create new conference room\r\n\ "IMC_CMD_START_STR IMC_CMD_JOIN" [] - \ @@ -73,6 +78,8 @@ join the conference room\r\n\ invite a user to join a conference room\r\n\ "IMC_CMD_START_STR IMC_CMD_ADD" [] - \ add a user to a conference room\r\n\ +"IMC_CMD_START_STR IMC_CMD_MODIFY" [] - \ +modify user role in a conference room\r\n\ "IMC_CMD_START_STR IMC_CMD_ACCEPT" - \ accept invitation to join a conference room\r\n\ "IMC_CMD_START_STR IMC_CMD_REJECT" - \ @@ -129,5 +136,7 @@ int imc_handle_help(struct sip_msg* msg, imc_cmd_t *cmd, struct imc_uri *src, struct imc_uri *dst); int imc_handle_message(struct sip_msg* msg, str *msgbody, struct imc_uri *src, struct imc_uri *dst); +int imc_handle_modify(struct sip_msg* msg, imc_cmd_t *cmd, + struct imc_uri *src, struct imc_uri *dst); #endif diff --git a/src/modules/imc/imc_mng.c b/src/modules/imc/imc_mng.c index dc65d060888..7740a74b681 100644 --- a/src/modules/imc/imc_mng.c +++ b/src/modules/imc/imc_mng.c @@ -344,8 +344,38 @@ imc_member_p imc_add_member(imc_room_p room, str* user, str* domain, int flags) return imp; } +imc_member_p imc_modify_member(imc_room_p room, str* user, str* domain, int flags) { + imc_member_p imp = NULL; + unsigned int hashid; + + if(room==NULL || user == NULL || user->s==NULL || user->len<=0 + || domain == NULL || domain->s==NULL || domain->len<=0) + { + LM_ERR("invalid parameters\n"); + return NULL; + } + + hashid = core_case_hash(user, domain, 0); + imp = room->members; + while(imp) + { + if(imp->hashid==hashid && imp->user.len==user->len + && imp->domain.len==domain->len + && !strncasecmp(imp->user.s, user->s, user->len) + && !strncasecmp(imp->domain.s, domain->s, domain->len)) + { + LM_DBG("member found. modify flags\n"); + imp->flags = flags; + return 0; + } + imp = imp->next; + } + + return -1; +} + /** - * search memeber + * search member */ imc_member_p imc_get_member(imc_room_p room, str* user, str* domain) { @@ -374,7 +404,7 @@ imc_member_p imc_get_member(imc_room_p room, str* user, str* domain) imp = imp->next; } - return NULL; + return 0; } /** diff --git a/src/modules/imc/imc_mng.h b/src/modules/imc/imc_mng.h index 206351e3cd3..866a1fa56dd 100644 --- a/src/modules/imc/imc_mng.h +++ b/src/modules/imc/imc_mng.h @@ -38,6 +38,10 @@ #define IMC_MEMBER_DELETED (1<<3) #define IMC_MEMBER_SKIP (1<<4) +#define IMC_MEMBER_OWNER_STR "owner" +#define IMC_MEMBER_ADMIN_STR "admin" +#define IMC_MEMBER_INVITED_STR "member" + typedef struct _imc_member { unsigned int hashid; @@ -81,6 +85,7 @@ typedef struct _imc_hentry } imc_hentry_t, *imc_hentry_p; imc_member_p imc_add_member(imc_room_p room, str* user, str* domain, int flags); +imc_member_p imc_modify_member(imc_room_p room, str* user, str* domain, int flags); imc_member_p imc_get_member(imc_room_p room, str* user, str* domain); int imc_del_member(imc_room_p room, str* user, str* domain); From a6ed37c39c814a18da35e6d14679b5dc9e09ac26 Mon Sep 17 00:00:00 2001 From: Joey Golan Date: Mon, 28 Nov 2022 17:07:01 +0200 Subject: [PATCH 2/8] imc: call handle_modify --- src/modules/imc/imc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/modules/imc/imc.c b/src/modules/imc/imc.c index 9638b5b06f8..f9f931d7b55 100644 --- a/src/modules/imc/imc.c +++ b/src/modules/imc/imc.c @@ -590,6 +590,14 @@ static int ki_imc_manager(struct sip_msg* msg) goto error; } break; + case IMC_CMDID_MODIFY: + if(imc_handle_modify(msg, &cmd, &src, &dst)<0) + { + LM_ERR("failed to handle 'modify'\n"); + ret = -120; + goto error; + } + break; case IMC_CMDID_HELP: if(imc_handle_help(msg, &cmd, &src, &dst)<0) { From b5e8711ce397b9d32214bddfaeecc8451b9d6e6e Mon Sep 17 00:00:00 2001 From: Joey Golan Date: Fri, 2 Dec 2022 09:02:42 +0200 Subject: [PATCH 3/8] imc: db_mode support Support db_mode. if db_mode is 2, synch all operations to DB, otherwise use only memory. --- src/modules/imc/doc/imc_admin.xml | 21 ++ src/modules/imc/imc.c | 311 ++++++------------------- src/modules/imc/imc.h | 1 + src/modules/imc/imc_cmd.c | 122 +++++++++- src/modules/imc/imc_mng.c | 375 +++++++++++++++++++++++++++++- src/modules/imc/imc_mng.h | 27 ++- 6 files changed, 596 insertions(+), 261 deletions(-) diff --git a/src/modules/imc/doc/imc_admin.xml b/src/modules/imc/doc/imc_admin.xml index 6f7f5a02582..4b71c5f6806 100644 --- a/src/modules/imc/doc/imc_admin.xml +++ b/src/modules/imc/doc/imc_admin.xml @@ -88,6 +88,27 @@ ... modparam("imc", "db_url", "&exampledb;") ... + + + +
+ <varname>db_mode</varname>(integer) + + The module supports 2 modes of operation, high speed memory + based storage (mode 0), and database only (mode 2) where all + data is stored in a database, allowing scalability at the + expense of speed. Mode 1 is reserved. + + + Default value is 0 + + + + Set <varname>db_mode</varname> parameter + +... +modparam("imc", "db_mode", 2) +...
diff --git a/src/modules/imc/imc.c b/src/modules/imc/imc.c index f9f931d7b55..14989e67578 100644 --- a/src/modules/imc/imc.c +++ b/src/modules/imc/imc.c @@ -30,14 +30,12 @@ #include #include #include "../../lib/srdb1/db.h" -#include "../../lib/srdb1/db_res.h" #include "../../core/sr_module.h" #include "../../core/dprint.h" #include "../../core/ut.h" #include "../../core/timer.h" #include "../../core/str.h" #include "../../core/mem/shm_mem.h" -#include "../../lib/srdb1/db.h" #include "../../core/parser/parse_from.h" #include "../../core/parser/parse_content.h" #include "../../core/parser/contact/parse_contact.h" @@ -61,20 +59,22 @@ char hdr_buf[1024]; str all_hdrs; /** parameters */ - db1_con_t *imc_db = NULL; db_func_t imc_dbf; + static str db_url = str_init(DEFAULT_DB_URL); -str outbound_proxy = {NULL, 0}; +int db_mode = 0; -static str rooms_table = str_init("imc_rooms"); -static str members_table = str_init("imc_members"); +str rooms_table = str_init("imc_rooms"); +str members_table = str_init("imc_members"); -static str imc_col_username = str_init("username"); -static str imc_col_domain = str_init("domain"); -static str imc_col_flag = str_init("flag"); -static str imc_col_room = str_init("room"); -static str imc_col_name = str_init("name"); +str imc_col_username = str_init("username"); +str imc_col_domain = str_init("domain"); +str imc_col_flag = str_init("flag"); +str imc_col_room = str_init("room"); +str imc_col_name = str_init("name"); + +str outbound_proxy = {NULL, 0}; imc_hentry_p _imc_htable = NULL; int imc_hash_size = 4; @@ -108,11 +108,12 @@ static cmd_export_t cmds[]={ static param_export_t params[]={ {"db_url", PARAM_STR, &db_url}, + {"db_mode", INT_PARAM, &db_mode}, {"hash_size", INT_PARAM, &imc_hash_size}, {"imc_cmd_start_char", PARAM_STR, &imc_cmd_start_str}, {"rooms_table", PARAM_STR, &rooms_table}, {"members_table", PARAM_STR, &members_table}, - {"outbound_proxy", PARAM_STR, &outbound_proxy}, + {"outbound_proxy", PARAM_STR, &outbound_proxy}, {"extra_hdrs", PARAM_STR, &extra_hdrs}, {"create_on_join", INT_PARAM, &imc_create_on_join}, {"check_on_create", INT_PARAM, &imc_check_on_create}, @@ -146,183 +147,6 @@ struct module_exports exports= { destroy /* module destroy function */ }; -/** - * the initiating function - */ -int add_from_db(void) -{ - imc_member_p member = NULL; - int i, j, flag; - db_key_t mq_result_cols[4], mquery_cols[2]; - db_key_t rq_result_cols[4]; - db_val_t mquery_vals[2]; - db1_res_t *r_res= NULL; - db1_res_t *m_res= NULL; - db_row_t *m_row = NULL, *r_row = NULL; - db_val_t *m_row_vals, *r_row_vals = NULL; - str name, domain; - imc_room_p room = NULL; - int er_ret = -1; - - rq_result_cols[0] = &imc_col_name; - rq_result_cols[1] = &imc_col_domain; - rq_result_cols[2] = &imc_col_flag; - - mq_result_cols[0] = &imc_col_username; - mq_result_cols[1] = &imc_col_domain; - mq_result_cols[2] = &imc_col_flag; - - mquery_cols[0] = &imc_col_room; - mquery_vals[0].type = DB1_STR; - mquery_vals[0].nul = 0; - - if(imc_dbf.use_table(imc_db, &rooms_table)< 0) - { - LM_ERR("use_table failed\n"); - return -1; - } - - if(imc_dbf.query(imc_db,0, 0, 0, rq_result_cols,0, 3, 0,&r_res)< 0) - { - LM_ERR("failed to querry table\n"); - return -1; - } - if(r_res==NULL || r_res->n<=0) - { - LM_INFO("the query returned no result\n"); - if(r_res) imc_dbf.free_result(imc_db, r_res); - r_res = NULL; - return 0; - } - - LM_DBG("found %d rooms\n", r_res->n); - - for(i =0 ; i< r_res->n ; i++) - { - /*add rooms*/ - r_row = &r_res->rows[i]; - r_row_vals = ROW_VALUES(r_row); - - name.s = r_row_vals[0].val.str_val.s; - name.len = strlen(name.s); - - domain.s = r_row_vals[1].val.str_val.s; - domain.len = strlen(domain.s); - - flag = r_row_vals[2].val.int_val; - - room = imc_add_room(&name, &domain, flag); - if(room == NULL) - { - LM_ERR("failed to add room\n "); - goto error; - } - - /* add members */ - if(imc_dbf.use_table(imc_db, &members_table)< 0) - { - LM_ERR("use_table failed\n "); - goto error; - } - - mquery_vals[0].val.str_val= room->uri; - - if(imc_dbf.query(imc_db, mquery_cols, 0, mquery_vals, mq_result_cols, - 1, 3, 0, &m_res)< 0) - { - LM_ERR("failed to querry table\n"); - goto error; - } - - if(m_res==NULL || m_res->n<=0) - { - LM_INFO("the query returned no result\n"); - er_ret = 0; - goto error; /* each room must have at least one member*/ - } - for(j =0; j< m_res->n; j++) - { - m_row = &m_res->rows[j]; - m_row_vals = ROW_VALUES(m_row); - - name.s = m_row_vals[0].val.str_val.s; - name.len = strlen(name.s); - - domain.s = m_row_vals[1].val.str_val.s; - domain.len = strlen(domain.s); - - flag = m_row_vals[2].val.int_val; - - LM_DBG("adding memeber: [name]=%.*s [domain]=%.*s" - " in [room]= %.*s\n", STR_FMT(&name), STR_FMT(&domain), - STR_FMT(&room->uri)); - - member = imc_add_member(room, &name, &domain, flag); - if(member == NULL) - { - LM_ERR("failed to adding member\n "); - goto error; - } - imc_release_room(room); - } - - if(m_res) - { - imc_dbf.free_result(imc_db, m_res); - m_res = NULL; - } - } - - if(imc_dbf.use_table(imc_db, &members_table)< 0) - { - LM_ERR("use table failed\n "); - goto error; - } - - if(imc_dbf.delete(imc_db, 0, 0 , 0, 0) < 0) - { - LM_ERR("failed to delete information from db\n"); - goto error; - } - - if(imc_dbf.use_table(imc_db, &rooms_table)< 0) - { - LM_ERR("use table failed\n "); - goto error; - } - - if(imc_dbf.delete(imc_db, 0, 0 , 0, 0) < 0) - { - LM_ERR("failed to delete information from db\n"); - goto error; - } - - if(r_res) - { - imc_dbf.free_result(imc_db, r_res); - r_res = NULL; - } - - return 0; - -error: - if(r_res) - { - imc_dbf.free_result(imc_db, r_res); - r_res = NULL; - } - if(m_res) - { - imc_dbf.free_result(imc_db, m_res); - m_res = NULL; - } - if(room) - imc_release_room(room); - return er_ret; - -} - - static int mod_init(void) { #ifdef STATISTICS @@ -333,22 +157,19 @@ static int mod_init(void) } #endif - if(imc_rpc_init()<0) - { + if(imc_rpc_init()<0) { LM_ERR("failed to register RPC commands\n"); return -1; } - if(imc_hash_size <= 0) - { + if(imc_hash_size <= 0) { LM_ERR("invalid hash size\n"); return -1; } imc_hash_size = 1 << imc_hash_size; - if(imc_htable_init() < 0) - { + if(imc_htable_init() < 0) { LM_ERR("initializing hash table\n"); return -1; } @@ -365,29 +186,34 @@ static int mod_init(void) all_hdrs.len = extra_hdrs.len + imc_hdrs.len; } else { all_hdrs = imc_hdrs; - } + } - /* binding to mysql module */ - LM_DBG("db_url=%s/%d/%p\n", ZSW(db_url.s), db_url.len, db_url.s); + if(db_mode == 2) { + /* binding to mysql module */ + LM_DBG("db_url=%s/%d/%p\n", ZSW(db_url.s), db_url.len, db_url.s); - if (db_bind_mod(&db_url, &imc_dbf)) - { - LM_DBG("database module not found\n"); - return -1; - } + if (db_bind_mod(&db_url, &imc_dbf)) { + LM_DBG("database module not found\n"); + return -1; + } - imc_db = imc_dbf.init(&db_url); - if (!imc_db) - { - LM_ERR("failed to connect to the database\n"); - return -1; - } - /* read the informations stored in db */ - if(add_from_db() <0) - { - LM_ERR("failed to get information from db\n"); - return -1; - } + imc_db = imc_dbf.init(&db_url); + if (!imc_db) { + LM_ERR("failed to connect to the database\n"); + return -1; + } + + /* read the informations stored in db */ + if (load_rooms_from_db() < 0) { + LM_ERR("failed to get information from db\n"); + return -1; + } + + if(imc_db) + imc_dbf.close(imc_db); + + imc_db = NULL; + } /* load TM API */ if (load_tm_api(&tmb)!=0) { @@ -395,11 +221,7 @@ static int mod_init(void) return -1; } - imc_cmd_start_char = imc_cmd_start_str.s[0]; - - if(imc_db) - imc_dbf.close(imc_db); - imc_db = NULL; + imc_cmd_start_char = imc_cmd_start_str.s[0]; return 0; } @@ -412,32 +234,30 @@ static int child_init(int rank) if (rank==PROC_INIT || rank==PROC_TCP_MAIN) return 0; /* do nothing for the main process */ - if (imc_dbf.init==0) - { - LM_ERR("database not bound\n"); - return -1; - } - imc_db = imc_dbf.init(&db_url); - if (!imc_db) - { - LM_ERR("child %d: Error while connecting database\n", rank); - return -1; - } - else - { - if (imc_dbf.use_table(imc_db, &rooms_table) < 0) - { - LM_ERR("child %d: Error in use_table '%.*s'\n", rank, STR_FMT(&rooms_table)); + if (db_mode == 2) { + if (imc_dbf.init == 0) { + LM_ERR("database not bound\n"); return -1; } - if (imc_dbf.use_table(imc_db, &members_table) < 0) - { - LM_ERR("child %d: Error in use_table '%.*s'\n", rank, STR_FMT(&members_table)); + + imc_db = imc_dbf.init(&db_url); + if (!imc_db) { + LM_ERR("child %d: Error while connecting database\n", rank); return -1; } + else { + if (imc_dbf.use_table(imc_db, &rooms_table) < 0) { + LM_ERR("child %d: Error in use_table '%.*s'\n", rank, STR_FMT(&rooms_table)); + return -1; + } + if (imc_dbf.use_table(imc_db, &members_table) < 0) { + LM_ERR("child %d: Error in use_table '%.*s'\n", rank, STR_FMT(&members_table)); + return -1; + } - LM_DBG("child %d: Database connection opened successfully\n", rank); - } + LM_DBG("child %d: Database connection opened successfully\n", rank); + } + } return 0; } @@ -451,8 +271,7 @@ static int ki_imc_manager(struct sip_msg* msg) int ret = -1; body.s = get_body( msg ); - if (body.s==0) - { + if (body.s==0) { LM_ERR("cannot extract body from msg\n"); goto error; } @@ -508,7 +327,7 @@ static int ki_imc_manager(struct sip_msg* msg) LM_ERR("failed to handle 'create'\n"); ret = -30; goto error; - } + } break; case IMC_CMDID_JOIN: if(imc_handle_join(msg, &cmd, &src, &dst)<0) @@ -532,7 +351,7 @@ static int ki_imc_manager(struct sip_msg* msg) LM_ERR("failed to handle 'add'\n"); ret = -50; goto error; - } + } break; case IMC_CMDID_ACCEPT: if(imc_handle_accept(msg, &cmd, &src, &dst)<0) @@ -556,7 +375,7 @@ static int ki_imc_manager(struct sip_msg* msg) LM_ERR("failed to handle 'remove'\n"); ret = -80; goto error; - } + } break; case IMC_CMDID_LEAVE: if(imc_handle_leave(msg, &cmd, &src, &dst)<0) diff --git a/src/modules/imc/imc.h b/src/modules/imc/imc.h index b57cb5c3ab7..204bb5f78e5 100644 --- a/src/modules/imc/imc.h +++ b/src/modules/imc/imc.h @@ -33,6 +33,7 @@ extern str imc_cmd_start_str; extern char imc_cmd_start_char; extern struct tm_binds tmb; extern str outbound_proxy; +extern int db_mode; extern str all_hdrs; extern str extra_hdrs; extern int imc_create_on_join; diff --git a/src/modules/imc/imc_cmd.c b/src/modules/imc/imc_cmd.c index 4f8a1501425..adff66e24f8 100644 --- a/src/modules/imc/imc_cmd.c +++ b/src/modules/imc/imc_cmd.c @@ -62,6 +62,7 @@ static str msg_join_attempt_bcast = STR_STATIC_INIT(PREFIX "%.*s attempted to jo static str msg_join_attempt_ucast = STR_STATIC_INIT(PREFIX "Private rooms are by invitation only. Room owners have been notified."); static str msg_invite = STR_STATIC_INIT(PREFIX "%.*s invites you to join the room (send '%.*saccept' or '%.*sreject')"); static str msg_add_reject = STR_STATIC_INIT(PREFIX "You don't have the permmission to add members to this room"); +static str msg_user_modified = STR_STATIC_INIT(PREFIX "%.*s is now %.*s"); static str msg_modify_reject = STR_STATIC_INIT(PREFIX "You don't have the permmission to modify members in this room"); #if 0 static str msg_rejected = STR_STATIC_INIT(PREFIX "%.*s has rejected invitation"); @@ -415,6 +416,14 @@ int imc_handle_create(struct sip_msg* msg, imc_cmd_t *cmd, } LM_DBG("Added room [%.*s]\n", STR_FMT(&rm->uri)); + if (db_mode == 2) { + if (add_room_to_db(rm) < 0) { + LM_ERR("failed to add room to db\n"); + goto error; + } + LM_DBG("Add room [%.*s] to db\n", STR_FMT(&rm->uri)); + } + flag_member |= IMC_MEMBER_OWNER; /* adding the owner as the first member*/ member = imc_add_member(rm, &src->parsed.user, &src->parsed.host, flag_member); @@ -425,6 +434,13 @@ int imc_handle_create(struct sip_msg* msg, imc_cmd_t *cmd, LM_DBG("Added [%.*s] as the first member in room [%.*s]\n", STR_FMT(&member->uri), STR_FMT(&rm->uri)); + if (db_mode == 2) { + if (add_room_member_to_db(member, rm, flag_member) < 0) { + LM_ERR("failed to add room member [%.*s] to db\n", STR_FMT(&member->uri)); + goto error; + } + } + imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_room_created); goto done; } @@ -457,6 +473,13 @@ int imc_handle_create(struct sip_msg* msg, imc_cmd_t *cmd, LM_DBG("Added [%.*s] as member to room [%.*s]\n", STR_FMT(&member->uri), STR_FMT(&rm->uri)); + if (db_mode == 2) { + if (add_room_member_to_db(member, rm, flag_member) < 0) { + LM_ERR("failed to add room member [%.*s] to db\n", STR_FMT(&member->uri)); + goto error; + } + } + body.s = imc_body_buf; body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(member->uri))); @@ -501,6 +524,7 @@ int imc_handle_join(struct sip_msg* msg, imc_cmd_t *cmd, goto error; rm = imc_get_room(&room.parsed.user, &room.parsed.host); + if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) { LM_DBG("Room [%.*s] not found\n", STR_FMT(&room.uri)); @@ -516,12 +540,28 @@ int imc_handle_join(struct sip_msg* msg, imc_cmd_t *cmd, goto error; } LM_DBG("Created a new room [%.*s]\n", STR_FMT(&rm->uri)); + + if (db_mode == 2) { + if (add_room_to_db(rm) < 0) { + LM_ERR("failed to add room to db\n"); + goto error; + } + LM_DBG("Add room [%.*s] to db\n", STR_FMT(&rm->uri)); + } + flag_member |= IMC_MEMBER_OWNER; member = imc_add_member(rm, &src->parsed.user, &src->parsed.host, flag_member); if (member == NULL) { LM_ERR("Failed to add new member [%.*s]\n", STR_FMT(&src->uri)); goto error; } + + if (db_mode == 2) { + if (add_room_member_to_db(member, rm, flag_member) < 0) { + LM_ERR("failed to add room member [%.*s] to db\n", STR_FMT(&member->uri)); + goto error; + } + } /* send info message */ imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_room_created); goto done; @@ -545,6 +585,13 @@ int imc_handle_join(struct sip_msg* msg, imc_cmd_t *cmd, goto error; } + if (db_mode == 2) { + if (add_room_member_to_db(member, rm, flag_member) < 0) { + LM_ERR("failed to add room member [%.*s] to db\n", STR_FMT(&member->uri)); + goto error; + } + } + body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(src->uri))); } else { @@ -638,6 +685,13 @@ int imc_handle_invite(struct sip_msg* msg, imc_cmd_t *cmd, goto error; } + if (db_mode == 2) { + if (add_room_member_to_db(member, rm, flag_member) < 0) { + LM_ERR("failed to add room member [%.*s] to db\n", STR_FMT(&member->uri)); + goto error; + } + } + body.s = imc_body_buf; body.len = snprintf(body.s, sizeof(imc_body_buf), msg_invite.s, STR_FMT(format_uri(src->uri)), STR_FMT(&imc_cmd_start_str), STR_FMT(&imc_cmd_start_str)); @@ -743,6 +797,13 @@ int imc_handle_add(struct sip_msg* msg, imc_cmd_t *cmd, goto error; } + if (db_mode == 2) { + if (add_room_member_to_db(member, rm, 0) < 0) { + LM_ERR("failed to add room member [%.*s] to db\n", STR_FMT(&member->uri)); + goto error; + } + } + body.s = imc_body_buf; body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(member->uri))); @@ -796,6 +857,13 @@ int imc_handle_accept(struct sip_msg* msg, imc_cmd_t *cmd, member->flags &= ~IMC_MEMBER_INVITED; + if (db_mode == 2) { + if (modify_room_member_in_db(member, rm, member->flags) < 0) { + LM_ERR("failed to modify room member [%.*s] in db\n", STR_FMT(&member->uri)); + goto error; + } + } + body.s = imc_body_buf; body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(member->uri))); @@ -879,6 +947,13 @@ int imc_handle_remove(struct sip_msg* msg, imc_cmd_t *cmd, member->flags |= IMC_MEMBER_DELETED; imc_del_member(rm, &user.parsed.user, &user.parsed.host); + if (db_mode == 2) { + if (remove_room_member_from_db(member, rm) < 0) { + LM_ERR("failed to remove room member\n"); + goto error; + } + } + body.s = imc_body_buf; body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_left.s, STR_FMT(format_uri(member->uri))); @@ -940,6 +1015,13 @@ int imc_handle_reject(struct sip_msg* msg, imc_cmd_t *cmd, imc_del_member(rm, &src->parsed.user, &src->parsed.host); + if (db_mode == 2) { + if( remove_room_member_from_db(member, rm) < 0) { + LM_ERR("failed to remove room member\n"); + goto error; + } + } + rv = 0; error: if (room.uri.s != NULL) pkg_free(room.uri.s); @@ -1146,6 +1228,13 @@ int imc_handle_leave(struct sip_msg* msg, imc_cmd_t *cmd, member->flags |= IMC_MEMBER_DELETED; imc_del_member(rm, &src->parsed.user, &src->parsed.host); + if (db_mode == 2) { + if (remove_room_member_from_db(member, rm) < 0) { + LM_ERR("failed to remove room member\n"); + goto error; + } + } + done: rv = 0; error: @@ -1189,14 +1278,22 @@ int imc_handle_destroy(struct sip_msg* msg, imc_cmd_t *cmd, rm->flags |= IMC_ROOM_DELETED; /* braodcast message */ - imc_room_broadcast(rm, build_headers(msg), &msg_room_destroyed); + imc_room_broadcast(rm, build_headers(msg), &msg_room_destroyed); + + if (db_mode == 2) { + LM_DBG("Deleting room [%.*s] from db\n", STR_FMT(&room.uri)); + if (remove_room_from_db(rm) < 0) { + LM_ERR("Failed to delete room [%.*s] from db\n", STR_FMT(&room.uri)); + goto error; + } + } + + LM_DBG("Deleting room [%.*s] from htable\n", STR_FMT(&room.uri)); + imc_del_room(&room.parsed.user, &room.parsed.host); imc_release_room(rm); rm = NULL; - LM_DBG("Deleting room [%.*s]\n", STR_FMT(&room.uri)); - imc_del_room(&room.parsed.user, &room.parsed.host); - rv = 0; error: if (room.uri.s != NULL) pkg_free(room.uri.s); @@ -1341,10 +1438,10 @@ int imc_handle_modify(struct sip_msg* msg, imc_cmd_t *cmd, && !strncasecmp(cmd->param[1].s, IMC_MEMBER_ADMIN_STR, cmd->param[1].len)) { flag_member |= IMC_MEMBER_ADMIN; - } else if(cmd->param[1].len==(sizeof(IMC_MEMBER_INVITED_STR)-1) - && !strncasecmp(cmd->param[1].s, IMC_MEMBER_INVITED_STR, cmd->param[1].len)) + } else if(cmd->param[1].len==(sizeof(IMC_MEMBER_STR)-1) + && !strncasecmp(cmd->param[1].s, IMC_MEMBER_STR, cmd->param[1].len)) { - flag_member |= IMC_MEMBER_INVITED; + flag_member = 0; } else { LM_INFO("Modify command with unknown argument role [%.*s]\n", STR_FMT(&cmd->param[1])); goto error; @@ -1386,15 +1483,22 @@ int imc_handle_modify(struct sip_msg* msg, imc_cmd_t *cmd, goto error; } - rv = imc_modify_member(rm, &src->parsed.user, &src->parsed.host, flag_member); + rv = imc_modify_member(rm, &member->user, &member->domain, flag_member); if (rv == -1) { LM_ERR("Failed to modify member [%.*s] role [%.*s]\n", STR_FMT(&member->uri), STR_FMT(&cmd->param[1])); goto error; } + if (db_mode == 2) { + if (modify_room_member_in_db(member, rm, flag_member) < 0){ + LM_ERR("Failed to modify member [%.*s] role [%.*s] in db\n", STR_FMT(&member->uri), STR_FMT(&cmd->param[1])); + goto error; + } + } + body.s = imc_body_buf; - body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(member->uri))); + body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_modified.s, STR_FMT(&member->uri), STR_FMT(&cmd->param[1])); if (body.len < 0) { LM_ERR("Error while building response\n"); diff --git a/src/modules/imc/imc_mng.c b/src/modules/imc/imc_mng.c index 7740a74b681..73c2d68cafb 100644 --- a/src/modules/imc/imc_mng.c +++ b/src/modules/imc/imc_mng.c @@ -26,12 +26,15 @@ #include #include +#include "../../lib/srdb1/db_res.h" #include "../../core/mem/mem.h" #include "../../core/mem/shm_mem.h" #include "../../core/dprint.h" #include "../../core/hashes.h" #include "imc_mng.h" +#include "imc.h" + /* imc hash table */ extern imc_hentry_p _imc_htable; extern int imc_hash_size; @@ -65,7 +68,7 @@ int imc_htable_init(void) goto error; } } - + return 0; error: @@ -106,6 +109,370 @@ int imc_htable_destroy(void) return 0; } +int load_rooms_from_db() +{ + imc_member_p member = NULL; + int i, j, flag; + db_key_t mq_result_cols[4], mquery_cols[2]; + db_key_t rq_result_cols[4]; + db_val_t mquery_vals[2]; + db1_res_t *r_res= NULL; + db1_res_t *m_res= NULL; + db_row_t *m_row = NULL, *r_row = NULL; + db_val_t *m_row_vals, *r_row_vals = NULL; + str name, domain; + imc_room_p room = NULL; + int er_ret = -1; + + rq_result_cols[0] = &imc_col_name; + rq_result_cols[1] = &imc_col_domain; + rq_result_cols[2] = &imc_col_flag; + + mq_result_cols[0] = &imc_col_username; + mq_result_cols[1] = &imc_col_domain; + mq_result_cols[2] = &imc_col_flag; + + mquery_cols[0] = &imc_col_room; + mquery_vals[0].type = DB1_STR; + mquery_vals[0].nul = 0; + + if(imc_dbf.use_table(imc_db, &rooms_table)< 0) + { + LM_ERR("use_table failed\n"); + return -1; + } + + if(imc_dbf.query(imc_db,0, 0, 0, rq_result_cols,0, 3, 0,&r_res)< 0) + { + LM_ERR("failed to query table\n"); + return -1; + } + if(r_res==NULL || r_res->n<=0) + { + LM_INFO("the query returned no result\n"); + if(r_res) imc_dbf.free_result(imc_db, r_res); + r_res = NULL; + return 0; + } + + LM_DBG("found %d rooms\n", r_res->n); + + for(i =0 ; i< r_res->n ; i++) + { + /*add rooms*/ + r_row = &r_res->rows[i]; + r_row_vals = ROW_VALUES(r_row); + + name.s = r_row_vals[0].val.str_val.s; + name.len = strlen(name.s); + + domain.s = r_row_vals[1].val.str_val.s; + domain.len = strlen(domain.s); + + flag = r_row_vals[2].val.int_val; + + room = imc_add_room(&name, &domain, flag); + if(room == NULL) + { + LM_ERR("failed to add room\n "); + goto error; + } + + /* add members */ + if(imc_dbf.use_table(imc_db, &members_table)< 0) + { + LM_ERR("use_table failed\n "); + goto error; + } + + mquery_vals[0].val.str_val= room->uri; + + if(imc_dbf.query(imc_db, mquery_cols, 0, mquery_vals, mq_result_cols, + 1, 3, 0, &m_res)< 0) + { + LM_ERR("failed to query table\n"); + goto error; + } + + if(m_res==NULL || m_res->n<=0) + { + LM_INFO("the query returned no result\n"); + er_ret = 0; + goto error; /* each room must have at least one member*/ + } + for(j =0; j< m_res->n; j++) + { + m_row = &m_res->rows[j]; + m_row_vals = ROW_VALUES(m_row); + + name.s = m_row_vals[0].val.str_val.s; + name.len = strlen(name.s); + + domain.s = m_row_vals[1].val.str_val.s; + domain.len = strlen(domain.s); + + flag = m_row_vals[2].val.int_val; + + LM_DBG("adding memeber: [name]=%.*s [domain]=%.*s" + " in [room]= %.*s\n", STR_FMT(&name), STR_FMT(&domain), + STR_FMT(&room->uri)); + + member = imc_add_member(room, &name, &domain, flag); + if(member == NULL) + { + LM_ERR("failed to adding member\n "); + goto error; + } + imc_release_room(room); + } + + if(m_res) + { + imc_dbf.free_result(imc_db, m_res); + m_res = NULL; + } + } + + return 0; + +error: + if(r_res) + { + imc_dbf.free_result(imc_db, r_res); + r_res = NULL; + } + if(m_res) + { + imc_dbf.free_result(imc_db, m_res); + m_res = NULL; + } + if(room) + imc_release_room(room); + return er_ret; +} + +int add_room_to_db(imc_room_p room) +{ + db_key_t rkeys[3]; + db_val_t rvalues[3]; + + rkeys[0] = &imc_col_name; + rkeys[1] = &imc_col_domain; + rkeys[2] = &imc_col_flag; + + rvalues[0].type = DB1_STR; + rvalues[0].nul = 0; + rvalues[0].val.str_val.s = room->name.s; + rvalues[0].val.str_val.len = room->name.len; + + rvalues[1].type = DB1_STR; + rvalues[1].nul = 0; + rvalues[1].val.str_val.s = room->domain.s; + rvalues[1].val.str_val.len = room->domain.len; + + rvalues[2].type = DB1_INT; + rvalues[2].nul = 0; + rvalues[2].val.int_val = 0; + + if(imc_dbf.use_table(imc_db, &rooms_table)< 0) + { + LM_ERR("use_table failed on rooms_table\n"); + return -1; + } + + if(imc_dbf.insert(imc_db, rkeys, rvalues, 3)< 0) + { + LM_ERR("failed to insert room\n"); + return -1; + } + + return 0; +} + +int remove_room_from_db(imc_room_p room) +{ + db_key_t rkeys[2]; + db_val_t rvalues[2]; + db_key_t mkeys[1]; + db_val_t mvalues[1]; + + mkeys[0] = &imc_col_room; + + mvalues[0].type = DB1_STR; + mvalues[0].nul = 0; + mvalues[0].val.str_val.s = room->uri.s; + mvalues[0].val.str_val.len = room->uri.len; + + if(imc_dbf.use_table(imc_db, &members_table)< 0) + { + LM_ERR("use table failed\n "); + return -1; + } + + if(imc_dbf.delete(imc_db, mkeys, 0 , mvalues, 1) < 0) + { + LM_ERR("failed to delete room member from db\n"); + return -1; + } + + rkeys[0] = &imc_col_name; + rkeys[1] = &imc_col_domain; + + rvalues[0].type = DB1_STR; + rvalues[0].nul = 0; + rvalues[0].val.str_val.s = room->name.s; + rvalues[0].val.str_val.len = room->name.len; + + rvalues[1].type = DB1_STR; + rvalues[1].nul = 0; + rvalues[1].val.str_val.s = room->domain.s; + rvalues[1].val.str_val.len = room->domain.len; + + if(imc_dbf.use_table(imc_db, &rooms_table)< 0) + { + LM_ERR("use_table failed on rooms_table\n"); + return -1; + } + + if(imc_dbf.delete(imc_db, rkeys, 0 , rvalues, 2) < 0) + { + LM_ERR("failed to delete room from db\n"); + return -1; + } + + return 0; +} + +int add_room_member_to_db(imc_member_p member, imc_room_p room, int flag) +{ + db_key_t mkeys[4]; + db_val_t mvalues[4]; + + mkeys[0] = &imc_col_username; + mkeys[1] = &imc_col_domain; + mkeys[2] = &imc_col_room; + mkeys[3] = &imc_col_flag; + + mvalues[0].type = DB1_STR; + mvalues[0].nul = 0; + mvalues[0].val.str_val.s = member->user.s; + mvalues[0].val.str_val.len = member->user.len; + + mvalues[1].type = DB1_STR; + mvalues[1].nul = 0; + mvalues[1].val.str_val.s = member->domain.s; + mvalues[1].val.str_val.len = member->domain.len; + + mvalues[2].type = DB1_STR; + mvalues[2].nul = 0; + mvalues[2].val.str_val.s = room->uri.s; + mvalues[2].val.str_val.len = room->uri.len; + + mvalues[3].type = DB1_INT; + mvalues[3].nul = 0; + mvalues[3].val.int_val = flag; + + if(imc_dbf.use_table(imc_db, &members_table)< 0) + { + LM_ERR("use_table failed on members_table\n"); + return -1; + } + + if(imc_dbf.insert(imc_db, mkeys, mvalues, 4)< 0) + { + LM_ERR("failed to insert member\n"); + return -1; + } + + return 0; +} + +int remove_room_member_from_db(imc_member_p member, imc_room_p room) { + db_key_t mkeys[3]; + db_val_t mvalues[3]; + + mkeys[0] = &imc_col_username; + mkeys[1] = &imc_col_domain; + mkeys[2] = &imc_col_room; + + mvalues[0].type = DB1_STR; + mvalues[0].nul = 0; + mvalues[0].val.str_val.s = member->user.s; + mvalues[0].val.str_val.len = member->user.len; + + mvalues[1].type = DB1_STR; + mvalues[1].nul = 0; + mvalues[1].val.str_val.s = member->domain.s; + mvalues[1].val.str_val.len = member->domain.len; + + mvalues[2].type = DB1_STR; + mvalues[2].nul = 0; + mvalues[2].val.str_val.s = room->uri.s; + mvalues[2].val.str_val.len = room->uri.len; + + if(imc_dbf.use_table(imc_db, &members_table)< 0) + { + LM_ERR("use table failed\n "); + return -1; + } + + if(imc_dbf.delete(imc_db, mkeys, 0 , mvalues, 3) < 0) + { + LM_ERR("failed to delete room member from db\n"); + return -1; + } + + return 0; +} + +int modify_room_member_in_db(imc_member_p member, imc_room_p room, int flag) +{ + db_key_t mkeys[3]; + db_val_t mvalues[3]; + + db_key_t mukeys[1]; + db_val_t muvalues[1]; + + mkeys[0] = &imc_col_username; + mkeys[1] = &imc_col_domain; + mkeys[2] = &imc_col_room; + + mvalues[0].type = DB1_STR; + mvalues[0].nul = 0; + mvalues[0].val.str_val.s = member->user.s; + mvalues[0].val.str_val.len = member->user.len; + + mvalues[1].type = DB1_STR; + mvalues[1].nul = 0; + mvalues[1].val.str_val.s = member->domain.s; + mvalues[1].val.str_val.len = member->domain.len; + + mvalues[2].type = DB1_STR; + mvalues[2].nul = 0; + mvalues[2].val.str_val.s = room->uri.s; + mvalues[2].val.str_val.len = room->uri.len; + + mukeys[0] = &imc_col_flag; + + muvalues[0].type = DB1_INT; + muvalues[0].nul = 0; + muvalues[0].val.int_val = flag; + + if(imc_dbf.use_table(imc_db, &members_table)< 0) + { + LM_ERR("use_table failed on members_table\n"); + return -1; + } + + if(imc_dbf.update(imc_db, mkeys, 0, mvalues, mukeys, muvalues, 3, 1)< 0) + { + LM_ERR("failed to update member\n"); + return -1; + } + + return 0; +} + /** * add room */ @@ -344,7 +711,7 @@ imc_member_p imc_add_member(imc_room_p room, str* user, str* domain, int flags) return imp; } -imc_member_p imc_modify_member(imc_room_p room, str* user, str* domain, int flags) { +int imc_modify_member(imc_room_p room, str* user, str* domain, int flags) { imc_member_p imp = NULL; unsigned int hashid; @@ -352,7 +719,7 @@ imc_member_p imc_modify_member(imc_room_p room, str* user, str* domain, int flag || domain == NULL || domain->s==NULL || domain->len<=0) { LM_ERR("invalid parameters\n"); - return NULL; + return -1; } hashid = core_case_hash(user, domain, 0); @@ -366,6 +733,8 @@ imc_member_p imc_modify_member(imc_room_p room, str* user, str* domain, int flag { LM_DBG("member found. modify flags\n"); imp->flags = flags; + imp->hashid = core_case_hash(&imp->user, &imp->domain, 0); + return 0; } imp = imp->next; diff --git a/src/modules/imc/imc_mng.h b/src/modules/imc/imc_mng.h index 866a1fa56dd..34ac74cd573 100644 --- a/src/modules/imc/imc_mng.h +++ b/src/modules/imc/imc_mng.h @@ -27,7 +27,7 @@ #define _IMC_MNG_H_ - +#include "../../lib/srdb1/db.h" #include "../../core/locking.h" #include "../../core/str.h" #include "../../core/parser/parse_from.h" @@ -40,7 +40,21 @@ #define IMC_MEMBER_OWNER_STR "owner" #define IMC_MEMBER_ADMIN_STR "admin" -#define IMC_MEMBER_INVITED_STR "member" +#define IMC_MEMBER_STR "member" + +extern db1_con_t *imc_db; +extern db_func_t imc_dbf; + +extern int db_mode; + +extern str rooms_table; +extern str members_table; + +extern str imc_col_username; +extern str imc_col_domain; +extern str imc_col_flag; +extern str imc_col_room; +extern str imc_col_name; typedef struct _imc_member { @@ -84,8 +98,15 @@ typedef struct _imc_hentry gen_lock_t lock; } imc_hentry_t, *imc_hentry_p; +int load_rooms_from_db(); +int add_room_to_db(imc_room_p room); +int remove_room_from_db(imc_room_p room); +int add_room_member_to_db(imc_member_p member, imc_room_p room, int flag); +int modify_room_member_in_db(imc_member_p member, imc_room_p room, int flag); +int remove_room_member_from_db(imc_member_p member, imc_room_p room); + imc_member_p imc_add_member(imc_room_p room, str* user, str* domain, int flags); -imc_member_p imc_modify_member(imc_room_p room, str* user, str* domain, int flags); +int imc_modify_member(imc_room_p room, str* user, str* domain, int flags); imc_member_p imc_get_member(imc_room_p room, str* user, str* domain); int imc_del_member(imc_room_p room, str* user, str* domain); From f9820f9d257b80a2a547c32e19204ee6b0ef6dd7 Mon Sep 17 00:00:00 2001 From: Joey Golan Date: Fri, 2 Dec 2022 09:17:16 +0200 Subject: [PATCH 4/8] imc: destroy db only if db_mode is not 0 --- src/modules/imc/imc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/imc/imc.c b/src/modules/imc/imc.c index 14989e67578..e9208731655 100644 --- a/src/modules/imc/imc.c +++ b/src/modules/imc/imc.c @@ -469,6 +469,9 @@ static void destroy(void) db_key_t rq_cols[4]; db_val_t rq_vals[4]; + if (db_mode == 0) + goto done; + if(imc_db==NULL) goto done; From 643a2d90ef62ad149e75cc705deb328895ffd736 Mon Sep 17 00:00:00 2001 From: Joey Golan Date: Fri, 2 Dec 2022 13:53:08 +0200 Subject: [PATCH 5/8] imc: propagate content-type header --- src/modules/imc/imc.c | 4 ++-- src/modules/imc/imc_cmd.c | 28 ++++++++++++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/modules/imc/imc.c b/src/modules/imc/imc.c index e9208731655..47216ba2cc1 100644 --- a/src/modules/imc/imc.c +++ b/src/modules/imc/imc.c @@ -54,7 +54,7 @@ MODULE_VERSION /** header variables */ -str imc_hdrs = str_init("Content-Type: text/plain\r\nSupported: kamailio/imc\r\n"); +str imc_hdrs = str_init("Supported: kamailio/imc\r\n"); char hdr_buf[1024]; str all_hdrs; @@ -435,7 +435,7 @@ static int ki_imc_manager(struct sip_msg* msg) } goto done; - } + } if(imc_handle_message(msg, &body, &src, &dst)<0) { diff --git a/src/modules/imc/imc_cmd.c b/src/modules/imc/imc_cmd.c index adff66e24f8..ea76e798162 100644 --- a/src/modules/imc/imc_cmd.c +++ b/src/modules/imc/imc_cmd.c @@ -91,29 +91,37 @@ static str *get_callid(struct sip_msg *msg) static str *build_headers(struct sip_msg *msg) { + static str ctname = STR_STATIC_INIT("Content-Type: "); static str name = STR_STATIC_INIT("In-Reply-To: "); + static str nl = STR_STATIC_INIT("\r\n"); static char buf[1024]; static str rv; str *callid; - if ((callid = get_callid(msg)) == NULL) - return &all_hdrs; - rv.s = buf; - rv.len = all_hdrs.len + name.len + callid->len; + rv.len = all_hdrs.len + ctname.len + msg->content_type->body.len; + + memcpy(buf, all_hdrs.s, all_hdrs.len); + memcpy(buf + all_hdrs.len, ctname.s, ctname.len); + memcpy(buf + all_hdrs.len + ctname.len, msg->content_type->body.s, msg->content_type->body.len); + + if ((callid = get_callid(msg)) == NULL) { + return &rv; + } + + rv.len += nl.len + name.len + callid->len; if (rv.len > sizeof(buf)) { LM_ERR("Header buffer too small for In-Reply-To header\n"); - return &all_hdrs; + return &rv; } - - memcpy(buf, all_hdrs.s, all_hdrs.len); - memcpy(buf + all_hdrs.len, name.s, name.len); - memcpy(buf + all_hdrs.len + name.len, callid->s, callid->len); + + memcpy(buf + all_hdrs.len + ctname.len + msg->content_type->body.len, nl.s, nl.len); + memcpy(buf + all_hdrs.len + ctname.len + msg->content_type->body.len + nl.len, name.s, name.len); + memcpy(buf + all_hdrs.len + ctname.len + msg->content_type->body.len + nl.len + name.len, callid->s, callid->len); return &rv; } - static str *format_uri(str uri) { static char buf[512]; From 5bfc028bb1149eadd9b687ce400423ddff690c64 Mon Sep 17 00:00:00 2001 From: Joey Golan Date: Sun, 28 May 2023 14:48:02 +0300 Subject: [PATCH 6/8] rtpengine: support receiving dtmf events from rtpengine and raise an event --- src/modules/rtpengine/doc/rtpengine.xml | 7 + src/modules/rtpengine/doc/rtpengine_admin.xml | 117 ++++- src/modules/rtpengine/rtpengine.c | 405 ++++++++++++++---- 3 files changed, 455 insertions(+), 74 deletions(-) diff --git a/src/modules/rtpengine/doc/rtpengine.xml b/src/modules/rtpengine/doc/rtpengine.xml index 5a6975cb71d..0a768117a91 100644 --- a/src/modules/rtpengine/doc/rtpengine.xml +++ b/src/modules/rtpengine/doc/rtpengine.xml @@ -73,6 +73,13 @@ rfuchs@sipwise.com + + Joey + Golan +
+ joeygo@gmail.com +
+
2003-2008 diff --git a/src/modules/rtpengine/doc/rtpengine_admin.xml b/src/modules/rtpengine/doc/rtpengine_admin.xml index 0cb881b4397..cc1dc3025bf 100644 --- a/src/modules/rtpengine/doc/rtpengine_admin.xml +++ b/src/modules/rtpengine/doc/rtpengine_admin.xml @@ -2188,6 +2188,78 @@ modparam("rtpengine", "mos_average_samples_B_pv", "$avp(mos_average_samples_B)") +
+ <varname>dtmf_event_callid</varname> (string) + + The name of a pseudovariable to be filled in with the callid of the triggered dtmf event. + + + By default, this parameter is not set. + + + Set <varname>dtmf_event_callid</varname> parameter + +... +modparam("rtpengine", "dtmf_event_callid", "$avp(dtmf_event_callid)") +... + + +
+ +
+ <varname>dtmf_event_source_tag</varname> (string) + + The name of a pseudovariable to be filled in with the source tag that triggered the dtmf event. + + + By default, this parameter is not set. + + + Set <varname>dtmf_event_source_tag</varname> parameter + +... +modparam("rtpengine", "dtmf_event_source_tag", "$avp(dtmf_event_source_tag)") +... + + +
+ +
+ <varname>dtmf_event_timestamp</varname> (string) + + The name of a pseudovariable to be filled in with the timestamp when the dtmf event was triggered. + + + By default, this parameter is not set. + + + Set <varname>dtmf_event_timestamp</varname> parameter + +... +modparam("rtpengine", "dtmf_event_timestamp", "$avp(dtmf_event_timestamp)") +... + + +
+ +
+ <varname>dtmf_event</varname> (string) + + The name of a pseudovariable to be filled in with the triggered DTMF value. + + + By default, this parameter is not set. + + + Set <varname>dtmf_event</varname> parameter + +... +modparam("rtpengine", "dtmf_event", "$avp(dtmf_event)") +... + + +
+
<varname>control_cmd_tos</varname> (integer) @@ -2253,7 +2325,28 @@ modparam("rtpengine", "wsapi", "lwsc")
- +
+ <varname>dtmf_events_sock</varname> (string) + + Definition of IPv4/IPv6 UDP socket used to receive dtmf events from RTPEngine. + + + DTMF events coming from RTPEngine will trigger rtpengine:dtmf-event route. + + + + Default value is NONE (disabled). + + + + Set <varname>dtmf_events_sock</varname> parameter + +... +modparam("rtpengine", "dtmf_events_sock", "127.0.0.1:2223") +... + + +
@@ -3485,4 +3578,26 @@ $ &kamcmd; rtpengine.get_hash_total +
+ Event routes +
+ + <function moreinfo="none">rtpengine:dtmf-event</function> + + + When defined, the module calls event_route[rtpengine:dtmf-event] + when a DTMF is received. + + +... +event_route[rtpengine:dtmf-event] { + xlog("L_INFO", "callid: $avp(dtmf_event_callid)\n"); + xlog("L_INFO", "source_tag: $avp(dtmf_event_source_tag)\n"); + xlog("L_INFO", "timestamp: $avp(dtmf_event_timestamp)\n"); + xlog("L_INFO", "dtmf: $avp(dtmf_event)\n"); +} +... + +
+
diff --git a/src/modules/rtpengine/rtpengine.c b/src/modules/rtpengine/rtpengine.c index 442df8ddd77..af9dc0ded7a 100644 --- a/src/modules/rtpengine/rtpengine.c +++ b/src/modules/rtpengine/rtpengine.c @@ -53,6 +53,7 @@ #include "../../core/data_lump.h" #include "../../core/data_lump_rpl.h" #include "../../core/error.h" +#include "../../core/fmsg.h" #include "../../core/forward.h" #include "../../core/mem/mem.h" #include "../../core/parser/parse_from.h" @@ -109,8 +110,9 @@ MODULE_VERSION #define DEFAULT_RTPP_SET_ID 0 -enum -{ +#define RTPENGINE_DTMF_EVENT_BUFFER 32768 + +enum { RPC_FOUND_ALL = 2, RPC_FOUND_ONE = 1, RPC_FOUND_NONE = 0, @@ -243,9 +245,9 @@ static int build_rtpp_socks(int lmode, int rtest); static char *send_rtpp_command(struct rtpp_node *, bencode_item_t *, int *); static int get_extra_id(struct sip_msg *msg, str *id_str); -static int rtpengine_set_store(modparam_t type, void *val); -static int rtpengine_add_rtpengine_set(char *rtp_proxies, unsigned int weight, - int disabled, unsigned int ticks); +static int rtpengine_set_store(modparam_t type, void * val); +static int rtpengine_set_dtmf_events_sock(modparam_t type, void * val); +static int rtpengine_add_rtpengine_set(char * rtp_proxies, unsigned int weight, int disabled, unsigned int ticks); static int mod_init(void); static int child_init(int); @@ -259,6 +261,9 @@ static int add_rtpp_node_info( void *ptrs, struct rtpp_node *crt_rtpp, struct rtpp_set *rtpp_list); static int rtpp_test_ping(struct rtpp_node *node); +static void rtpengine_dtmf_events_loop(int rank); +static int rtpengine_raise_dtmf_event(char* buffer, int len); + /* Pseudo-Variables */ static int pv_get_rtpestat_f(struct sip_msg *, pv_param_t *, pv_value_t *); static int set_rtp_inst_pvar(struct sip_msg *msg, const str *const uri); @@ -311,6 +316,18 @@ static pv_spec_t *read_sdp_pvar = NULL; static str media_duration_pvar_str = {NULL, 0}; static pv_spec_t *media_duration_pvar = NULL; +static str dtmf_event_callid_pvar_str = {NULL, 0}; +static pv_spec_t *dtmf_event_callid_pvar = NULL; + +static str dtmf_event_source_tag_pvar_str = {NULL, 0}; +static pv_spec_t *dtmf_event_source_tag_pvar = NULL; + +static str dtmf_event_timestamp_pvar_str = {NULL, 0}; +static pv_spec_t *dtmf_event_timestamp_pvar = NULL; + +static str dtmf_event_pvar_str = {NULL, 0}; +static pv_spec_t *dtmf_event_pvar = NULL; + #define RTPENGINE_SESS_LIMIT_MSG "Parallel session limit reached" #define RTPENGINE_SESS_LIMIT_MSG_LEN (sizeof(RTPENGINE_SESS_LIMIT_MSG) - 1) @@ -326,8 +343,11 @@ lwsc_api_t _rtpe_lwscb = {0}; static enum hash_algo_t hash_algo = RTP_HASH_CALLID; -typedef struct rtpp_set_link -{ +static str rtpengine_dtmf_event_sock; +static int rtpengine_dtmf_event_fd; +int dtmf_event_rt = -1; /* default disabled */ + +typedef struct rtpp_set_link { struct rtpp_set *rset; pv_spec_t *rpv; } rtpp_set_link_t; @@ -426,68 +446,58 @@ static pv_export_t mod_pvs[] = { {{0, 0}, 0, 0, 0, 0, 0, 0, 0}}; static param_export_t params[] = { - {"rtpengine_sock", PARAM_STRING | USE_FUNC_PARAM, - (void *)rtpengine_set_store}, - {"rtpengine_disable_tout", INT_PARAM, - &default_rtpengine_cfg.rtpengine_disable_tout}, - {"aggressive_redetection", INT_PARAM, - &default_rtpengine_cfg.aggressive_redetection}, - {"rtpengine_retr", INT_PARAM, &default_rtpengine_cfg.rtpengine_retr}, - {"queried_nodes_limit", INT_PARAM, - &default_rtpengine_cfg.queried_nodes_limit}, - {"rtpengine_tout_ms", INT_PARAM, - &default_rtpengine_cfg.rtpengine_tout_ms}, - {"rtpengine_allow_op", INT_PARAM, &rtpengine_allow_op}, - {"control_cmd_tos", INT_PARAM, &control_cmd_tos}, - {"db_url", PARAM_STR, &rtpp_db_url}, - {"table_name", PARAM_STR, &rtpp_table_name}, - {"setid_col", PARAM_STR, &rtpp_setid_col}, - {"url_col", PARAM_STR, &rtpp_url_col}, - {"weight_col", PARAM_STR, &rtpp_weight_col}, - {"disabled_col", PARAM_STR, &rtpp_disabled_col}, - {"extra_id_pv", PARAM_STR, &extra_id_pv_param}, - {"setid_avp", PARAM_STRING, &setid_avp_param}, - {"force_send_interface", PARAM_STRING, &force_send_ip_str}, - {"rtp_inst_pvar", PARAM_STR, &rtp_inst_pv_param}, - {"write_sdp_pv", PARAM_STR, &write_sdp_pvar_str}, - {"read_sdp_pv", PARAM_STR, &read_sdp_pvar_str}, - {"hash_table_tout", INT_PARAM, &hash_table_tout}, - {"hash_table_size", INT_PARAM, &hash_table_size}, - {"setid_default", INT_PARAM, &setid_default}, - {"media_duration", PARAM_STR, &media_duration_pvar_str}, - {"hash_algo", INT_PARAM, &hash_algo}, - - /* MOS stats output */ - /* global averages */ - {"mos_min_pv", PARAM_STR, &global_mos_stats.min.mos_param}, - {"mos_min_at_pv", PARAM_STR, &global_mos_stats.min.at_param}, - {"mos_min_packetloss_pv", PARAM_STR, - &global_mos_stats.min.packetloss_param}, - {"mos_min_jitter_pv", PARAM_STR, &global_mos_stats.min.jitter_param}, - {"mos_min_roundtrip_pv", PARAM_STR, - &global_mos_stats.min.roundtrip_param}, - {"mos_min_roundtrip_leg_pv", PARAM_STR, - &global_mos_stats.min.roundtrip_leg_param}, - {"mos_max_pv", PARAM_STR, &global_mos_stats.max.mos_param}, - {"mos_max_at_pv", PARAM_STR, &global_mos_stats.max.at_param}, - {"mos_max_packetloss_pv", PARAM_STR, - &global_mos_stats.max.packetloss_param}, - {"mos_max_jitter_pv", PARAM_STR, &global_mos_stats.max.jitter_param}, - {"mos_max_roundtrip_pv", PARAM_STR, - &global_mos_stats.max.roundtrip_param}, - {"mos_max_roundtrip_leg_pv", PARAM_STR, - &global_mos_stats.max.roundtrip_leg_param}, - {"mos_average_pv", PARAM_STR, &global_mos_stats.average.mos_param}, - {"mos_average_packetloss_pv", PARAM_STR, - &global_mos_stats.average.packetloss_param}, - {"mos_average_jitter_pv", PARAM_STR, - &global_mos_stats.average.jitter_param}, - {"mos_average_roundtrip_pv", PARAM_STR, - &global_mos_stats.average.roundtrip_param}, - {"mos_average_roundtrip_leg_pv", PARAM_STR, - &global_mos_stats.average.roundtrip_leg_param}, - {"mos_average_samples_pv", PARAM_STR, - &global_mos_stats.average.samples_param}, + {"rtpengine_sock", PARAM_STRING|USE_FUNC_PARAM, + (void*)rtpengine_set_store }, + {"rtpengine_disable_tout",INT_PARAM, &default_rtpengine_cfg.rtpengine_disable_tout }, + {"aggressive_redetection",INT_PARAM, &default_rtpengine_cfg.aggressive_redetection }, + {"rtpengine_retr", INT_PARAM, &default_rtpengine_cfg.rtpengine_retr }, + {"queried_nodes_limit", INT_PARAM, &default_rtpengine_cfg.queried_nodes_limit }, + {"rtpengine_tout_ms", INT_PARAM, &default_rtpengine_cfg.rtpengine_tout_ms }, + {"rtpengine_allow_op", INT_PARAM, &rtpengine_allow_op }, + {"control_cmd_tos", INT_PARAM, &control_cmd_tos }, + {"db_url", PARAM_STR, &rtpp_db_url }, + {"table_name", PARAM_STR, &rtpp_table_name }, + {"setid_col", PARAM_STR, &rtpp_setid_col }, + {"url_col", PARAM_STR, &rtpp_url_col }, + {"weight_col", PARAM_STR, &rtpp_weight_col }, + {"disabled_col", PARAM_STR, &rtpp_disabled_col }, + {"extra_id_pv", PARAM_STR, &extra_id_pv_param }, + {"setid_avp", PARAM_STRING, &setid_avp_param }, + {"force_send_interface", PARAM_STRING, &force_send_ip_str }, + {"rtp_inst_pvar", PARAM_STR, &rtp_inst_pv_param }, + {"write_sdp_pv", PARAM_STR, &write_sdp_pvar_str }, + {"read_sdp_pv", PARAM_STR, &read_sdp_pvar_str }, + {"hash_table_tout", INT_PARAM, &hash_table_tout }, + {"hash_table_size", INT_PARAM, &hash_table_size }, + {"setid_default", INT_PARAM, &setid_default }, + {"media_duration", PARAM_STR, &media_duration_pvar_str}, + {"hash_algo", INT_PARAM, &hash_algo}, + {"dtmf_events_sock", STR_PARAM|USE_FUNC_PARAM, (void *)rtpengine_set_dtmf_events_sock}, + {"dtmf_event_callid", PARAM_STR, &dtmf_event_callid_pvar_str }, + {"dtmf_event_source_tag", PARAM_STR, &dtmf_event_source_tag_pvar_str }, + {"dtmf_event_timestamp", PARAM_STR, &dtmf_event_timestamp_pvar_str }, + {"dtmf_event", PARAM_STR, &dtmf_event_pvar_str }, + + /* MOS stats output */ + /* global averages */ + {"mos_min_pv", PARAM_STR, &global_mos_stats.min.mos_param }, + {"mos_min_at_pv", PARAM_STR, &global_mos_stats.min.at_param }, + {"mos_min_packetloss_pv", PARAM_STR, &global_mos_stats.min.packetloss_param }, + {"mos_min_jitter_pv", PARAM_STR, &global_mos_stats.min.jitter_param }, + {"mos_min_roundtrip_pv", PARAM_STR, &global_mos_stats.min.roundtrip_param }, + {"mos_min_roundtrip_leg_pv", PARAM_STR, &global_mos_stats.min.roundtrip_leg_param }, + {"mos_max_pv", PARAM_STR, &global_mos_stats.max.mos_param }, + {"mos_max_at_pv", PARAM_STR, &global_mos_stats.max.at_param }, + {"mos_max_packetloss_pv", PARAM_STR, &global_mos_stats.max.packetloss_param }, + {"mos_max_jitter_pv", PARAM_STR, &global_mos_stats.max.jitter_param }, + {"mos_max_roundtrip_pv", PARAM_STR, &global_mos_stats.max.roundtrip_param }, + {"mos_max_roundtrip_leg_pv", PARAM_STR, &global_mos_stats.max.roundtrip_leg_param }, + {"mos_average_pv", PARAM_STR, &global_mos_stats.average.mos_param }, + {"mos_average_packetloss_pv", PARAM_STR, &global_mos_stats.average.packetloss_param }, + {"mos_average_jitter_pv", PARAM_STR, &global_mos_stats.average.jitter_param }, + {"mos_average_roundtrip_pv", PARAM_STR, &global_mos_stats.average.roundtrip_param }, + {"mos_average_roundtrip_leg_pv", PARAM_STR, &global_mos_stats.average.roundtrip_leg_param }, + {"mos_average_samples_pv", PARAM_STR, &global_mos_stats.average.samples_param }, /* designated side A */ {"mos_A_label_pv", PARAM_STR, &side_A_mos_stats.label_param}, @@ -1240,8 +1250,208 @@ static int rtpengine_add_rtpengine_set(char *rtp_proxies, unsigned int weight, return -1; } +static int rtpengine_set_dtmf_events_sock(modparam_t type, void * val) +{ + char * p; + p = (char* )val; + + if(p==0 || *p=='\0'){ + return 0; + } + + rtpengine_dtmf_event_sock.s = p; + rtpengine_dtmf_event_sock.len = strlen(rtpengine_dtmf_event_sock.s); + + return 0; +} + +static void rtpengine_dtmf_events_loop(int rank) +{ + int ret; + char *p; + str s_port; + unsigned int port; + union sockaddr_union udp_addr; + char buffer[RTPENGINE_DTMF_EVENT_BUFFER]; + + p = q_memchr(rtpengine_dtmf_event_sock.s, ':', rtpengine_dtmf_event_sock.len); + if (!p) { + LM_ERR("failed to initialize dtmf event listener because no port was specified %.*s!\n", rtpengine_dtmf_event_sock.len, rtpengine_dtmf_event_sock.s); + return; + } + + s_port.s = p + 1; + s_port.len = rtpengine_dtmf_event_sock.s + rtpengine_dtmf_event_sock.len - s_port.s; + + if (s_port.len <= 0 || str2int(&s_port, &port) < 0 || port > 65535) { + LM_ERR("failed to initialize dtmf event listener because port is invalid %.*s\n", rtpengine_dtmf_event_sock.len, rtpengine_dtmf_event_sock.s); + return; + } + rtpengine_dtmf_event_sock.len -= s_port.len + 1; + trim(&rtpengine_dtmf_event_sock); + rtpengine_dtmf_event_sock.s[rtpengine_dtmf_event_sock.len] = '\0'; + + memset(&udp_addr, 0, sizeof(udp_addr)); + + if (rtpengine_dtmf_event_sock.s[0] == '[') { + udp_addr.sin6.sin6_family = AF_INET6; + udp_addr.sin6.sin6_port = htons(port); + ret = inet_pton(AF_INET, rtpengine_dtmf_event_sock.s, &udp_addr.sin6.sin6_addr); + } else { + udp_addr.sin.sin_family = AF_INET; + udp_addr.sin.sin_port = htons(port); + ret = inet_pton(AF_INET, rtpengine_dtmf_event_sock.s, &udp_addr.sin.sin_addr); + } + + if (ret != 1) { + LM_ERR("failed to initialize dtmf event listener because address could not be created for %s\n", rtpengine_dtmf_event_sock.s); + return; + } + + rtpengine_dtmf_event_fd = socket(udp_addr.s.sa_family, SOCK_DGRAM, 0); + + if(rtpengine_dtmf_event_fd < 0) { + LM_ERR("can't create socket\n"); + return; + } + + if (bind(rtpengine_dtmf_event_fd, (struct sockaddr*)&udp_addr.s, sizeof(udp_addr.s)) < 0) { + LM_ERR("could not bind dtmf events socket %s:%u (%s:%d)\n", rtpengine_dtmf_event_sock.s, port, strerror(errno), errno); + goto end; + } + + LM_INFO("dtmf event listener started on %s:%u\n", rtpengine_dtmf_event_sock.s, port); + + for (;;) { + do + ret = read(rtpengine_dtmf_event_fd, buffer, RTPENGINE_DTMF_EVENT_BUFFER); + while (ret == -1 && errno == EINTR); + + if (ret < 0) { + LM_ERR("problem reading on socket %s:%u (%s:%d)\n", rtpengine_dtmf_event_sock.s, port, strerror(errno), errno); + goto end; + } + + if (dtmf_event_rt == -1) { + LM_NOTICE("nothing to do - nobody is listening!\n"); + continue; + } + + p = shm_malloc(ret + 1); + if (!p) { + LM_ERR("could not allocate %d for buffer %.*s\n", ret, ret, buffer); + continue; + } + memcpy(p, buffer, ret); + p[ret] = '\0'; + + if (rtpengine_raise_dtmf_event(p, ret) < 0) { + LM_ERR("Failed to raise dtmf event\n"); + shm_free(p); + } + } + +end: + close(rtpengine_dtmf_event_fd); +} + +static int rtpengine_raise_dtmf_event(char *buffer, int len) { + srjson_doc_t jdoc; + srjson_t *it = NULL; + struct sip_msg *fmsg; + struct run_act_ctx ctx; + int rtb; + + LM_DBG("executing event_route[rtpengine:dtmf-event] (%d)\n", dtmf_event_rt); + LM_DBG("dispatching buffer: %s\n", buffer); + + srjson_InitDoc(&jdoc, NULL); + + jdoc.buf.s = buffer; + jdoc.buf.len = len; -static int fixup_set_id(void **param, int param_no) + jdoc.root = srjson_Parse(&jdoc, jdoc.buf.s); + if(jdoc.root == NULL) { + LM_ERR("invalid json doc [[%s]]\n", jdoc.buf.s); + return -1; + } + + if(faked_msg_init()<0) { + LM_ERR("Failed to initialize fake msg\n"); + return -1; + } + + /* iterate over keys */ + for(it = jdoc.root->child; it; it = it->next) { + LM_DBG("found field: %s\n", it->string); + if(strcmp(it->string, "callid") == 0) { + pv_value_t pv_val; + pv_val.rs.s = it->valuestring; + pv_val.rs.len = strlen(it->valuestring); + pv_val.flags = PV_VAL_STR; + + if (dtmf_event_callid_pvar->setf(fmsg, &dtmf_event_callid_pvar->pvp, (int)EQ_T, &pv_val) < 0) { + LM_ERR("error setting pvar <%.*s>\n", dtmf_event_callid_pvar_str.len, dtmf_event_callid_pvar_str.s); + return -1; + } + } else if(strcmp(it->string, "source_tag") == 0) { + pv_value_t pv_val; + pv_val.rs.s = it->valuestring; + pv_val.rs.len = strlen(it->valuestring); + pv_val.flags = PV_VAL_STR; + + if (dtmf_event_source_tag_pvar->setf(fmsg, &dtmf_event_source_tag_pvar->pvp, (int)EQ_T, &pv_val) < 0) { + LM_ERR("error setting pvar <%.*s>\n", dtmf_event_source_tag_pvar_str.len, dtmf_event_source_tag_pvar_str.s); + return -1; + } + } else if(strcmp(it->string, "timestamp") == 0) { + pv_value_t pv_val; + int_str val = {0}; + char intbuf[32]; + snprintf(intbuf, sizeof(intbuf), "%lli", SRJSON_GET_INT(it)); + memset(&val, 0, sizeof(val)); + + pv_val.rs.s = intbuf; + pv_val.rs.len = strlen(intbuf); + pv_val.flags = PV_VAL_STR; + + if (dtmf_event_timestamp_pvar->setf(fmsg, &dtmf_event_timestamp_pvar->pvp, (int)EQ_T, &pv_val) < 0) { + LM_ERR("error setting pvar <%.*s>\n", dtmf_event_timestamp_pvar_str.len, dtmf_event_timestamp_pvar_str.s); + return -1; + } + } else if(strcmp(it->string, "event") == 0) { + pv_value_t pv_val; + int_str val = {0}; + char intbuf[32]; + snprintf(intbuf, sizeof(intbuf), "%lli", SRJSON_GET_INT(it)); + memset(&val, 0, sizeof(val)); + + pv_val.rs.s = intbuf; + pv_val.rs.len = strlen(intbuf); + pv_val.flags = PV_VAL_STR; + + if (dtmf_event_pvar->setf(fmsg, &dtmf_event_pvar->pvp, (int)EQ_T, &pv_val) < 0) { + LM_ERR("error setting pvar <%.*s>\n", dtmf_event_pvar_str.len, dtmf_event_pvar_str.s); + return -1; + } + } + } + + fmsg = faked_msg_next(); + rtb = get_route_type(); + set_route_type(REQUEST_ROUTE); + init_run_actions_ctx(&ctx); + run_top_route(event_rt.rlist[dtmf_event_rt], fmsg, &ctx); + set_route_type(rtb); + if(ctx.run_flags&DROP_R_F) { + LM_ERR("exit due to 'drop' in event route\n"); + return -1; + } + + return 0; +} + +static int fixup_set_id(void ** param, int param_no) { int int_val; unsigned int set_id; @@ -1812,7 +2022,47 @@ static int mod_init(void) } } - if(rtpp_strings) + if (dtmf_event_callid_pvar_str.len > 0) { + dtmf_event_callid_pvar = pv_cache_get(&dtmf_event_callid_pvar_str); + if (dtmf_event_callid_pvar == NULL + || (dtmf_event_callid_pvar->type != PVT_AVP && dtmf_event_callid_pvar->type != PVT_SCRIPTVAR) ) { + LM_ERR("dtmf_event_callid_pv: not a valid AVP or VAR definition <%.*s>\n", + dtmf_event_callid_pvar_str.len, dtmf_event_callid_pvar_str.s); + return -1; + } + } + + if (dtmf_event_source_tag_pvar_str.len > 0) { + dtmf_event_source_tag_pvar = pv_cache_get(&dtmf_event_source_tag_pvar_str); + if (dtmf_event_source_tag_pvar == NULL + || (dtmf_event_source_tag_pvar->type != PVT_AVP && dtmf_event_source_tag_pvar->type != PVT_SCRIPTVAR) ) { + LM_ERR("dtmf_event_source_tag_pv: not a valid AVP or VAR definition <%.*s>\n", + dtmf_event_source_tag_pvar_str.len, dtmf_event_source_tag_pvar_str.s); + return -1; + } + } + + if (dtmf_event_timestamp_pvar_str.len > 0) { + dtmf_event_timestamp_pvar = pv_cache_get(&dtmf_event_timestamp_pvar_str); + if (dtmf_event_timestamp_pvar == NULL + || (dtmf_event_timestamp_pvar->type != PVT_AVP && dtmf_event_timestamp_pvar->type != PVT_SCRIPTVAR) ) { + LM_ERR("dtmf_event_timestamp_pv: not a valid AVP or VAR definition <%.*s>\n", + dtmf_event_timestamp_pvar_str.len, dtmf_event_timestamp_pvar_str.s); + return -1; + } + } + + if (dtmf_event_pvar_str.len > 0) { + dtmf_event_pvar = pv_cache_get(&dtmf_event_pvar_str); + if (dtmf_event_pvar == NULL + || (dtmf_event_pvar->type != PVT_AVP && dtmf_event_pvar->type != PVT_SCRIPTVAR) ) { + LM_ERR("event_pv: not a valid AVP or VAR definition <%.*s>\n", + dtmf_event_pvar_str.len, dtmf_event_pvar_str.s); + return -1; + } + } + + if (rtpp_strings) pkg_free(rtpp_strings); if(load_tm_api(&tmb) < 0) { @@ -1858,6 +2108,10 @@ static int mod_init(void) } } + dtmf_event_rt = route_lookup(&event_rt, "rtpengine:dtmf-event"); + if (dtmf_event_rt >= 0 && event_rt.rlist[dtmf_event_rt] == 0) + dtmf_event_rt = -1; /* disable */ + return 0; } @@ -2147,6 +2401,9 @@ static int child_init(int rank) /* probe rtpengines only in first worker */ if(build_rtpp_socks(0, 1)) return -1; + + if (rtpengine_dtmf_event_sock.len > 0) + rtpengine_dtmf_events_loop(rank); } else { if(build_rtpp_socks(0, 0)) return -1; @@ -2173,7 +2430,9 @@ static void mod_destroy(void) rtpp_no_lock = NULL; } - if(!rtpp_set_list) { + close(rtpengine_dtmf_event_fd); + + if (!rtpp_set_list) { return; } @@ -2232,7 +2491,7 @@ static void mod_destroy(void) if(_rtpe_list_version != NULL) { shm_free(_rtpe_list_version); _rtpe_list_version = NULL; - } + } } From ecfec78bf38e17f96f6b01ec79bc89d7a63b797d Mon Sep 17 00:00:00 2001 From: Joey Golan Date: Mon, 29 May 2023 11:09:28 +0300 Subject: [PATCH 7/8] Initialize uninitialized local variable --- src/modules/rtpengine/rtpengine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/rtpengine/rtpengine.c b/src/modules/rtpengine/rtpengine.c index af9dc0ded7a..2ba0d2110cc 100644 --- a/src/modules/rtpengine/rtpengine.c +++ b/src/modules/rtpengine/rtpengine.c @@ -1358,7 +1358,7 @@ static void rtpengine_dtmf_events_loop(int rank) static int rtpengine_raise_dtmf_event(char *buffer, int len) { srjson_doc_t jdoc; srjson_t *it = NULL; - struct sip_msg *fmsg; + struct sip_msg *fmsg = NULL; struct run_act_ctx ctx; int rtb; From df3cce755c5538c9d60775716902720bcbabe2a7 Mon Sep 17 00:00:00 2001 From: Joey Golan Date: Mon, 29 May 2023 11:15:38 +0300 Subject: [PATCH 8/8] Pass 0 to pvar setf in case of an event raised --- src/modules/rtpengine/rtpengine.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/rtpengine/rtpengine.c b/src/modules/rtpengine/rtpengine.c index 2ba0d2110cc..a04a9e56627 100644 --- a/src/modules/rtpengine/rtpengine.c +++ b/src/modules/rtpengine/rtpengine.c @@ -1390,7 +1390,7 @@ static int rtpengine_raise_dtmf_event(char *buffer, int len) { pv_val.rs.len = strlen(it->valuestring); pv_val.flags = PV_VAL_STR; - if (dtmf_event_callid_pvar->setf(fmsg, &dtmf_event_callid_pvar->pvp, (int)EQ_T, &pv_val) < 0) { + if (dtmf_event_callid_pvar->setf(0, &dtmf_event_callid_pvar->pvp, (int)EQ_T, &pv_val) < 0) { LM_ERR("error setting pvar <%.*s>\n", dtmf_event_callid_pvar_str.len, dtmf_event_callid_pvar_str.s); return -1; } @@ -1400,7 +1400,7 @@ static int rtpengine_raise_dtmf_event(char *buffer, int len) { pv_val.rs.len = strlen(it->valuestring); pv_val.flags = PV_VAL_STR; - if (dtmf_event_source_tag_pvar->setf(fmsg, &dtmf_event_source_tag_pvar->pvp, (int)EQ_T, &pv_val) < 0) { + if (dtmf_event_source_tag_pvar->setf(0, &dtmf_event_source_tag_pvar->pvp, (int)EQ_T, &pv_val) < 0) { LM_ERR("error setting pvar <%.*s>\n", dtmf_event_source_tag_pvar_str.len, dtmf_event_source_tag_pvar_str.s); return -1; } @@ -1415,7 +1415,7 @@ static int rtpengine_raise_dtmf_event(char *buffer, int len) { pv_val.rs.len = strlen(intbuf); pv_val.flags = PV_VAL_STR; - if (dtmf_event_timestamp_pvar->setf(fmsg, &dtmf_event_timestamp_pvar->pvp, (int)EQ_T, &pv_val) < 0) { + if (dtmf_event_timestamp_pvar->setf(0, &dtmf_event_timestamp_pvar->pvp, (int)EQ_T, &pv_val) < 0) { LM_ERR("error setting pvar <%.*s>\n", dtmf_event_timestamp_pvar_str.len, dtmf_event_timestamp_pvar_str.s); return -1; } @@ -1430,7 +1430,7 @@ static int rtpengine_raise_dtmf_event(char *buffer, int len) { pv_val.rs.len = strlen(intbuf); pv_val.flags = PV_VAL_STR; - if (dtmf_event_pvar->setf(fmsg, &dtmf_event_pvar->pvp, (int)EQ_T, &pv_val) < 0) { + if (dtmf_event_pvar->setf(0, &dtmf_event_pvar->pvp, (int)EQ_T, &pv_val) < 0) { LM_ERR("error setting pvar <%.*s>\n", dtmf_event_pvar_str.len, dtmf_event_pvar_str.s); return -1; }