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

📄 sip_reg.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:
    if (!pj_list_empty(&regc->route_set)) {
	pjsip_hdr *route_pos;
	const pjsip_route_hdr *route;

	route_pos = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
	if (!route_pos)
	    route_pos = &tdata->msg->hdr;

	route = regc->route_set.next;
	while (route != &regc->route_set) {
	    pjsip_hdr *new_hdr = pjsip_hdr_shallow_clone(tdata->pool, route);
	    pj_list_insert_after(route_pos, new_hdr);
	    route_pos = new_hdr;
	    route = route->next;
	}
    }

    /* Add additional request headers */
    if (!pj_list_empty(&regc->hdr_list)) {
	const pjsip_hdr *hdr;

	hdr = regc->hdr_list.next;
	while (hdr != &regc->hdr_list) {
	    pjsip_hdr *new_hdr = pjsip_hdr_shallow_clone(tdata->pool, hdr);
	    pjsip_msg_add_hdr(tdata->msg, new_hdr);
	    hdr = hdr->next;
	}
    }

    /* Done. */
    *p_tdata = tdata;
    return PJ_SUCCESS;
}


PJ_DEF(pj_status_t) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg,
					pjsip_tx_data **p_tdata)
{
    pjsip_msg *msg;
    pj_status_t status;
    pjsip_tx_data *tdata;

    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);

    status = create_request(regc, &tdata);
    if (status != PJ_SUCCESS)
	return status;

    /* Add Contact header. */
    msg = tdata->msg;
    pjsip_msg_add_hdr(msg, pjsip_hdr_shallow_clone(tdata->pool, 
						   regc->contact_hdr));
    if (regc->expires_hdr)
	pjsip_msg_add_hdr(msg, pjsip_hdr_shallow_clone(tdata->pool,
						       regc->expires_hdr));

    if (regc->timer.id != 0) {
	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
	regc->timer.id = 0;
    }

    regc->auto_reg = autoreg;

    /* Done */
    *p_tdata = tdata;
    return PJ_SUCCESS;
}


PJ_DEF(pj_status_t) pjsip_regc_unregister(pjsip_regc *regc,
					  pjsip_tx_data **p_tdata)
{
    pjsip_tx_data *tdata;
    pjsip_msg *msg;
    pj_status_t status;

    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);

    if (regc->timer.id != 0) {
	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
	regc->timer.id = 0;
    }

    status = create_request(regc, &tdata);
    if (status != PJ_SUCCESS)
	return status;

    msg = tdata->msg;
    pjsip_msg_add_hdr(msg, pjsip_hdr_shallow_clone(tdata->pool, 
						   regc->contact_hdr));
    pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_expires_hdr);

    *p_tdata = tdata;
    return PJ_SUCCESS;
}

PJ_DEF(pj_status_t) pjsip_regc_unregister_all(pjsip_regc *regc,
					      pjsip_tx_data **p_tdata)
{
    pjsip_tx_data *tdata;
    pjsip_msg *msg;
    pj_status_t status;

    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);

    if (regc->timer.id != 0) {
	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
	regc->timer.id = 0;
    }

    status = create_request(regc, &tdata);
    if (status != PJ_SUCCESS)
	return status;

    msg = tdata->msg;
    pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_contact_hdr);
    pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_expires_hdr);

    *p_tdata = tdata;
    return PJ_SUCCESS;
}


PJ_DEF(pj_status_t) pjsip_regc_update_contact(  pjsip_regc *regc,
					        int contact_cnt,
						const pj_str_t contact[] )
{
    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
    return set_contact( regc, contact_cnt, contact );
}


PJ_DEF(pj_status_t) pjsip_regc_update_expires(  pjsip_regc *regc,
					        pj_uint32_t expires )
{
    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
    set_expires( regc, expires );
    return PJ_SUCCESS;
}


static void call_callback(pjsip_regc *regc, pj_status_t status, int st_code, 
			  const pj_str_t *reason,
			  pjsip_rx_data *rdata, pj_int32_t expiration,
			  int contact_cnt, pjsip_contact_hdr *contact[])
{
    struct pjsip_regc_cbparam cbparam;


    if (!regc->cb)
	return;

    cbparam.regc = regc;
    cbparam.token = regc->token;
    cbparam.status = status;
    cbparam.code = st_code;
    cbparam.reason = *reason;
    cbparam.rdata = rdata;
    cbparam.contact_cnt = contact_cnt;
    cbparam.expiration = expiration;
    if (contact_cnt) {
	pj_memcpy( cbparam.contact, contact, 
		   contact_cnt*sizeof(pjsip_contact_hdr*));
    }

    (*regc->cb)(&cbparam);
}

static void regc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
				   struct pj_timer_entry *entry)
{
    pjsip_regc *regc = entry->user_data;
    pjsip_tx_data *tdata;
    pj_status_t status;
    
    PJ_UNUSED_ARG(timer_heap);

    /* Temporarily increase busy flag to prevent regc from being deleted
     * in pjsip_regc_send()
     */
    regc->busy++;

    entry->id = 0;
    status = pjsip_regc_register(regc, 1, &tdata);
    if (status == PJ_SUCCESS) {
	status = pjsip_regc_send(regc, tdata);
    } 
    
    if (status != PJ_SUCCESS && regc->cb) {
	char errmsg[PJ_ERR_MSG_SIZE];
	pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
	call_callback(regc, status, 400, &reason, NULL, -1, 0, NULL);
    }

    regc->busy--;

    /* Delete the record if user destroy regc during the callback. */
    if (regc->_delete_flag && regc->busy==0) {
	pjsip_regc_destroy(regc);
    }
}

