pj_status_t InstantMessaging::sip_send (pjsip_inv_session *session, std::string& id, const std::string& text)
{

    pjsip_method msg_method;
    const pj_str_t type =  STR_TEXT;
    const pj_str_t subtype = STR_PLAIN;
    pjsip_tx_data *tdata;
    pj_status_t status;
    pjsip_dialog* dialog;
    pj_str_t message;

    msg_method.id = PJSIP_OTHER_METHOD;
    msg_method.name = METHOD_NAME;

    // Get the dialog associated to the call
    dialog = session->dlg;
    // Convert the text into a format readable by pjsip

    message = pj_str ( (char*) text.c_str ());

    // Must lock dialog
    pjsip_dlg_inc_lock (dialog);

    // Create the message request
    status = pjsip_dlg_create_request (dialog, &msg_method, -1, &tdata);
    PJ_ASSERT_RETURN (status == PJ_SUCCESS, 1);

    // Attach "text/plain" body
    tdata->msg->body = pjsip_msg_body_create (tdata->pool, &type, &subtype, &message);

    // Create the Require header to handle recipient-list Content-Disposition type
    // pjsip_generic_string_hdr reqhdr;
    // pj_str_t reqhname = pj_str ("Require");
    // pj_str_t reqhvalue = pj_str ("recipient-list");

    // Create the Content-Type header to handle multipart/mixed and boundary MIME types
    // pj_str_t ctype = pj_str ("Content-Type");
    // pj_str_t sctype = pj_str ("ctype"); // small version of the header name
    // ctypehdr = pjsip_msg_find_hdr_by_names (tdata->msg, &ctype, &sctype, NULL);
    // pjsip_generic_string_hdr ctypehdr;
    // pj_str_t ctypehname = pj_str ("Content-Type");
    // pj_str_t ctypehvalue = pj_str ("multipart/mixed;boundary=\"boundary\"");

    // Add headers to the message
    // pjsip_generic_string_hdr_init2 (&reqhdr, &reqhname, &reqhvalue);
    // pj_list_push_back (& (tdata->msg->hdr), (pjsip_hdr*) (&reqhdr));
    // pj_list_push_back (& (tdata->msg->hdr), (pjsip_hdr*) (&ctypehdr));

    // Send the request
    status = pjsip_dlg_send_request (dialog, tdata, -1, NULL);
    // PJ_ASSERT_RETURN (status == PJ_SUCCESS, 1);

    // Done
    pjsip_dlg_dec_lock (dialog);

    // Archive the message
    this->saveMessage (text, "Me", id);

    return PJ_SUCCESS;
}
Exemple #2
0
/*
 * Call this function to create request to initiate REFER subscription.
 *
 */
PJ_DEF(pj_status_t) pjsip_xfer_initiate( pjsip_evsub *sub,
					 const pj_str_t *refer_to_uri,
					 pjsip_tx_data **p_tdata)
{
    pjsip_xfer *xfer;
    const pj_str_t refer_to = { "Refer-To", 8};
    pjsip_tx_data *tdata;
    pjsip_generic_string_hdr *hdr;
    pj_status_t status;

    /* sub and p_tdata argument must be valid.  */
    PJ_ASSERT_RETURN(sub && p_tdata, PJ_EINVAL);


    /* Get the xfer object. */
    xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
    PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);

    /* refer_to_uri argument MAY be NULL for subsequent REFER requests,
     * but it MUST be specified in the first REFER.
     */
    PJ_ASSERT_RETURN((refer_to_uri || xfer->refer_to_uri.slen), PJ_EINVAL);

    /* Lock dialog. */
    pjsip_dlg_inc_lock(xfer->dlg);

    /* Create basic REFER request */
    status = pjsip_evsub_initiate(sub, pjsip_get_refer_method(), -1, 
				  &tdata);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Save Refer-To URI. */
    if (refer_to_uri == NULL) {
	refer_to_uri = &xfer->refer_to_uri;
    } else {
	pj_strdup(xfer->dlg->pool, &xfer->refer_to_uri, refer_to_uri);
    }

    /* Create and add Refer-To header. */
    hdr = pjsip_generic_string_hdr_create(tdata->pool, &refer_to,
					  refer_to_uri);
    if (!hdr) {
	pjsip_tx_data_dec_ref(tdata);
	status = PJ_ENOMEM;
	goto on_return;
    }

    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);


    /* Done. */
    *p_tdata = tdata;

    status = PJ_SUCCESS;

on_return:
    pjsip_dlg_dec_lock(xfer->dlg);
    return status;
}
Exemple #3
0
/*
 * Create client subscription.
 */
