/* Create client publish session */ pj_status_t SIPPresence::publish(SIPPresence *pres) { pj_status_t status; const pj_str_t STR_PRESENCE = CONST_PJ_STR("presence"); SIPAccount * acc = pres->getAccount(); pjsip_endpoint *endpt = ((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint(); /* Create and init client publication session */ /* Create client publication */ status = pjsip_publishc_create(endpt, &my_publish_opt, pres, &publish_cb, &pres->publish_sess_); if (status != PJ_SUCCESS) { pres->publish_sess_ = NULL; ERROR("Failed to create a publish seesion."); return status; } /* Initialize client publication */ pj_str_t from = pj_strdup3(pres->pool_, acc->getFromUri().c_str()); status = pjsip_publishc_init(pres->publish_sess_, &STR_PRESENCE, &from, &from, &from, 0xFFFF); if (status != PJ_SUCCESS) { ERROR("Failed to init a publish session"); pres->publish_sess_ = NULL; return status; } /* Add credential for authentication */ if (acc->hasCredentials() and pjsip_publishc_set_credentials(pres->publish_sess_, acc->getCredentialCount(), acc->getCredInfo()) != PJ_SUCCESS) { ERROR("Could not initialize credentials for invite session authentication"); return status; } /* Set route-set */ // FIXME: is this really necessary? pjsip_regc *regc = acc->getRegistrationInfo(); if (regc and acc->hasServiceRoute()) pjsip_regc_set_route_set(regc, sip_utils::createRouteSet(acc->getServiceRoute(), pres->getPool())); /* Send initial PUBLISH request */ status = send_publish(pres); if (status != PJ_SUCCESS) return status; return PJ_SUCCESS; }
/* Update server subscription (e.g. when our online status has changed) */ void pjsua_pres_update_acc(int acc_id, pj_bool_t force) { 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); /* Only send NOTIFY once subscription is active. Some subscriptions * may still be in NULL (when app is adding a new buddy while in the * on_incoming_subscribe() callback) or PENDING (when user approval is * being requested) state and we don't send NOTIFY to these subs until * the user accepted the request. */ if (pjsip_evsub_get_state(uapres->sub)==PJSIP_EVSUB_STATE_ACTIVE && (force || pres_status.info[0].basic_open != acc->online_status)) { pres_status.info[0].basic_open = acc->online_status; pj_memcpy(&pres_status.info[0].rpid, &acc->rpid, sizeof(pjrpid_element)); 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 (force || acc->publish_state != acc->online_status) { send_publish(acc_id, PJ_TRUE); } } }
/* 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, PJSUA_PRES_TIMER); if (status != PJ_SUCCESS) { acc->publish_sess = NULL; return status; } /* Add credential for authentication */ if (acc->cred_cnt) { 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; }
/* 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 }; pjsua_srv_pres *next; pjsip_tx_data *tdata; next = uapres->next; 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 = 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; } }
void publ_cback_func(struct cell *t, int type, struct tmcb_params *ps) { struct hdr_field* hdr= NULL; struct sip_msg* msg= NULL; ua_pres_t* presentity= NULL; ua_pres_t* db_presentity= NULL; ua_pres_t* hentity= NULL; int found = 0; int size= 0; unsigned int lexpire= 0; str etag; unsigned int hash_code; db1_res_t *res=NULL; ua_pres_t dbpres; str pres_uri={0,0}, watcher_uri={0,0}, extra_headers={0,0}; int end_transaction = 1; memset(&dbpres, 0, sizeof(dbpres)); dbpres.pres_uri = &pres_uri; dbpres.watcher_uri = &watcher_uri; dbpres.extra_headers = &extra_headers; if (dbmode == PUA_DB_ONLY && pua_dbf.start_transaction) { if (pua_dbf.start_transaction(pua_db, db_table_lock) < 0) { LM_ERR("in start_transaction\n"); goto error; } } if(ps->param== NULL|| *ps->param== NULL) { LM_ERR("NULL callback parameter\n"); goto error; } hentity= (ua_pres_t*)(*ps->param); msg= ps->rpl; if(msg == NULL) { LM_ERR("no reply message found\n "); goto error; } if(msg== FAKED_REPLY) { LM_DBG("FAKED_REPLY\n"); goto done; } hash_code= core_hash(hentity->pres_uri, NULL, HASH_SIZE); if( ps->code>= 300 ) { find_and_delete_record(hentity, hash_code); if(ps->code== 412 && hentity->body && hentity->flag!= MI_PUBLISH && hentity->flag!= MI_ASYN_PUBLISH) { /* sent a PUBLISH within a dialog that no longer exists * send again an intial PUBLISH */ LM_DBG("received a 412 reply- try again to send PUBLISH\n"); publ_info_t publ; memset(&publ, 0, sizeof(publ_info_t)); publ.pres_uri= hentity->pres_uri; publ.body= hentity->body; if(hentity->desired_expires== 0) publ.expires= -1; else if(hentity->desired_expires<= (int)time(NULL)) publ.expires= 0; else publ.expires= hentity->desired_expires- (int)time(NULL)+ 3; publ.source_flag|= hentity->flag; publ.event|= hentity->event; publ.content_type= hentity->content_type; publ.id= hentity->id; publ.extra_headers= hentity->extra_headers; publ.outbound_proxy = hentity->outbound_proxy; publ.cb_param= hentity->cb_param; if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction) { if (pua_dbf.end_transaction(pua_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } end_transaction = 0; if(send_publish(&publ)< 0) { LM_ERR("when trying to send PUBLISH\n"); goto error; } } goto done; } /* code >= 300 */ if( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("parsing headers\n"); goto error; } if(msg->expires== NULL || msg->expires->body.len<= 0) { LM_ERR("No Expires header found\n"); goto error; } if (!msg->expires->parsed && (parse_expires(msg->expires) < 0)) { LM_ERR("cannot parse Expires header\n"); goto error; } lexpire = ((exp_body_t*)msg->expires->parsed)->val; LM_DBG("lexpire= %u\n", lexpire); hdr = msg->headers; while (hdr!= NULL) { if(cmp_hdrname_strzn(&hdr->name, "SIP-ETag",8)==0 ) { found = 1; break; } hdr = hdr->next; } if(found== 0) /* must find SIP-Etag header field in 200 OK msg*/ { LM_ERR("no SIP-ETag header field found\n"); goto error; } etag= hdr->body; LM_DBG("completed with status %d [contact:%.*s]\n", ps->code, hentity->pres_uri->len, hentity->pres_uri->s); if (lexpire == 0) { find_and_delete_record(hentity, hash_code); goto done; } if (hentity->etag.s) { if (pua_dbf.affected_rows != NULL || dbmode != PUA_DB_ONLY) { if (find_and_update_record(hentity, hash_code, lexpire, &etag) > 0) goto done; } else if ((db_presentity = get_record_puadb(hentity->id, &hentity->etag, &dbpres, &res)) != NULL) { update_record_puadb(hentity, lexpire, &etag); goto done; } } size= sizeof(ua_pres_t)+ sizeof(str)+ (hentity->pres_uri->len+ hentity->tuple_id.len + hentity->id.len)* sizeof(char); if(hentity->extra_headers) size+= sizeof(str)+ hentity->extra_headers->len* sizeof(char); presentity= (ua_pres_t*)shm_malloc(size); if(presentity== NULL) { LM_ERR("no more share memory\n"); goto error; } memset(presentity, 0, size); size= sizeof(ua_pres_t); presentity->pres_uri= (str*)((char*)presentity+ size); size+= sizeof(str); presentity->pres_uri->s= (char*)presentity+ size; memcpy(presentity->pres_uri->s, hentity->pres_uri->s, hentity->pres_uri->len); presentity->pres_uri->len= hentity->pres_uri->len; size+= hentity->pres_uri->len; presentity->tuple_id.s= (char*)presentity+ size; memcpy(presentity->tuple_id.s, hentity->tuple_id.s, hentity->tuple_id.len); presentity->tuple_id.len= hentity->tuple_id.len; size+= presentity->tuple_id.len; presentity->id.s=(char*)presentity+ size; memcpy(presentity->id.s, hentity->id.s, hentity->id.len); presentity->id.len= hentity->id.len; size+= presentity->id.len; if(hentity->extra_headers) { presentity->extra_headers= (str*)((char*)presentity+ size); size+= sizeof(str); presentity->extra_headers->s= (char*)presentity+ size; memcpy(presentity->extra_headers->s, hentity->extra_headers->s, hentity->extra_headers->len); presentity->extra_headers->len= hentity->extra_headers->len; size+= hentity->extra_headers->len; } presentity->desired_expires= hentity->desired_expires; presentity->expires= lexpire+ (int)time(NULL); presentity->flag|= hentity->flag; presentity->event|= hentity->event; presentity->etag.s= (char*)shm_malloc(etag.len* sizeof(char)); if(presentity->etag.s== NULL) { LM_ERR("No more share memory\n"); goto error; } memcpy(presentity->etag.s, etag.s, etag.len); presentity->etag.len= etag.len; if (dbmode==PUA_DB_ONLY) { insert_record_puadb(presentity); } else { lock_get(&HashT->p_records[hash_code].lock); insert_htable(presentity, hash_code); lock_release(&HashT->p_records[hash_code].lock); } LM_DBG("Inserted record\n"); done: if(hentity->ua_flag == REQ_OTHER) { run_pua_callbacks(hentity, msg); } if(*ps->param) { shm_free(*ps->param); *ps->param= NULL; } if(dbmode==PUA_DB_ONLY && presentity) { shm_free(presentity->etag.s); shm_free(presentity); } if (res) free_results_puadb(res); if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction && end_transaction) { if (pua_dbf.end_transaction(pua_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } return; error: if(ps->param && *ps->param) { shm_free(*ps->param); *ps->param= NULL; } if(presentity) shm_free(presentity); if (res) free_results_puadb(res); if (dbmode == PUA_DB_ONLY && pua_dbf.abort_transaction) { if (pua_dbf.abort_transaction(pua_db) < 0) LM_ERR("in abort_transaction\n"); } return; }