static void tsx_callback(void *token, pjsip_event *event)
{
    pj_status_t status;
    pjsip_regc *regc = token;
    pjsip_transaction *tsx = event->body.tsx_state.tsx;
    
    /* Decrement pending transaction counter. */
    pj_assert(regc->has_tsx);
    regc->has_tsx = PJ_FALSE;

    /* Handle 401/407 challenge (even when _delete_flag is set) */
    if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
	tsx->status_code == PJSIP_SC_UNAUTHORIZED)
    {
	pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
	pjsip_tx_data *tdata;

	status = pjsip_auth_clt_reinit_req( &regc->auth_sess,
					    rdata, 
					    tsx->last_tx,  
					    &tdata);

	if (status == PJ_SUCCESS) {
	    status = pjsip_regc_send(regc, tdata);
	} 
	
	if (status != PJ_SUCCESS) {

	    /* Only call callback if application is still interested
	     * in it.
	     */
	    if (regc->_delete_flag == 0) {
		/* Increment busy flag temporarily to prevent regc from
		 * being destroyed.
		 */
		++regc->busy;

		call_callback(regc, status, tsx->status_code, 
			      &rdata->msg_info.msg->line.status.reason,
			      rdata, -1, 0, NULL);

		/* Decrement busy flag */
		--regc->busy;
	    }
	}

    } else if (regc->_delete_flag) {

	/* User has called pjsip_regc_destroy(), so don't call callback. 
	 * This regc will be destroyed later in this function.
	 */

	/* Nothing to do */
	;

    } else {
	int contact_cnt = 0;
	pjsip_contact_hdr *contact[PJSIP_REGC_MAX_CONTACT];
	pjsip_rx_data *rdata;
	pj_int32_t expiration = 0xFFFF;

	if (tsx->status_code/100 == 2) {
	    int i;
	    pjsip_contact_hdr *hdr;
	    pjsip_msg *msg;
	    pjsip_expires_hdr *expires;

	    rdata = event->body.tsx_state.src.rdata;
	    msg = rdata->msg_info.msg;
	    hdr = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
	    while (hdr) {
		contact[contact_cnt++] = hdr;
		hdr = hdr->next;
		if (hdr == (void*)&msg->hdr)
		    break;
		hdr = pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, hdr);
	    }

	    expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);

	    if (expires)
		expiration = expires->ivalue;
	    
	    for (i=0; i<contact_cnt; ++i) {
		hdr = contact[i];
		if (hdr->expires >= 0 && hdr->expires < expiration)
		    expiration = contact[i]->expires;
	    }

	    if (regc->auto_reg && expiration != 0 && expiration != 0xFFFF) {
		pj_time_val delay = { 0, 0};

		delay.sec = expiration - DELAY_BEFORE_REFRESH;
		if (regc->expires != PJSIP_REGC_EXPIRATION_NOT_SPECIFIED && 
		    delay.sec > (pj_int32_t)regc->expires) 
		{
		    delay.sec = regc->expires;
		}
		if (delay.sec < DELAY_BEFORE_REFRESH) 
		    delay.sec = DELAY_BEFORE_REFRESH;
		regc->timer.cb = &regc_refresh_timer_cb;
		regc->timer.id = REFRESH_TIMER;
		regc->timer.user_data = regc;
		pjsip_endpt_schedule_timer( regc->endpt, &regc->timer, &delay);
		pj_gettimeofday(&regc->last_reg);
		regc->next_reg = regc->last_reg;
		regc->next_reg.sec += delay.sec;
	    }

	} else {
	    rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ? 
			event->body.tsx_state.src.rdata : NULL;
	}

	/* Increment busy flag temporarily to prevent regc from
	 * being destroyed.
	 */
	++regc->busy;

	/* Call callback. */
	if (expiration == 0xFFFF) expiration = -1;
	call_callback(regc, PJ_SUCCESS, tsx->status_code, 
		      (rdata ? &rdata->msg_info.msg->line.status.reason 
			: pjsip_get_status_text(tsx->status_code)),
		      rdata, expiration, 
		      contact_cnt, contact);

	/* Decrement busy flag */
	--regc->busy;
    }

    /* Delete the record if user destroy regc during the callback. */
    if (regc->_delete_flag && regc->busy==0) {
	pjsip_regc_destroy(regc);
    }
}

PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata)
{
    pj_status_t status;
    pjsip_cseq_hdr *cseq_hdr;
    pj_uint32_t cseq;

    /* Make sure we don't have pending transaction. */
    if (regc->has_tsx) {
	PJ_LOG(4,(THIS_FILE, "Unable to send request, regc has another "
			     "transaction pending"));
	pjsip_tx_data_dec_ref( tdata );
	return PJSIP_EBUSY;
    }

    /* Invalidate message buffer. */
    pjsip_tx_data_invalidate_msg(tdata);

    /* Increment CSeq */
    cseq = ++regc->cseq_hdr->cseq;
    cseq_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
    cseq_hdr->cseq = cseq;

    /* Increment pending transaction first, since transaction callback
     * may be called even before send_request() returns!
     */
    regc->has_tsx = PJ_TRUE;
    ++regc->busy;
    status = pjsip_endpt_send_request(regc->endpt, tdata, REGC_TSX_TIMEOUT,
				      regc, &tsx_callback);
    if (status!=PJ_SUCCESS) {
	PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
    }
    --regc->busy;

    /* Delete the record if user destroy regc during the callback. */
    if (regc->_delete_flag && regc->busy==0) {
	pjsip_regc_destroy(regc);
    }

    return status;
}


⌨️ 快捷键说明

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