PJ_DEF(pj_status_t) pjsip_pres_create_uac( pjsip_dialog *dlg,
					   const pjsip_evsub_user *user_cb,
					   unsigned options,
					   pjsip_evsub **p_evsub )
{
    pj_status_t status;
    pjsip_pres *pres;
    pjsip_evsub *sub;

    PJ_ASSERT_RETURN(dlg && p_evsub, PJ_EINVAL);

    pjsip_dlg_inc_lock(dlg);

    /* Create event subscription */
    status = pjsip_evsub_create_uac( dlg,  &pres_user, &STR_PRESENCE, 
				     options, &sub);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Create presence */
    pres = pj_pool_zalloc(dlg->pool, sizeof(pjsip_pres));
    pres->dlg = dlg;
    pres->sub = sub;
    if (user_cb)
	pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user));

    /* Attach to evsub */
    pjsip_evsub_set_mod_data(sub, mod_presence.id, pres);

    *p_evsub = sub;

on_return:
    pjsip_dlg_dec_lock(dlg);
    return status;
}
/*
 * Create NOTIFY that reflect current state.
 */
PJ_DEF(pj_status_t) pjsip_mwi_current_notify( pjsip_evsub *sub,
					      pjsip_tx_data **p_tdata )
{
    pjsip_mwi *mwi;
    pjsip_tx_data *tdata;
    pj_status_t status;
    
    /* Check arguments. */
    PJ_ASSERT_RETURN(sub && p_tdata, PJ_EINVAL);

    /* Get the mwi object. */
    mwi = (pjsip_mwi*) pjsip_evsub_get_mod_data(sub, mod_mwi.id);
    PJ_ASSERT_RETURN(mwi != NULL, PJ_EINVALIDOP);

    /* Lock object. */
    pjsip_dlg_inc_lock(mwi->dlg);

    /* Create the NOTIFY request. */
    status = pjsip_evsub_current_notify( sub, &tdata);
    if (status != PJ_SUCCESS)
	goto on_return;


    /* Create message body to reflect the mwi status. */
    status = mwi_create_msg_body( mwi, tdata );
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Done. */
    *p_tdata = tdata;

on_return:
    pjsip_dlg_dec_lock(mwi->dlg);
    return status;
}
Exemple #5
0
/*
 * Create transferer (sender of REFER request).
 *
 */
PJ_DEF(pj_status_t) pjsip_xfer_create_uac( pjsip_dialog *dlg,
					   const pjsip_evsub_user *user_cb,
					   pjsip_evsub **p_evsub )
{
    pj_status_t status;
    pjsip_xfer *xfer;
    pjsip_evsub *sub;

    PJ_ASSERT_RETURN(dlg && p_evsub, PJ_EINVAL);

    pjsip_dlg_inc_lock(dlg);

    /* Create event subscription */
    status = pjsip_evsub_create_uac( dlg,  &xfer_user, &STR_REFER, 
				     PJSIP_EVSUB_NO_EVENT_ID, &sub);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Create xfer session */
    xfer = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_xfer);
    xfer->dlg = dlg;
    xfer->sub = sub;
    if (user_cb)
	pj_memcpy(&xfer->user_cb, user_cb, sizeof(pjsip_evsub_user));

    /* Attach to evsub */
    pjsip_evsub_set_mod_data(sub, mod_xfer.id, xfer);

    *p_evsub = sub;

on_return:
    pjsip_dlg_dec_lock(dlg);
    return status;

}
Exemple #6
0
/*
 * For notifier, create NOTIFY request to subscriber, and set the state 
 * of the subscription. 
 */
PJ_DEF(pj_status_t) pjsip_xfer_notify( pjsip_evsub *sub,
				       pjsip_evsub_state state,
				       int xfer_st_code,
				       const pj_str_t *xfer_st_text,
				       pjsip_tx_data **p_tdata)
{
    pjsip_tx_data *tdata;
    pjsip_xfer *xfer;
    pjsip_param *param;
    const pj_str_t reason = { "noresource", 10 };
    char *body;
    int bodylen;
    pjsip_msg_body *msg_body;
    pj_status_t status;
    

    /* Check arguments. */
    PJ_ASSERT_RETURN(sub, PJ_EINVAL);

    /* Get the xfer object. */
    xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
    PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);


    /* Lock object. */
    pjsip_dlg_inc_lock(xfer->dlg);

    /* Create the NOTIFY request. 
     * Note that reason is only used when state is TERMINATED, and
     * the defined termination reason for REFER is "noresource".
     */
    status = pjsip_evsub_notify( sub, state, NULL, &reason, &tdata);
    if (status != PJ_SUCCESS)
	goto on_return;


    /* Check status text */
    if (xfer_st_text==NULL || xfer_st_text->slen==0)
	xfer_st_text = pjsip_get_status_text(xfer_st_code);

    /* Save st_code and st_text, for current_notify() */
    xfer->last_st_code = xfer_st_code;
    pj_strdup(xfer->dlg->pool, &xfer->last_st_text, xfer_st_text);

    /* Create sipfrag content. */
    body = (char*) pj_pool_alloc(tdata->pool, 128);
    bodylen = pj_ansi_snprintf(body, 128, "SIP/2.0 %u %.*s\r\n",
			       xfer_st_code,
			       (int)xfer_st_text->slen,
			       xfer_st_text->ptr);
    PJ_ASSERT_ON_FAIL(bodylen > 0 && bodylen < 128, 
			{status=PJ_EBUG; pjsip_tx_data_dec_ref(tdata); 
			 goto on_return; });
