⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sip_ua_layer.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	    /* Unlock user agent. */	    pj_mutex_unlock(mod_ua.mutex);	}    } else {	/* Unlock user agent. */	pj_mutex_unlock(mod_ua.mutex);    }    return dlg;}/* * Find the first dialog in dialog set in hash table for an incoming message. */static struct dlg_set *find_dlg_set_for_msg( pjsip_rx_data *rdata ){    /* CANCEL message doesn't have To tag, so we must lookup the dialog     * by finding the INVITE UAS transaction being cancelled.     */    if (rdata->msg_info.cseq->method.id == PJSIP_CANCEL_METHOD) {	pjsip_dialog *dlg;	/* Create key for the rdata, but this time, use INVITE as the	 * method.	 */	pj_str_t key;	pjsip_role_e role;	pjsip_transaction *tsx;	if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG)	    role = PJSIP_ROLE_UAS;	else	    role = PJSIP_ROLE_UAC;	pjsip_tsx_create_key(rdata->tp_info.pool, &key, role, 			     &pjsip_invite_method, rdata);	/* Lookup the INVITE transaction */	tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);	/* We should find the dialog attached to the INVITE transaction */	if (tsx) {	    dlg = tsx->mod_data[mod_ua.mod.id];	    pj_mutex_unlock(tsx->mutex);	    /* Dlg may be NULL on some extreme condition	     * (e.g. during debugging where initially there is a dialog)	     */	    return dlg ? dlg->dlg_set : NULL;	} else {	    return NULL;	}    } else {	pj_str_t *tag;	struct dlg_set *dlg_set;	if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG)	    tag = &rdata->msg_info.to->tag;	else	    tag = &rdata->msg_info.from->tag;	/* Lookup the dialog set. */	dlg_set = pj_hash_get(mod_ua.dlg_table, tag->ptr, tag->slen, NULL);	return dlg_set;    }}/* On received requests. */static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata){    struct dlg_set *dlg_set;    pj_str_t *from_tag;    pjsip_dialog *dlg;    pj_status_t status;    /* Optimized path: bail out early if request is not CANCEL and it doesn't     * have To tag      */    if (rdata->msg_info.to->tag.slen == 0 && 	rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD)    {	return PJ_FALSE;    }retry_on_deadlock:    /* Lock user agent before looking up the dialog hash table. */    pj_mutex_lock(mod_ua.mutex);    /* Lookup the dialog set, based on the To tag header. */    dlg_set = find_dlg_set_for_msg(rdata);    /* If dialog is not found, respond with 481 (Call/Transaction     * Does Not Exist).     */    if (dlg_set == NULL) {	/* Unable to find dialog. */	pj_mutex_unlock(mod_ua.mutex);	if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {	    PJ_LOG(5,(THIS_FILE, 		      "Unable to find dialogset for %s, answering with 481",		      pjsip_rx_data_get_info(rdata)));	    /* Respond with 481 . */	    pjsip_endpt_respond_stateless( mod_ua.endpt, rdata, 481, NULL, 					   NULL, NULL );	}	return PJ_TRUE;    }    /* Dialog set has been found.     * Find the dialog in the dialog set based on the content of the remote      * tag.     */    from_tag = &rdata->msg_info.from->tag;    dlg = dlg_set->dlg_list.next;    while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {		if (pj_strcmp(&dlg->remote.info->tag, from_tag) == 0)	    break;	dlg = dlg->next;    }    /* Dialog may not be found, e.g. in this case:     *	- UAC sends SUBSCRIBE, then UAS sends NOTIFY before answering     *    SUBSCRIBE request with 2xx.     *     * In this case, we can accept the request ONLY when the original      * dialog still has empty To tag.     */    if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {	pjsip_dialog *first_dlg = dlg_set->dlg_list.next;	if (first_dlg->remote.info->tag.slen != 0) {	    /* Not found. Mulfunction UAC? */	    pj_mutex_unlock(mod_ua.mutex);	    if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {		PJ_LOG(5,(THIS_FILE, 		          "Unable to find dialog for %s, answering with 481",		          pjsip_rx_data_get_info(rdata)));		pjsip_endpt_respond_stateless(mod_ua.endpt, rdata,					      PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, 					      NULL, NULL, NULL);	    } else {		PJ_LOG(5,(THIS_FILE, 		          "Unable to find dialog for %s",		          pjsip_rx_data_get_info(rdata)));	    }	    return PJ_TRUE;	}	dlg = first_dlg;    }    /* Mark the dialog id of the request. */    rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;    /* Try to lock the dialog */    PJ_LOG(6,(dlg->obj_name, "UA layer acquiring dialog lock for request"));    status = pjsip_dlg_try_inc_lock(dlg);    if (status != PJ_SUCCESS) {	/* Failed to acquire dialog mutex immediately, this could be 	 * because of deadlock. Release UA mutex, yield, and retry 	 * the whole thing once again.	 */	pj_mutex_unlock(mod_ua.mutex);	pj_thread_sleep(0);	goto retry_on_deadlock;    }    /* Done with processing in UA layer, release lock */    pj_mutex_unlock(mod_ua.mutex);    /* Pass to dialog. */    pjsip_dlg_on_rx_request(dlg, rdata);    /* Unlock the dialog. This may destroy the dialog */    pjsip_dlg_dec_lock(dlg);    /* Report as handled. */    return PJ_TRUE;}/* On rx response notification. */static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata){    pjsip_transaction *tsx;    struct dlg_set *dlg_set;    pjsip_dialog *dlg;    pj_status_t status;    /*     * Find the dialog instance for the response.     * All outgoing dialog requests are sent statefully, which means     * there will be an UAC transaction associated with this response,     * and the dialog instance will be recorded in that transaction.     *     * But even when transaction is found, there is possibility that     * the response is a forked response.     */retry_on_deadlock:    dlg = NULL;    /* Lock user agent dlg table before we're doing anything. */    pj_mutex_lock(mod_ua.mutex);    /* Check if transaction is present. */    tsx = pjsip_rdata_get_tsx(rdata);    if (tsx) {	/* Check if dialog is present in the transaction. */	dlg = pjsip_tsx_get_dlg(tsx);	if (!dlg) {	    /* Unlock dialog hash table. */	    pj_mutex_unlock(mod_ua.mutex);	    return PJ_FALSE;	}	/* Get the dialog set. */	dlg_set = dlg->dlg_set;	/* Even if transaction is found and (candidate) dialog has been 	 * identified, it's possible that the request has forked.	 */    } else {	/* Transaction is not present.	 * Check if this is a 2xx/OK response to INVITE, which in this	 * case the response will be handled directly by the	 * dialog.	 */	pjsip_cseq_hdr *cseq_hdr = rdata->msg_info.cseq;	if (cseq_hdr->method.id != PJSIP_INVITE_METHOD ||	    rdata->msg_info.msg->line.status.code / 100 != 2)	{	    /* Not a 2xx response to INVITE.	     * This must be some stateless response sent by other modules,	     * or a very late response.	     */	    /* Unlock dialog hash table. */	    pj_mutex_unlock(mod_ua.mutex);	    return PJ_FALSE;	}	/* Get the dialog set. */	dlg_set = pj_hash_get(mod_ua.dlg_table, 			      rdata->msg_info.from->tag.ptr,			      rdata->msg_info.from->tag.slen,			      NULL);	if (!dlg_set) {	    /* Unlock dialog hash table. */	    pj_mutex_unlock(mod_ua.mutex);	    /* Strayed 2xx response!! */	    PJ_LOG(4,(THIS_FILE, 		      "Received strayed 2xx response (no dialog is found)"		      " from %s:%d: %s",		      rdata->pkt_info.src_name, rdata->pkt_info.src_port,		      pjsip_rx_data_get_info(rdata)));	    return PJ_TRUE;	}    }    /* At this point, we must have the dialog set, and the dialog set     * must have a dialog in the list.     */    pj_assert(dlg_set && !pj_list_empty(&dlg_set->dlg_list));    /* Check for forked response.      * Request will fork only for the initial INVITE request.     */    //This doesn't work when there is authentication challenge, since     //first_cseq evaluation will yield false.    //if (rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD &&    //	rdata->msg_info.cseq->cseq == dlg_set->dlg_list.next->local.first_cseq)    if (rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD) {		int st_code = rdata->msg_info.msg->line.status.code;	pj_str_t *to_tag = &rdata->msg_info.to->tag;	dlg = dlg_set->dlg_list.next;	while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {	    /* If there is dialog with no remote tag (i.e. dialog has not	     * been established yet), then send this response to that	     * dialog.	     */	    if (dlg->remote.info->tag.slen == 0)		break;	    /* Otherwise find the one with matching To tag. */	    if (pj_strcmp(to_tag, &dlg->remote.info->tag) == 0)		break;	    dlg = dlg->next;	}	/* If no dialog with matching remote tag is found, this must be	 * a forked response. Respond to this ONLY when response is non-100	 * provisional response OR a 2xx response.	 */	if (dlg == (pjsip_dialog*)&dlg_set->dlg_list &&	    ((st_code/100==1 && st_code!=100) || st_code/100==2)) 	{	    PJ_LOG(5,(THIS_FILE, 		      "Received forked %s for existing dialog %s",		      pjsip_rx_data_get_info(rdata), 		      dlg_set->dlg_list.next->obj_name));	    /* Report to application about forked condition.	     * Application can either create a dialog or ignore the response.	     */	    if (mod_ua.param.on_dlg_forked) {		dlg = (*mod_ua.param.on_dlg_forked)(dlg_set->dlg_list.next, 						    rdata);	    } else {		dlg = dlg_set->dlg_list.next;		PJ_LOG(4,(THIS_FILE, 			  "Unhandled forked %s from %s:%d, response will be "			  "handed over to the first dialog",			  pjsip_rx_data_get_info(rdata),			  rdata->pkt_info.src_name, rdata->pkt_info.src_port));	    }	} else if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {	    /* For 100 or non-2xx response which has different To tag,	     * pass the response to the first dialog.	     */	    dlg = dlg_set->dlg_list.next;	}    } else {	/* Either this is a non-INVITE response, or subsequent INVITE	 * within dialog. The dialog should have been identified when	 * the transaction was found.	 */	pj_assert(tsx != NULL);	pj_assert(dlg != NULL);    }    /* The dialog must have been found. */    pj_assert(dlg != NULL);    /* Put the dialog instance in the rdata. */    rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;    /* Attempt to acquire lock to the dialog. */    PJ_LOG(6,(dlg->obj_name, "UA layer acquiring dialog lock for response"));    status = pjsip_dlg_try_inc_lock(dlg);    if (status != PJ_SUCCESS) {	/* Failed to acquire dialog mutex. This could indicate a deadlock	 * situation, and for safety, try to avoid deadlock by releasing	 * UA mutex, yield, and retry the whole processing once again.	 */	pj_mutex_unlock(mod_ua.mutex);	pj_thread_sleep(0);	goto retry_on_deadlock;    }    /* We're done with processing in the UA layer, we can release the mutex */    pj_mutex_unlock(mod_ua.mutex);    /* Pass the response to the dialog. */    pjsip_dlg_on_rx_response(dlg, rdata);    /* Unlock the dialog. This may destroy the dialog. */    pjsip_dlg_dec_lock(dlg);    /* Done. */    return PJ_TRUE;}#if PJ_LOG_MAX_LEVEL >= 3static void print_dialog( const char *title,			  pjsip_dialog *dlg, char *buf, pj_size_t size){    int len;    char userinfo[128];    len = pjsip_hdr_print_on(dlg->remote.info, userinfo, sizeof(userinfo));    if (len < 1)	pj_ansi_strcpy(userinfo, "<--uri too long-->");    else	userinfo[len] = '\0';        len = pj_ansi_snprintf(buf, size, "%s[%s]  %s",			   title,			   (dlg->state==PJSIP_DIALOG_STATE_NULL ? " - " :							     "est"),		      userinfo);    if (len < 1 || len >= (int)size) {	pj_ansi_strcpy(buf, "<--uri too long-->");    } else	buf[len] = '\0';}#endif/* * Dump user agent contents (e.g. all dialogs). */PJ_DEF(void) pjsip_ua_dump(pj_bool_t detail){#if PJ_LOG_MAX_LEVEL >= 3    pj_hash_iterator_t itbuf, *it;    char dlginfo[128];    pj_mutex_lock(mod_ua.mutex);    PJ_LOG(3, (THIS_FILE, "Number of dialog sets: %u", 			  pj_hash_count(mod_ua.dlg_table)));    if (detail && pj_hash_count(mod_ua.dlg_table)) {	PJ_LOG(3, (THIS_FILE, "Dumping dialog sets:"));	it = pj_hash_first(mod_ua.dlg_table, &itbuf);	for (; it != NULL; it = pj_hash_next(mod_ua.dlg_table, it))  {	    struct dlg_set *dlg_set;	    pjsip_dialog *dlg;	    const char *title;	    dlg_set = pj_hash_this(mod_ua.dlg_table, it);	    if (!dlg_set || pj_list_empty(&dlg_set->dlg_list)) continue;	    /* First dialog in dialog set. */	    dlg = dlg_set->dlg_list.next;	    if (dlg->role == PJSIP_ROLE_UAC)		title = "  [out] ";	    else		title = "  [in]  ";	    print_dialog(title, dlg, dlginfo, sizeof(dlginfo));	    PJ_LOG(3,(THIS_FILE, "%s", dlginfo));	    /* Next dialog in dialog set (forked) */	    dlg = dlg->next;	    while (dlg != (pjsip_dialog*) &dlg_set->dlg_list) {		print_dialog("    [forked] ", dlg, dlginfo, sizeof(dlginfo));		dlg = dlg->next;	    }	}    }    pj_mutex_unlock(mod_ua.mutex);#endif}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -