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

📄 pjsua_pres.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		       param->reason.ptr));	}	pjsip_publishc_destroy(param->pubc);	acc->publish_sess = NULL;    }}/* * Send PUBLISH request. */static pj_status_t send_publish(int acc_id, pj_bool_t active){    pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;    pjsua_acc *acc = &pjsua_var.acc[acc_id];    pjsip_pres_status pres_status;    pjsip_tx_data *tdata;    pj_status_t status;    /* Create PUBLISH request */    if (active) {	char *bpos;	pj_str_t entity;	status = pjsip_publishc_publish(acc->publish_sess, PJ_TRUE, &tdata);	if (status != PJ_SUCCESS) {	    pjsua_perror(THIS_FILE, "Error creating PUBLISH request", status);	    goto on_error;	}	/* Set our online status: */	pj_bzero(&pres_status, sizeof(pres_status));	pres_status.info_cnt = 1;	pres_status.info[0].basic_open = acc->online_status;	/* Be careful not to send PIDF with presence entity ID containing	 * "<" character.	 */	if ((bpos=pj_strchr(&acc_cfg->id, '<')) != NULL) {	    char *epos = pj_strchr(&acc_cfg->id, '>');	    if (epos - bpos < 2) {		pj_assert(!"Unexpected invalid URI");		status = PJSIP_EINVALIDURI;		goto on_error;	    }	    entity.ptr = bpos+1;	    entity.slen = epos - bpos - 1;	} else {	    entity = acc_cfg->id;	}	/* Create and add PIDF message body */	status = pjsip_pres_create_pidf(tdata->pool, &pres_status,					&entity, &tdata->msg->body);	if (status != PJ_SUCCESS) {	    pjsua_perror(THIS_FILE, "Error creating PIDF for PUBLISH request",			 status);	    pjsip_tx_data_dec_ref(tdata);	    goto on_error;	}    } else {	status = pjsip_publishc_unpublish(acc->publish_sess, &tdata);	if (status != PJ_SUCCESS) {	    pjsua_perror(THIS_FILE, "Error creating PUBLISH request", status);	    goto on_error;	}    }    /* Add headers etc */    pjsua_process_msg_data(tdata, NULL);    /* Send the PUBLISH request */    status = pjsip_publishc_send(acc->publish_sess, tdata);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Error sending PUBLISH request", status);	goto on_error;    }    acc->publish_state = acc->online_status;    return PJ_SUCCESS;on_error:    pjsip_publishc_destroy(acc->publish_sess);    acc->publish_sess = NULL;    return status;}/* Create client publish session */pj_status_t pjsua_pres_init_publish_acc(int acc_id){    const pj_str_t STR_PRESENCE = { "presence", 8 };    pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;    pjsua_acc *acc = &pjsua_var.acc[acc_id];    pj_status_t status;    /* Create and init client publication session */    if (acc_cfg->publish_enabled) {	/* Create client publication */	status = pjsip_publishc_create(pjsua_var.endpt, 0, acc, &publish_cb,				       &acc->publish_sess);	if (status != PJ_SUCCESS) {	    acc->publish_sess = NULL;	    return status;	}	/* Initialize client publication */	status = pjsip_publishc_init(acc->publish_sess, &STR_PRESENCE,				     &acc_cfg->id, &acc_cfg->id,				     &acc_cfg->id, 				     60);	if (status != PJ_SUCCESS) {	    acc->publish_sess = NULL;	    return status;	}	/* Add credential for authentication */	pjsip_publishc_set_credentials(acc->publish_sess, acc->cred_cnt, 				       acc->cred);	/* Set route-set */	pjsip_publishc_set_route_set(acc->publish_sess, &acc->route_set);	/* Send initial PUBLISH request */	if (acc->online_status != 0) {	    status = send_publish(acc_id, PJ_TRUE);	    if (status != PJ_SUCCESS)		return status;	}    } else {	acc->publish_sess = NULL;    }    return PJ_SUCCESS;}/* Init presence for account */pj_status_t pjsua_pres_init_acc(int acc_id){    pjsua_acc *acc = &pjsua_var.acc[acc_id];    /* Init presence subscription */    pj_list_init(&acc->pres_srv_list);    return PJ_SUCCESS;}/* Terminate server subscription for the account */void pjsua_pres_delete_acc(int acc_id){    pjsua_acc *acc = &pjsua_var.acc[acc_id];    pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;    pjsua_srv_pres *uapres;    uapres = pjsua_var.acc[acc_id].pres_srv_list.next;    /* Notify all subscribers that we're no longer available */    while (uapres != &acc->pres_srv_list) {		pjsip_pres_status pres_status;	pj_str_t reason = { "noresource", 10 };	pjsip_tx_data *tdata;	pjsip_pres_get_status(uapres->sub, &pres_status);		pres_status.info[0].basic_open = pjsua_var.acc[acc_id].online_status;	pjsip_pres_set_status(uapres->sub, &pres_status);	if (pjsip_pres_notify(uapres->sub, 			      PJSIP_EVSUB_STATE_TERMINATED, NULL,			      &reason, &tdata)==PJ_SUCCESS)	{	    pjsip_pres_send_request(uapres->sub, tdata);	}	uapres = uapres->next;    }    /* Clear server presence subscription list because account might be reused     * later. */    pj_list_init(&acc->pres_srv_list);    /* Terminate presence publication, if any */    if (acc->publish_sess) {	acc->online_status = PJ_FALSE;	send_publish(acc_id, PJ_FALSE);	if (acc->publish_sess) {	    pjsip_publishc_destroy(acc->publish_sess);	    acc->publish_sess = NULL;	}	acc_cfg->publish_enabled = PJ_FALSE;    }}/* Refresh subscription (e.g. when our online status has changed) */static void refresh_server_subscription(int acc_id){    pjsua_acc *acc = &pjsua_var.acc[acc_id];    pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;    pjsua_srv_pres *uapres;    uapres = pjsua_var.acc[acc_id].pres_srv_list.next;    while (uapres != &acc->pres_srv_list) {		pjsip_pres_status pres_status;	pjsip_tx_data *tdata;	pjsip_pres_get_status(uapres->sub, &pres_status);	if (pres_status.info[0].basic_open != acc->online_status) {	    pres_status.info[0].basic_open = acc->online_status;	    pjsip_pres_set_status(uapres->sub, &pres_status);	    if (pjsip_pres_current_notify(uapres->sub, &tdata)==PJ_SUCCESS) {		pjsua_process_msg_data(tdata, NULL);		pjsip_pres_send_request(uapres->sub, tdata);	    }	}	uapres = uapres->next;    }    /* Send PUBLISH if required. We only do this when we have a PUBLISH     * session. If we don't have a PUBLISH session, then it could be     * that we're waiting until registration has completed before we     * send the first PUBLISH.      */    if (acc_cfg->publish_enabled && acc->publish_sess) {	if (acc->publish_state != acc->online_status) {	    send_publish(acc_id, PJ_TRUE);	}    }}/*************************************************************************** * Client subscription. *//* Callback called when *client* subscription state has changed. */static void pjsua_evsub_on_state( pjsip_evsub *sub, pjsip_event *event){    pjsua_buddy *buddy;    PJ_UNUSED_ARG(event);    PJSUA_LOCK();    buddy = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id);    if (buddy) {	PJ_LOG(3,(THIS_FILE, 		  "Presence subscription to %.*s is %s",		  (int)pjsua_var.buddy[buddy->index].uri.slen,		  pjsua_var.buddy[buddy->index].uri.ptr, 		  pjsip_evsub_get_state_name(sub)));	if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {	    buddy->sub = NULL;	    buddy->status.info_cnt = 0;	    pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL);	}	/* Call callback */	if (pjsua_var.ua_cfg.cb.on_buddy_state)	    (*pjsua_var.ua_cfg.cb.on_buddy_state)(buddy->index);    }    PJSUA_UNLOCK();}/* Callback when transaction state has changed. */static void pjsua_evsub_on_tsx_state(pjsip_evsub *sub, 				     pjsip_transaction *tsx,				     pjsip_event *event){    pjsua_buddy *buddy;    pjsip_contact_hdr *contact_hdr;    PJSUA_LOCK();    buddy = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id);    if (!buddy) {	PJSUA_UNLOCK();	return;    }    /* We only use this to update buddy's Contact, when it's not     * set.     */    if (buddy->contact.slen != 0) {	/* Contact already set */	PJSUA_UNLOCK();	return;    }        /* Only care about 2xx response to outgoing SUBSCRIBE */    if (tsx->status_code/100 != 2 ||	tsx->role != PJSIP_UAC_ROLE ||	event->type != PJSIP_EVENT_RX_MSG || 	pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method)!=0)    {	PJSUA_UNLOCK();	return;    }    /* Find contact header. */    contact_hdr = pjsip_msg_find_hdr(event->body.rx_msg.rdata->msg_info.msg,				     PJSIP_H_CONTACT, NULL);    if (!contact_hdr) {	PJSUA_UNLOCK();	return;    }    buddy->contact.ptr = pj_pool_alloc(pjsua_var.pool, PJSIP_MAX_URL_SIZE);    buddy->contact.slen = pjsip_uri_print( PJSIP_URI_IN_CONTACT_HDR,					   contact_hdr->uri,					   buddy->contact.ptr, 					   PJSIP_MAX_URL_SIZE);    if (buddy->contact.slen < 0)	buddy->contact.slen = 0;    PJSUA_UNLOCK();}/* Callback called when we receive NOTIFY */static void pjsua_evsub_on_rx_notify(pjsip_evsub *sub, 				     pjsip_rx_data *rdata,				     int *p_st_code,				     pj_str_t **p_st_text,				     pjsip_hdr *res_hdr,				     pjsip_msg_body **p_body){    pjsua_buddy *buddy;    PJSUA_LOCK();    buddy = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id);    if (buddy) {	/* Update our info. */	pjsip_pres_get_status(sub, &buddy->status);    }    /* The default is to send 200 response to NOTIFY.     * Just leave it there..     */    PJ_UNUSED_ARG(rdata);    PJ_UNUSED_ARG(p_st_code);    PJ_UNUSED_ARG(p_st_text);    PJ_UNUSED_ARG(res_hdr);    PJ_UNUSED_ARG(p_body);    PJSUA_UNLOCK();}/* Event subscription callback. */static pjsip_evsub_user pres_callback = {    &pjsua_evsub_on_state,      &pjsua_evsub_on_tsx_state,    NULL,   /* on_rx_refresh: don't care about SUBSCRIBE refresh, unless 	     * we want to authenticate 	     */    &pjsua_evsub_on_rx_notify,    NULL,   /* on_client_refresh: Use default behaviour, which is to 	     * refresh client subscription. */    NULL,   /* on_server_timeout: Use default behaviour, which is to send 	     * NOTIFY to terminate. 	     */};/* It does what it says.. */static void subscribe_buddy_presence(unsigned index){    pjsua_buddy *buddy;    int acc_id;    pjsua_acc *acc;    pj_str_t contact;    pjsip_dialog *dlg;    pjsip_tx_data *tdata;    pj_status_t status;    buddy = &pjsua_var.buddy[index];    acc_id = pjsua_acc_find_for_outgoing(&buddy->uri);    acc = &pjsua_var.acc[acc_id];    PJ_LOG(4,(THIS_FILE, "Using account %d for buddy %d subscription",			 acc_id, index));    /* Generate suitable Contact header */    status = pjsua_acc_create_uac_contact(pjsua_var.pool, &contact,					  acc_id, &buddy->uri);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);	return;    }    /* Create UAC dialog */    status = pjsip_dlg_create_uac( pjsip_ua_instance(), 				   &acc->cfg.id,				   &contact,				   &buddy->uri,				   NULL, &dlg);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to create dialog", 		     status);	return;    }    status = pjsip_pres_create_uac( dlg, &pres_callback, 				    PJSIP_EVSUB_NO_EVENT_ID, &buddy->sub);    if (status != PJ_SUCCESS) {	pjsua_var.buddy[index].sub = NULL;	pjsua_perror(THIS_FILE, "Unable to create presence client", 		     status);	pjsip_dlg_terminate(dlg);	return;    }    /* If account is locked to specific transport, then lock dialog     * to this transport too.     */    if (acc->cfg.transport_id != PJSUA_INVALID_ID) {	pjsip_tpselector tp_sel;	pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);	pjsip_dlg_set_transport(dlg, &tp_sel);    }    /* Set route-set */    if (!pj_list_empty(&acc->route_set)) {	pjsip_dlg_set_route_set(dlg, &acc->route_set);    }    /* Set credentials */    if (acc->cred_cnt) {	pjsip_auth_clt_set_credentials( &dlg->auth_sess, 					acc->cred_cnt, acc->cred);    }    pjsip_evsub_set_mod_data(buddy->sub, pjsua_var.mod.id, buddy);    status = pjsip_pres_initiate(buddy->sub, -1, &tdata);    if (status != PJ_SUCCESS) {	pjsip_pres_terminate(buddy->sub, PJ_FALSE);	buddy->sub = NULL;	pjsua_perror(THIS_FILE, "Unable to create initial SUBSCRIBE", 		     status);	return;    }    pjsua_process_msg_data(tdata, NULL);    status = pjsip_pres_send_request(buddy->sub, tdata);    if (status != PJ_SUCCESS) {	pjsip_pres_terminate(buddy->sub, PJ_FALSE);	buddy->sub = NULL;	pjsua_perror(THIS_FILE, "Unable to send initial SUBSCRIBE", 		     status);	return;    }}/* It does what it says... */static void unsubscribe_buddy_presence(unsigned index){    pjsua_buddy *buddy;    pjsip_tx_data *tdata;    pj_status_t status;    buddy = &pjsua_var.buddy[index];    if (buddy->sub == NULL)	return;    if (pjsip_evsub_get_state(buddy->sub) == PJSIP_EVSUB_STATE_TERMINATED) {	pjsua_var.buddy[index].sub = NULL;	return;    }    status = pjsip_pres_initiate( buddy->sub, 0, &tdata);    if (status == PJ_SUCCESS) {	pjsua_process_msg_data(tdata, NULL);	status = pjsip_pres_send_request( buddy->sub, tdata );    }    if (status != PJ_SUCCESS) {	pjsip_pres_terminate(buddy->sub, PJ_FALSE);	buddy->sub = NULL;	pjsua_perror(THIS_FILE, "Unable to unsubscribe presence", 		     status);    }}/* It does what it says.. */static void refresh_client_subscriptions(void){    unsigned i;    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {	if (!pjsua_var.buddy[i].uri.slen)	    continue;	if (pjsua_var.buddy[i].monitor && !pjsua_var.buddy[i].sub) {	    subscribe_buddy_presence(i);	} else if (!pjsua_var.buddy[i].monitor && pjsua_var.buddy[i].sub) {	    unsubscribe_buddy_presence(i);	}    }}/* * Init presence */pj_status_t pjsua_pres_init(){    unsigned i;    pj_status_t status;    status = pjsip_endpt_register_module( pjsua_var.endpt, &mod_pjsua_pres);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to register pjsua presence module", 		     status);    }    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {	reset_buddy(i);    }    return status;}/* * Start presence subsystem. */pj_status_t pjsua_pres_start(void){    /* Nothing to do (is it?) */    return PJ_SUCCESS;}/* * Refresh presence subscriptions */void pjsua_pres_refresh(){    unsigned i;    refresh_client_subscriptions();    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {	if (pjsua_var.acc[i].valid)	    refresh_server_subscription(i);    }}/* * Shutdown presence. */void pjsua_pres_shutdown(void){    unsigned i;    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {	if (!pjsua_var.acc[i].valid)	    continue;	pjsua_pres_delete_acc(i);    }    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {	pjsua_var.buddy[i].monitor = 0;    }    pjsua_pres_refresh();}

⌨️ 快捷键说明

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