Exemple #7
0
/*
 * Create NOTIFY
 */
PJ_DEF(pj_status_t) pjsip_pres_notify( pjsip_evsub *sub,
				       pjsip_evsub_state state,
				       const pj_str_t *state_str,
				       const pj_str_t *reason,
				       pjsip_tx_data **p_tdata)
{
    pjsip_pres *pres;
    pjsip_tx_data *tdata;
    pj_status_t status;
    
    /* Check arguments. */
    PJ_ASSERT_RETURN(sub, PJ_EINVAL);

    /* Get the presence object. */
    pres = (pjsip_pres*) pjsip_evsub_get_mod_data(sub, mod_presence.id);
    PJ_ASSERT_RETURN(pres != NULL, PJSIP_SIMPLE_ENOPRESENCE);

    /* Must have at least one presence info, unless state is 
     * PJSIP_EVSUB_STATE_TERMINATED. This could happen if subscription
     * has not been active (e.g. we're waiting for user authorization)
     * and remote cancels the subscription.
     */
    PJ_ASSERT_RETURN(state==PJSIP_EVSUB_STATE_TERMINATED ||
		     pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO);


    /* Lock object. */
    pjsip_dlg_inc_lock(pres->dlg);

    /* Create the NOTIFY request. */
    status = pjsip_evsub_notify( sub, state, state_str, reason, &tdata);
    if (status != PJ_SUCCESS)
	goto on_return;


    /* Create message body to reflect the presence status. 
     * Only do this if we have presence status info to send (see above).
     */
    if (pres->status.info_cnt > 0) {
	status = pres_create_msg_body( pres, tdata );
	if (status != PJ_SUCCESS)
	    goto on_return;
    }

    /* Done. */
    *p_tdata = tdata;


on_return:
    pjsip_dlg_dec_lock(pres->dlg);
    return status;
}
/*
 * Create NOTIFY
 */
PJ_DEF(pj_status_t) pjsip_mwi_notify(  pjsip_evsub *sub,
				       pjsip_evsub_state state,
				       const pj_str_t *state_str,
				       const pj_str_t *reason,
				       const pjsip_media_type *mime_type,
				       const pj_str_t *body,
				       pjsip_tx_data **p_tdata)
{
    pjsip_mwi *mwi;
    pjsip_tx_data *tdata;
    pj_status_t status;
    
    /* Check arguments. */
    PJ_ASSERT_RETURN(sub && mime_type && body && p_tdata, PJ_EINVAL);

    /* Get the mwi object. */
    mwi = (pjsip_mwi*) pjsip_evsub_get_mod_data(sub, mod_mwi.id);
    PJ_ASSERT_RETURN(mwi != NULL, PJ_EINVALIDOP);

    /* Lock object. */
    pjsip_dlg_inc_lock(mwi->dlg);

    /* Create the NOTIFY request. */
    status = pjsip_evsub_notify( sub, state, state_str, reason, &tdata);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Update the cached message body */
    if (mime_type || body)
	pj_pool_reset(mwi->body_pool);
    if (mime_type)
	pjsip_media_type_cp(mwi->body_pool, &mwi->mime_type, mime_type);
    if (body)
	pj_strdup(mwi->body_pool, &mwi->body, body);

    /* Create message body */
    status = mwi_create_msg_body( mwi, tdata );
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Done. */
    *p_tdata = tdata;

on_return:
    pjsip_dlg_dec_lock(mwi->dlg);
    return status;
}
Exemple #9
0
/*
 * Create NOTIFY that reflect current state.
 */
PJ_DEF(pj_status_t) pjsip_pres_current_notify( pjsip_evsub *sub,
					       pjsip_tx_data **p_tdata )
{
    pjsip_pres *pres;
    pjsip_tx_data *tdata;
    pj_status_t status;
    
    /* Check arguments. */
    PJ_ASSERT_RETURN(sub, PJ_EINVAL);

    /* Get the presence object. */
    pres = (pjsip_pres*) pjsip_evsub_get_mod_data(sub, mod_presence.id);
    PJ_ASSERT_RETURN(pres != NULL, PJSIP_SIMPLE_ENOPRESENCE);

    /* We may not have a presence info yet, e.g. when we receive SUBSCRIBE
     * to refresh subscription while we're waiting for user authorization.
     */
    //PJ_ASSERT_RETURN(pres->status.info_cnt > 0, 
    //		       PJSIP_SIMPLE_ENOPRESENCEINFO);


    /* Lock object. */
    pjsip_dlg_inc_lock(pres->dlg);

    /* Create the NOTIFY request. */
    status = pjsip_evsub_current_notify( sub, &tdata);
    if (status != PJ_SUCCESS)
	goto on_return;


    /* Create message body to reflect the presence status. */
    if (pres->status.info_cnt > 0) {
	status = pres_create_msg_body( pres, tdata );
	if (status != PJ_SUCCESS)
	    goto on_return;
    }

    /* Done. */
    *p_tdata = tdata;


on_return:
    pjsip_dlg_dec_lock(pres->dlg);
    return status;
}
Exemple #10
0
/*
 * Create NOTIFY
 */
