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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; });
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* 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; }
/* 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)); } }
/* 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); }
/* * 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_); }
/* 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"))); } }
/* * 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; }