/*************************************************************************************** * * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. * * By downloading, copying, installing or using the software you agree to this license. * If you do not agree to this license, do not download, install, * copy or use the software. * * Copyright (C) 2014-2022, Happytimesoft Corporation, all rights reserved. * * Redistribution and use in binary forms, with or without modification, are permitted. * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. * ****************************************************************************************/ #include "sys_inc.h" #include "hsip.h" #include "sip_parse.h" #include "sip_trans.h" /***************************************************************************************/ extern HSIP_CLASS hsip; /***************************************************************************************/ STRANSN * sip_trans_get_idle(STRANS * thiz, BOOL b_sig) { STRANSN * p_trans =(STRANSN *)pps_fl_pop(thiz->trans_fl); if (p_trans) { memset(p_trans, 0, sizeof(STRANSN)); // Set the global ID of this call sprintf(p_trans->callid, "%u%u@%s", (uint32)rand(), sys_os_get_uptime(), hsip.local_ipstr); if (b_sig == TRUE) { p_trans->p_wait_sig = sys_os_create_sig(); } // Set default retransmission parameters p_trans->state_retx_count = 0; p_trans->state_timer_interval = 1; p_trans->state_retx_max_times = 5; pps_ctx_ul_add(thiz->trans_ul, p_trans); // Add to UsedList for easy management } else { // pps_ctx_show(thiz->trans_fl); } return p_trans; } BOOL sip_trans_set_msg(STRANSN * p_trans, void * p_msg) { if (p_trans == NULL || p_msg == NULL) { return FALSE; } HSIP_MSG * tx_msg = (HSIP_MSG *)p_msg; char cseq[16]; if (sip_get_user_name(tx_msg, "From", p_trans->from, sizeof(p_trans->from)) == FALSE) { return FALSE; } if (sip_get_user_name(tx_msg, "To", p_trans->to, sizeof(p_trans->to)) == FALSE) { return FALSE; } if (sip_get_msg_call_id(tx_msg, p_trans->callid, sizeof(p_trans->callid)) == FALSE) { return FALSE; } if (sip_get_msg_cseq(tx_msg, cseq, sizeof(cseq)) == FALSE) { return FALSE; } p_trans->seq = (uint32)atoi(cseq); p_trans->tx_msg = tx_msg; p_trans->state = 1; log_print(HT_LOG_INFO, "%s, from[%s] to[%s] callid[%s] seq[%u]\r\n", __FUNCTION__, p_trans->from, p_trans->to, p_trans->callid, p_trans->seq); return TRUE; } void sip_trans_set_idle(STRANS * thiz, STRANSN * p_trans) { sip_trans_hash_del(thiz, p_trans); sys_os_destroy_sig_mutex(p_trans->p_wait_sig); memset(p_trans, 0, sizeof(STRANSN)); pps_fl_push_tail(thiz->trans_fl, p_trans); } void sip_trans_free_used(STRANS * thiz, STRANSN * p_trans) { pps_ctx_ul_del(thiz->trans_ul, p_trans); sip_trans_set_idle(thiz, p_trans); } STRANSN * sip_trans_lookup_start(STRANS * thiz) { return (STRANSN *)pps_lookup_start(thiz->trans_ul); } STRANSN * sip_trans_lookup_next(STRANS * thiz, STRANSN * p_trans) { return (STRANSN *)pps_lookup_next(thiz->trans_ul, p_trans); } void sip_trans_lookup_stop(STRANS * thiz) { pps_lookup_end(thiz->trans_ul); } /*******************************************************\ Get the index value of the corresponding PTRANS transaction entry \*******************************************************/ uint32 sip_trans_get_index(STRANS * thiz, STRANSN * p_trans) { return pps_get_index(thiz->trans_fl, p_trans); } STRANSN * sip_trans_get_by_index(STRANS * thiz, uint32 index) { return (STRANSN *)pps_get_node_by_index(thiz->trans_fl, index); } /*******************************************************\ PTRANS transaction table entry HASH operation \*******************************************************/ void sip_trans_hash_add(STRANS * thiz, STRANSN * p_trans) { snprintf(p_trans->hash_key, sizeof(p_trans->hash_key)-1, "%s%s%s%u", p_trans->callid, p_trans->from, p_trans->to, p_trans->seq); ihash_add(thiz->trans_hash, p_trans->hash_key, sip_trans_get_index(thiz, p_trans), 0); } void sip_trans_hash_del(STRANS * thiz, STRANSN * p_trans) { ihash_del(thiz->trans_hash, p_trans->hash_key, sip_trans_get_index(thiz, p_trans)); } STRANSN * sip_trans_hash_find(STRANS * thiz, const char * hash_key) { uint32 trans_index = (uint32) ihash_find_index_from_keystr(thiz->trans_hash, hash_key); if (trans_index == 0xFFFFFFFF || trans_index >= thiz->trans_num) { return NULL; } return sip_trans_get_by_index(thiz, trans_index); } /*******************************************************\ Transaction timer, check retransmission requirements \*******************************************************/ void sip_trans_timer(STRANS * thiz, uint32 cur_t) { uint32 i; STRANSN * p_trans; for (i = 0; i < thiz->trans_num; i++) { p_trans = sip_trans_get_by_index(thiz, i); if (p_trans == NULL || p_trans->last_tx_time == 0 || p_trans->state != 1) { continue; } if ((cur_t - p_trans->last_tx_time) > p_trans->state_timer_interval) { if (p_trans->state_retx_count > p_trans->state_retx_max_times) { p_trans->state = 4; if (p_trans->p_wait_sig) { sys_os_sig_sign(p_trans->p_wait_sig); // Notify the caller, the caller checks the state unit to determine whether it is successful or not } continue; } // sip_user_send_msg(&g_user, p_trans->tx_msg); p_trans->last_tx_time = sys_os_get_uptime(); p_trans->state_retx_count++; } } } /*******************************************************\ Response packet receiving processing \*******************************************************/ STRANSN * sip_trans_rly_find(STRANS * thiz, const char * callid, const char * from, const char * to, uint32 seq) { char hash_key[128]; snprintf(hash_key, sizeof(hash_key)-1, "%s%s%s%u", callid, from, to, seq); STRANSN * p_trans = sip_trans_hash_find(thiz, hash_key); if (p_trans == NULL) { return NULL; } if ((strcasecmp(p_trans->from, from) != 0) || (strcasecmp(p_trans->to, to) != 0) || p_trans->seq != seq) { log_print(HT_LOG_ERR, "%s, hash err!!!\r\n", __FUNCTION__); return NULL; } p_trans->state = 2; return p_trans; } /*******************************************************\ Transaction request response waiting \*******************************************************/ int sip_trans_wait(STRANSN * p_trans, int ms) { return sys_os_sig_wait_timeout(p_trans->p_wait_sig, ms); } /*******************************************************\ Transaction initialization function \*******************************************************/ void sip_trans_init(STRANS * thiz, int num) { memset(thiz, 0, sizeof(STRANS)); thiz->trans_num = num; thiz->trans_fl = pps_ctx_fl_init(num, sizeof(STRANSN), TRUE); thiz->trans_ul = pps_ctx_ul_init(thiz->trans_fl, TRUE); thiz->trans_hash = ihash_init(num, num); } void sip_trans_uninit(STRANS * thiz) { if (thiz->trans_hash) { ihash_uninit(thiz->trans_hash); thiz->trans_hash = NULL; } if (thiz->trans_ul) { pps_ul_free(thiz->trans_ul); thiz->trans_ul = NULL; } if (thiz->trans_fl) { pps_fl_free(thiz->trans_fl); thiz->trans_fl = NULL; } }