PJ_DEF(pj_status_t) pjsip_pres_notify( pjsip_evsub *sub,
				       pjsip_evsub_state state,
				       const pj_str_t *state_str,
				       const pj_str_t *reason,
				       pjsip_tx_data **p_tdata)
{
    pjsip_pres *pres;
    pjsip_tx_data *tdata;
    pj_status_t status;
    
    /* Check arguments. */
    PJ_ASSERT_RETURN(sub, PJ_EINVAL);

    /* Get the presence object. */
    pres = pjsip_evsub_get_mod_data(sub, mod_presence.id);
    PJ_ASSERT_RETURN(pres != NULL, PJSIP_SIMPLE_ENOPRESENCE);

    /* Must have at least one presence info. */
    PJ_ASSERT_RETURN(pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO);


    /* Lock object. */
    pjsip_dlg_inc_lock(pres->dlg);

    /* Create the NOTIFY request. */
    status = pjsip_evsub_notify( sub, state, state_str, reason, &tdata);
    if (status != PJ_SUCCESS)
	goto on_return;


    /* Create message body to reflect the presence status. */
    status = pres_create_msg_body( pres, tdata );
    if (status != PJ_SUCCESS)
	goto on_return;


    /* Done. */
    *p_tdata = tdata;


on_return:
    pjsip_dlg_dec_lock(pres->dlg);
    return status;
}
Exemple #11
0
/*
 * Create client subscription.
 */
PJ_DEF(pj_status_t) pjsip_pres_create_uac( pjsip_dialog *dlg,
					   const pjsip_evsub_user *user_cb,
					   unsigned options,
					   pjsip_evsub **p_evsub )
{
    pj_status_t status;
    pjsip_pres *pres;
    char obj_name[PJ_MAX_OBJ_NAME];
    pjsip_evsub *sub;

    PJ_ASSERT_RETURN(dlg && p_evsub, PJ_EINVAL);

    pjsip_dlg_inc_lock(dlg);

    /* Create event subscription */
    status = pjsip_evsub_create_uac( dlg,  &pres_user, &STR_PRESENCE, 
				     options, &sub);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Create presence */
    pres = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_pres);
    pres->dlg = dlg;
    pres->sub = sub;
    if (user_cb)
	pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user));

    pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "pres%p", dlg->pool);
    pres->status_pool = pj_pool_create(dlg->pool->factory, obj_name, 
				       512, 512, NULL);
    pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "tmpres%p", dlg->pool);
    pres->tmp_pool = pj_pool_create(dlg->pool->factory, obj_name, 
				    512, 512, NULL);

    /* Attach to evsub */
    pjsip_evsub_set_mod_data(sub, mod_presence.id, pres);

    *p_evsub = sub;

on_return:
    pjsip_dlg_dec_lock(dlg);
    return status;
}
Exemple #12
0
/* make call */
void make_call(char *uri, pj_bool_t with_offer)
{
    pj_str_t local = pj_str("sip:localhost" PORT_STR);
    pj_str_t remote = pj_str(uri);
    pj_status_t status;

    status = pjsip_dlg_create_uac(pjsip_ua_instance(),
				  &local, &local, &remote, &remote, &dlg);
    pj_assert(status == PJ_SUCCESS);

    pjsip_dlg_inc_lock(dlg);

    status = pjsip_dlg_add_usage(dlg, &mod_app, NULL);
    pj_assert(status == PJ_SUCCESS);

    pjsip_dlg_inc_session(dlg, &mod_app);

    send_request(&pjsip_invite_method, -1, NULL, with_offer);

    pjsip_dlg_dec_lock(dlg);
}
/*
 * Create client subscription.
 */
PJ_DEF(pj_status_t) pjsip_mwi_create_uac( pjsip_dialog *dlg,
					  const pjsip_evsub_user *user_cb,
					  unsigned options,
					  pjsip_evsub **p_evsub )
{
    pj_status_t status;
    pjsip_mwi *mwi;
    pjsip_evsub *sub;

    PJ_ASSERT_RETURN(dlg && p_evsub, PJ_EINVAL);

    PJ_UNUSED_ARG(options);

    pjsip_dlg_inc_lock(dlg);

    /* Create event subscription */
    status = pjsip_evsub_create_uac( dlg,  &mwi_user, &STR_MWI, 
				     options, &sub);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Create mwi */
    mwi = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_mwi);
    mwi->dlg = dlg;
    mwi->sub = sub;
    if (user_cb)
	pj_memcpy(&mwi->user_cb, user_cb, sizeof(pjsip_evsub_user));

    /* Attach to evsub */
    pjsip_evsub_set_mod_data(sub, mod_mwi.id, mwi);

    *p_evsub = sub;

on_return:
    pjsip_dlg_dec_lock(dlg);
    return status;
}
Exemple #14
0
/* Timer callback. When the timer is fired, it can be time to refresh
 * the session if UA is the refresher, otherwise it is time to end 
 * the session.
 */
void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
{
    pjsip_inv_session *inv = (pjsip_inv_session*) entry->user_data;
    pjsip_tx_data *tdata = NULL;
    pj_status_t status;
    pj_bool_t as_refresher;

    pj_assert(inv);

    PJ_UNUSED_ARG(timer_heap);

    /* When there is a pending INVITE transaction, delay/reschedule this timer
     * for five seconds to cover the case that pending INVITE fails and the
     * previous session is still active. If the pending INVITE is successful, 
     * timer state will be updated, i.e: restarted or stopped.
     */
    if (inv->invite_tsx != NULL) {
	pj_time_val delay = {5};

	inv->timer->timer.id = 1;
	pjsip_endpt_schedule_timer(inv->dlg->endpt, &inv->timer->timer, &delay);
	return;
    }

    /* Lock dialog. */
    pjsip_dlg_inc_lock(inv->dlg);

    /* Check our role */
    as_refresher = 
	(inv->timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) ||
	(inv->timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS);

    /* Do action based on role, refresher or refreshee */
    if (as_refresher) {

	pj_time_val now;

	/* Refresher, refresh the session */
	if (inv->timer->use_update) {
	    /* Create UPDATE request without offer */
	    status = pjsip_inv_update(inv, NULL, NULL, &tdata);
	} else {
	    /* Create re-INVITE without modifying session */
	    pjsip_msg_body *body;
	    const pjmedia_sdp_session *offer = NULL;

	    pj_assert(pjmedia_sdp_neg_get_state(inv->neg) == 
		      PJMEDIA_SDP_NEG_STATE_DONE);

	    status = pjsip_inv_invite(inv, &tdata);
	    if (status == PJ_SUCCESS)
		status = pjmedia_sdp_neg_send_local_offer(inv->pool_prov, 
							  inv->neg, &offer);
	    if (status == PJ_SUCCESS)
		status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
	    if (status == PJ_SUCCESS) {
		status = pjsip_create_sdp_body(tdata->pool, 
					(pjmedia_sdp_session*)offer, &body);
		tdata->msg->body = body;
	    }
	}

	pj_gettimeofday(&now);
	PJ_LOG(4, (inv->pool->obj_name, 
		   "Refresh session after %ds (expiration period=%ds)",
		   (now.sec-inv->timer->last_refresh.sec),
		   inv->timer->setting.sess_expires));
    } else {
	
	pj_time_val now;

	/* Refreshee, terminate the session */
	status = pjsip_inv_end_session(inv, PJSIP_SC_REQUEST_TIMEOUT, 
				       NULL, &tdata);

	pj_gettimeofday(&now);
	PJ_LOG(3, (inv->pool->obj_name, 
		   "No session refresh received after %ds "
		   "(expiration period=%ds), stopping session now!",
		   (now.sec-inv->timer->last_refresh.sec),
		   inv->timer->setting.sess_expires));
    }

    /* Unlock dialog. */
    pjsip_dlg_dec_lock(inv->dlg);

    /* Send message, if any */
    if (tdata && status == PJ_SUCCESS) {
	status = pjsip_inv_send_msg(inv, tdata);
    }

    /* Print error message, if any */
    if (status != PJ_SUCCESS) {
	char errmsg[PJ_ERR_MSG_SIZE];

	if (tdata)
	    pjsip_tx_data_dec_ref(tdata);

	pj_strerror(status, errmsg, sizeof(errmsg));
	PJ_LOG(2, (inv->pool->obj_name, "Session timer fails in %s session, "
					"err code=%d (%s)",
					(as_refresher? "refreshing" : 
						       "terminating"),
					status, errmsg));					
    }
}
Exemple #15
0
/* It does what it says.. */
static void subscribe_buddy_presence(unsigned index)
{
    pj_pool_t *tmp_pool = NULL;
    pjsua_buddy *buddy;
    int acc_id;
    pjsua_acc *acc;
    pj_str_t contact;
    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 unless one is already set in
     * the account
     */
    if (acc->contact.slen) {
	contact = acc->contact;
    } else {
	tmp_pool = pjsua_pool_create("tmpbuddy", 512, 256);

	status = pjsua_acc_create_uac_contact(tmp_pool, &contact,
					      acc_id, &buddy->uri);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "Unable to generate Contact header", 
		         status);
	    pj_pool_release(tmp_pool);
	    return;
	}
    }

    /* Create UAC dialog */
    status = pjsip_dlg_create_uac( pjsip_ua_instance(), 
				   &acc->cfg.id,
				   &contact,
				   &buddy->uri,
				   NULL, &buddy->dlg);
    if (status != PJ_SUCCESS) {
	pjsua_perror(THIS_FILE, "Unable to create dialog", 
		     status);
	if (tmp_pool) pj_pool_release(tmp_pool);
	return;
    }

    /* Increment the dialog's lock otherwise when presence session creation
     * fails the dialog will be destroyed prematurely.
     */
    pjsip_dlg_inc_lock(buddy->dlg);

    status = pjsip_pres_create_uac( buddy->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);
	/* This should destroy the dialog since there's no session
	 * referencing it
	 */
	pjsip_dlg_dec_lock(buddy->dlg);
	if (tmp_pool) pj_pool_release(tmp_pool);
	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(buddy->dlg, &tp_sel);
    }

    /* Set route-set */
    if (!pj_list_empty(&acc->route_set)) {
	pjsip_dlg_set_route_set(buddy->dlg, &acc->route_set);
    }

    /* Set credentials */
    if (acc->cred_cnt) {
	pjsip_auth_clt_set_credentials( &buddy->dlg->auth_sess, 
					acc->cred_cnt, acc->cred);
    }

    /* Set authentication preference */
    pjsip_auth_clt_set_prefs(&buddy->dlg->auth_sess, &acc->cfg.auth_pref);

    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_dlg_dec_lock(buddy->dlg);
	if (buddy->sub) {
	    pjsip_pres_terminate(buddy->sub, PJ_FALSE);
	}
	buddy->sub = NULL;
	pjsua_perror(THIS_FILE, "Unable to create initial SUBSCRIBE", 
		     status);
	if (tmp_pool) pj_pool_release(tmp_pool);
	return;
    }

    pjsua_process_msg_data(tdata, NULL);

    status = pjsip_pres_send_request(buddy->sub, tdata);
    if (status != PJ_SUCCESS) {
	pjsip_dlg_dec_lock(buddy->dlg);
	if (buddy->sub) {
	    pjsip_pres_terminate(buddy->sub, PJ_FALSE);
	}
	buddy->sub = NULL;
	pjsua_perror(THIS_FILE, "Unable to send initial SUBSCRIBE", 
		     status);
	if (tmp_pool) pj_pool_release(tmp_pool);
	return;
    }

    pjsip_dlg_dec_lock(buddy->dlg);
    if (tmp_pool) pj_pool_release(tmp_pool);
}
Exemple #16
0
/*
 * Create server subscription.
 */
PJ_DEF(pj_status_t) pjsip_pres_create_uas( pjsip_dialog *dlg,
					   const pjsip_evsub_user *user_cb,
					   pjsip_rx_data *rdata,
					   pjsip_evsub **p_evsub )
{
    pjsip_accept_hdr *accept;
    pjsip_event_hdr *event;
    content_type_e content_type = CONTENT_TYPE_NONE;
    pjsip_evsub *sub;
    pjsip_pres *pres;
    char obj_name[PJ_MAX_OBJ_NAME];
    pj_status_t status;

    /* Check arguments */
    PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);

    /* Must be request message */
    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
		     PJSIP_ENOTREQUESTMSG);

    /* Check that request is SUBSCRIBE */
    PJ_ASSERT_RETURN(pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
				      &pjsip_subscribe_method)==0,
		     PJSIP_SIMPLE_ENOTSUBSCRIBE);

    /* Check that Event header contains "presence" */
    event = (pjsip_event_hdr*)
    	    pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_EVENT, NULL);
    if (!event) {
	return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST);
    }
    if (pj_stricmp(&event->event_type, &STR_PRESENCE) != 0) {
	return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_EVENT);
    }

    /* Check that request contains compatible Accept header. */
    accept = (pjsip_accept_hdr*)
    	     pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL);
    if (accept) {
	unsigned i;
	for (i=0; i<accept->count; ++i) {
	    if (pj_stricmp(&accept->values[i], &STR_APP_PIDF_XML)==0) {
		content_type = CONTENT_TYPE_PIDF;
		break;
	    } else
	    if (pj_stricmp(&accept->values[i], &STR_APP_XPIDF_XML)==0) {
		content_type = CONTENT_TYPE_XPIDF;
		break;
	    }
	}

	if (i==accept->count) {
	    /* Nothing is acceptable */
	    return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE);
	}

    } else {
	/* No Accept header.
	 * Treat as "application/pidf+xml"
	 */
	content_type = CONTENT_TYPE_PIDF;
    }

    /* Lock dialog */
    pjsip_dlg_inc_lock(dlg);


    /* Create server subscription */
    status = pjsip_evsub_create_uas( dlg, &pres_user, rdata, 0, &sub);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Create server presence subscription */
    pres = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_pres);
    pres->dlg = dlg;
    pres->sub = sub;
    pres->content_type = content_type;
    if (user_cb)
	pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user));

    pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "pres%p", dlg->pool);
    pres->status_pool = pj_pool_create(dlg->pool->factory, obj_name, 
				       512, 512, NULL);
    pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "tmpres%p", dlg->pool);
    pres->tmp_pool = pj_pool_create(dlg->pool->factory, obj_name, 
				    512, 512, NULL);

    /* Attach to evsub */
    pjsip_evsub_set_mod_data(sub, mod_presence.id, pres);

    /* Done: */
    *p_evsub = sub;

on_return:
    pjsip_dlg_dec_lock(dlg);
    return status;
}
PJDialogLock::PJDialogLock(pjsip_dialog* dialog)
    : dialog_(dialog)
{
    pjsip_dlg_inc_lock(dialog_);
}
Exemple #18
0
/* Timer callback. When the timer is fired, it can be time to refresh
 * the session if UA is the refresher, otherwise it is time to end 
 * the session.
 */
static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
{
    pjsip_inv_session *inv = (pjsip_inv_session*) entry->user_data;
    pjsip_tx_data *tdata = NULL;
    pj_status_t status;
    pj_bool_t as_refresher;

    pj_assert(inv);

    PJ_UNUSED_ARG(timer_heap);

    /* Lock dialog. */
    pjsip_dlg_inc_lock(inv->dlg);

    /* Check our role */
    as_refresher =
	(inv->timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) ||
	(inv->timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS);    

    /* Do action based on role(refresher or refreshee). 
     * As refresher:
     * - send refresh, or  
     * - end session if there is no response to the refresh request.
     * As refreshee:
     * - end session if there is no refresh request received.
     */
    if (as_refresher && (entry->id != REFRESHER_EXPIRE_TIMER_ID)) {
	pj_time_val now;

	/* As refresher, reshedule the refresh request on the following:
	 *  - must not send re-INVITE if another INVITE or SDP negotiation
	 *    is in progress.
	 *  - must not send UPDATE with SDP if SDP negotiation is in progress
	 */
	pjmedia_sdp_neg_state neg_state = pjmedia_sdp_neg_get_state(inv->neg);

	inv->timer->timer.id = 0;

	if ( (!inv->timer->use_update && (
			inv->invite_tsx != NULL ||
			neg_state != PJMEDIA_SDP_NEG_STATE_DONE)
             )
	     ||
	     (inv->timer->use_update && inv->timer->with_sdp &&
		     neg_state != PJMEDIA_SDP_NEG_STATE_DONE
	     )
	   )
	{
	    pj_time_val delay = {1, 0};

	    inv->timer->timer.id = 1;
	    pjsip_endpt_schedule_timer(inv->dlg->endpt, &inv->timer->timer,
				       &delay);
	    pjsip_dlg_dec_lock(inv->dlg);
	    return;
	}

	/* Refresher, refresh the session */
	if (inv->timer->use_update) {
	    const pjmedia_sdp_session *offer = NULL;

	    if (inv->timer->with_sdp) {
		pjmedia_sdp_neg_get_active_local(inv->neg, &offer);
	    }
	    status = pjsip_inv_update(inv, NULL, offer, &tdata);
	} else {
	    /* Create re-INVITE without modifying session */
	    pjsip_msg_body *body;
	    const pjmedia_sdp_session *offer = NULL;

	    pj_assert(pjmedia_sdp_neg_get_state(inv->neg) == 
		      PJMEDIA_SDP_NEG_STATE_DONE);

	    status = pjsip_inv_invite(inv, &tdata);
	    if (status == PJ_SUCCESS)
		status = pjmedia_sdp_neg_send_local_offer(inv->pool_prov, 
							  inv->neg, &offer);
	    if (status == PJ_SUCCESS)
		status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
	    if (status == PJ_SUCCESS) {
		status = pjsip_create_sdp_body(tdata->pool, 
					(pjmedia_sdp_session*)offer, &body);
		tdata->msg->body = body;
	    }
	}

	pj_gettimeofday(&now);
	PJ_LOG(4, (inv->pool->obj_name,
		   "Refreshing session after %ds (expiration period=%ds)",
		   (now.sec-inv->timer->last_refresh.sec),
		   inv->timer->setting.sess_expires));
    } else {
	
	pj_time_val now;

	if (as_refresher)
	    inv->timer->expire_timer.id = 0;
	else
	    inv->timer->timer.id = 0;

	/* Terminate the session */
	status = pjsip_inv_end_session(inv, PJSIP_SC_REQUEST_TIMEOUT, 
				       NULL, &tdata);

	pj_gettimeofday(&now);
	PJ_LOG(3, (inv->pool->obj_name, 
		   "No session %s received after %ds "
		   "(expiration period=%ds), stopping session now!",
		   (as_refresher?"refresh response":"refresh"),
		   (now.sec-inv->timer->last_refresh.sec),
		   inv->timer->setting.sess_expires));

    }

    /* Unlock dialog. */
    pjsip_dlg_dec_lock(inv->dlg);

    /* Send message, if any */
    if (tdata && status == PJ_SUCCESS) {
	inv->timer->refresh_tdata = tdata;

	status = pjsip_inv_send_msg(inv, tdata);	
    }

    /* Print error message, if any */
    if (status != PJ_SUCCESS) {
	PJ_PERROR(2, (inv->pool->obj_name, status,
		     "Error in %s session timer",
		     ((as_refresher && entry->id != REFRESHER_EXPIRE_TIMER_ID)? 
		       "refreshing" : "terminating")));
    }
}
Exemple #19
0
/*
 * Create transferee (receiver of REFER request).
 *
 */
PJ_DEF(pj_status_t) pjsip_xfer_create_uas( pjsip_dialog *dlg,
					   const pjsip_evsub_user *user_cb,
					   pjsip_rx_data *rdata,
					   pjsip_evsub **p_evsub )
{
    pjsip_evsub *sub;
    pjsip_xfer *xfer;
    const pj_str_t STR_EVENT = {"Event", 5 };
    pjsip_event_hdr *event_hdr;
    pj_status_t status;

    /* Check arguments */
    PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);

    /* Must be request message */
    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
		     PJSIP_ENOTREQUESTMSG);

    /* Check that request is REFER */
    PJ_ASSERT_RETURN(pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
				      pjsip_get_refer_method())==0,
		     PJSIP_ENOTREFER);

    /* Lock dialog */
    pjsip_dlg_inc_lock(dlg);

    /* The evsub framework expects an Event header in the request,
     * while a REFER request conveniently doesn't have one (pun intended!).
     * So create a dummy Event header.
     */
    if (pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
				   &STR_EVENT, NULL)==NULL)
    {
	event_hdr = pjsip_event_hdr_create(rdata->tp_info.pool);
	event_hdr->event_type = STR_REFER;
	pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr*)event_hdr);
    }

    /* Create server subscription */
    status = pjsip_evsub_create_uas( dlg, &xfer_user, rdata, 
				     PJSIP_EVSUB_NO_EVENT_ID, &sub);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Create server xfer subscription */
    xfer = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_xfer);
    xfer->dlg = dlg;
    xfer->sub = sub;
    if (user_cb)
	pj_memcpy(&xfer->user_cb, user_cb, sizeof(pjsip_evsub_user));

    /* Attach to evsub */
    pjsip_evsub_set_mod_data(sub, mod_xfer.id, xfer);

    /* Done: */
    *p_evsub = sub;

on_return:
    pjsip_dlg_dec_lock(dlg);
    return status;
}
/*
 * Create server subscription.
 */
PJ_DEF(pj_status_t) pjsip_mwi_create_uas( pjsip_dialog *dlg,
					  const pjsip_evsub_user *user_cb,
					  pjsip_rx_data *rdata,
					  pjsip_evsub **p_evsub )
{
    pjsip_accept_hdr *accept;
    pjsip_event_hdr *event;
    pjsip_evsub *sub;
    pjsip_mwi *mwi;
    char obj_name[PJ_MAX_OBJ_NAME];
    pj_status_t status;

    /* Check arguments */
    PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);

    /* Must be request message */
    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
		     PJSIP_ENOTREQUESTMSG);

    /* Check that request is SUBSCRIBE */
    PJ_ASSERT_RETURN(pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
				      &pjsip_subscribe_method)==0,
		     PJSIP_SIMPLE_ENOTSUBSCRIBE);

    /* Check that Event header contains "mwi" */
    event = (pjsip_event_hdr*)
    	    pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_EVENT, NULL);
    if (!event) {
	return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST);
    }
    if (pj_stricmp(&event->event_type, &STR_MWI) != 0) {
	return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_EVENT);
    }

    /* Check that request contains compatible Accept header. */
    accept = (pjsip_accept_hdr*)
    	     pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL);
    if (accept) {
	unsigned i;
	for (i=0; i<accept->count; ++i) {
	    if (pj_stricmp(&accept->values[i], &STR_APP_SIMPLE_SMS)==0) {
		break;
	    }
	}

	if (i==accept->count) {
	    /* Nothing is acceptable */
	    return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE);
	}

    } else {
	/* No Accept header. 
	 * Assume client supports "application/simple-message-summary" 
	*/
    }

    /* Lock dialog */
    pjsip_dlg_inc_lock(dlg);


    /* Create server subscription */
    status = pjsip_evsub_create_uas( dlg, &mwi_user, rdata, 0, &sub);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Create server mwi subscription */
    mwi = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_mwi);
    mwi->dlg = dlg;
    mwi->sub = sub;
    if (user_cb)
	pj_memcpy(&mwi->user_cb, user_cb, sizeof(pjsip_evsub_user));

    pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "mwibd%p", dlg->pool);
    mwi->body_pool = pj_pool_create(dlg->pool->factory, obj_name, 
				    512, 512, NULL);

    /* Attach to evsub */
    pjsip_evsub_set_mod_data(sub, mod_mwi.id, mwi);

    /* Done: */
    *p_evsub = sub;

on_return:
    pjsip_dlg_dec_lock(dlg);
    return status;
}