/* NB: free returned result str when done from shm */ str get_presentity_from_subscriber_dialog(str *callid, str *to_tag, str *from_tag) { subs_t* s; unsigned int hash_code = 0; str pres_uri = {0,0}; hash_code = core_hash(callid, to_tag, sub_dialog_hash_size); /* search the record in hash table */ lock_get(&sub_dialog_table[hash_code].lock); LM_DBG("Searching sub dialog hash info with call_id: <%.*s> and ttag <%.*s> and ftag <%.*s> and hash code <%d>", callid->len, callid->s, to_tag->len, to_tag->s, from_tag->len, from_tag->s, hash_code); s = pres_search_shtable(sub_dialog_table, *callid, *to_tag, *from_tag, hash_code); if(s== NULL) { LM_DBG("Subscriber dialog record not found in hash table\n"); lock_release(&sub_dialog_table[hash_code].lock); return pres_uri; } //make copy of pres_uri pres_uri.s = (char*) shm_malloc(s->pres_uri.len); if (pres_uri.s==0) { LM_ERR("no more shm mem\n"); return pres_uri; } memcpy(pres_uri.s, s->pres_uri.s, s->pres_uri.len); pres_uri.len = s->pres_uri.len; lock_release(&sub_dialog_table[hash_code].lock); LM_DBG("Found subscriber dialog record in hash table with pres_uri: [%.*s]", pres_uri.len, pres_uri.s); return pres_uri; }
void get_dialog_from_did(char* did, subs_t **dialog, unsigned int *hash_code) { str callid, to_tag, from_tag; subs_t* s; *dialog= NULL; /* search the subscription in rlsubs_table*/ if( parse_rlsubs_did(did, &callid, &from_tag, &to_tag)< 0) { LM_ERR("bad format for resource list Subscribe dialog " "indentifier(rlsubs did)\n"); return; } if (dbmode == RLS_DB_ONLY) { *dialog = get_dialog_notify_rlsdb(callid,to_tag,from_tag); if(*dialog==NULL) { LM_INFO("record not retrieved from db [rlsubs_did]= %s\n", did); return; } } else { *hash_code= core_hash(&callid, &to_tag, hash_size); lock_get(&rls_table[*hash_code].lock); s= pres_search_shtable(rls_table,callid,to_tag,from_tag,*hash_code); if(s== NULL) { LM_INFO("record not found in hash_table [rlsubs_did]= %s\n", did); lock_release(&rls_table[*hash_code].lock); return; } /* save dialog info */ *dialog= pres_copy_subs(s, PKG_MEM_TYPE); if(*dialog== NULL) { LM_ERR("while copying subs_t structure\n"); lock_release(&rls_table[*hash_code].lock); return; } } if ((*dialog)->expires < (int)time(NULL)) (*dialog)->expires = 0; else (*dialog)->expires -= (int)time(NULL); if (dbmode != RLS_DB_ONLY) lock_release(&rls_table[*hash_code].lock); }
int remove_expired_rlsubs( subs_t* subs, unsigned int hash_code) { subs_t* s, *ps; int found= 0; if(subs->expires!=0) return 0; if (dbmode == RLS_DB_ONLY) { LM_ERR( "remove_expired_rlsubs called in RLS_DB_ONLY mode\n" ); } /* search the record in hash table */ lock_get(&rls_table[hash_code].lock); s= pres_search_shtable(rls_table, subs->callid, subs->to_tag, subs->from_tag, hash_code); if(s== NULL) { LM_DBG("record not found in hash table\n"); lock_release(&rls_table[hash_code].lock); return -1; } /* delete record from hash table */ ps= rls_table[hash_code].entries; while(ps->next) { if(ps->next== s) { found= 1; break; } ps= ps->next; } if(found== 0) { LM_ERR("record not found\n"); lock_release(&rls_table[hash_code].lock); return -1; } ps->next= s->next; shm_free(s); lock_release(&rls_table[hash_code].lock); return 0; }
/*! * \brief Expires timer for NO_DB db_mode * * Expires timer for NO_DB db_mode, process all contacts from * the record, delete the expired ones from memory. * \param _r processed record */ static inline void nodb_timer(impurecord_t* _r) { ucontact_t* ptr, *t; unsigned int hash_code = 0; reg_subscriber *s; subs_t* sub_dialog; get_act_time(); s = _r->shead; LM_DBG("Checking validity of IMPU: <%.*s> registration subscriptions\n", _r->public_identity.len, _r->public_identity.s); while (s) { if (!valid_subscriber(s)) { LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> expired and removed.\n", s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s); delete_subscriber(_r, s); } else { LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> is valid and expires in %d seconds.\n", s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s, (unsigned int) (s->expires - time(NULL))); hash_code = core_hash(&s->call_id, &s->to_tag, sub_dialog_hash_size); LM_DBG("Hash size: <%i>", sub_dialog_hash_size); LM_DBG("Searching sub dialog hash info with call_id: <%.*s> and ttag <%.*s> ftag <%.*s> and hash code <%i>", s->call_id.len, s->call_id.s, s->to_tag.len, s->to_tag.s, s->from_tag.len, s->from_tag.s, hash_code); /* search the record in hash table */ lock_get(&sub_dialog_table[hash_code].lock); sub_dialog= pres_search_shtable(sub_dialog_table, s->call_id, s->to_tag, s->from_tag, hash_code); if(sub_dialog== NULL) { LM_ERR("DBG:registrar_timer: Subscription has no dialog record in hash table\n"); }else { LM_DBG("DBG:registrar_timer: Subscription has dialog record in hash table with presentity uri <%.*s>\n", sub_dialog->pres_uri.len, sub_dialog->pres_uri.s); } lock_release(&sub_dialog_table[hash_code].lock); } s = s->next; } ptr = _r->contacts; LM_DBG("Checking validity of IMPU: <%.*s> contacts\n", _r->public_identity.len, _r->public_identity.s); while (ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(ptr->cbs, UL_CONTACT_EXPIRE)) run_ul_callbacks(ptr->cbs, UL_CONTACT_EXPIRE, _r, ptr); if (exists_ulcb_type(_r->cbs, UL_IMPU_EXPIRE_CONTACT)) { run_ul_callbacks(_r->cbs, UL_IMPU_EXPIRE_CONTACT, _r, ptr); } LM_DBG("Binding '%.*s','%.*s' has expired\n", ptr->aor->len, ZSW(ptr->aor->s), ptr->c.len, ZSW(ptr->c.s)); t = ptr; ptr = ptr->next; if (db_mode == WRITE_THROUGH && db_delete_ucontact(_r, t) != 0) { LM_ERR("error removing contact from DB [%.*s]... will still remove from memory\n", t->c.len, t->c.s); } mem_delete_ucontact(_r, t); update_stat(_r->slot->d->expires, 1); } else { LM_DBG("IMPU:<%.*s> - contact:<%.*s> is valid and expires in %d seconds\n", _r->public_identity.len, _r->public_identity.s, ptr->c.len, ptr->c.s, (unsigned int) (ptr->expires - time(NULL))); ptr = ptr->next; } } }
/*! * \brief Expires timer for NO_DB db_mode * * Expires timer for NO_DB db_mode, process all contacts from * the record, delete the expired ones from memory. * \param _r processed record */ static inline void process_impurecord(impurecord_t* _r) { int flag, mustdeleteimpu = 1, n, k; unsigned int sl; ucontact_t* ptr; int hascontacts; udomain_t* _d; reg_subscriber *s; subs_t* sub_dialog; get_act_time(); s = _r->shead; LM_DBG("Checking validity of IMPU: <%.*s> registration subscriptions\n", _r->public_identity.len, _r->public_identity.s); while (s) { if (!valid_subscriber(s, act_time)) { LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> expired and removed.\n", s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s); delete_subscriber(_r, s); } else { LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> is valid and expires in %d seconds.\n", s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s, (unsigned int) (s->expires - time(NULL))); sl = core_hash(&s->call_id, &s->to_tag, sub_dialog_hash_size); LM_DBG("Hash size: <%i>", sub_dialog_hash_size); LM_DBG("Searching sub dialog hash info with call_id: <%.*s> and ttag <%.*s> ftag <%.*s> and hash code <%i>", s->call_id.len, s->call_id.s, s->to_tag.len, s->to_tag.s, s->from_tag.len, s->from_tag.s, sl); /* search the record in hash table */ lock_get(&sub_dialog_table[sl].lock); sub_dialog = pres_search_shtable(sub_dialog_table, s->call_id, s->to_tag, s->from_tag, sl); if (sub_dialog == NULL) { LM_ERR("DBG:registrar_timer: Subscription has no dialog record in hash table\n"); } else { LM_DBG("DBG:registrar_timer: Subscription has dialog record in hash table with presentity uri <%.*s>\n", sub_dialog->pres_uri.len, sub_dialog->pres_uri.s); } lock_release(&sub_dialog_table[sl].lock); mustdeleteimpu = 0; } s = s->next; } LM_DBG("\tPublic Identity %.*s, Barred: [%d], State: [%s]\n", _r->public_identity.len, _r->public_identity.s, _r->barring, get_impu_regstate_as_string(_r->reg_state)); flag = 0; hascontacts = 0; num_contacts_to_expire = 0; for (k = 0; (k < _r->num_contacts) && (k < MAX_CONTACTS_PER_IMPU); k++) { if ((ptr = _r->newcontacts[k])) { flag = 1; if (!VALID_CONTACT(ptr, act_time)) { if (ptr->state == CONTACT_DELETED) { LM_DBG("Contact: <%.*s> has been deleted - unlinking from IMPU\n", ptr->c.len, ptr->c.s); contacts_to_expire[num_contacts_to_expire] = ptr; num_contacts_to_expire++; } else if (ptr->state == CONTACT_EXPIRE_PENDING_NOTIFY) { LM_DBG("Contact: <%.*s> is in state CONTACT_EXPIRE_PENDING_NOTIFY....running callback\n", ptr->c.len, ptr->c.s); if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE_CONTACT)) { LM_DBG("Running callback UL_IMPU_DELETE_CONTACT for contact [%.*s] and impu [%.*s]\n", ptr->c.len, ptr->c.s, _r->public_identity.len, _r->public_identity.s); run_ul_callbacks(_r->cbs, UL_IMPU_DELETE_CONTACT, _r, ptr); } hascontacts = 1; // we do this because the impu must only be deleted if in state deleted.... mustdeleteimpu = 0; } else if (ptr->state == CONTACT_VALID) { LM_DBG("Contact: <%.*s> is in state valid but it has expired.... ignoring as the contact check will set the appropriate action/state\n", ptr->c.len, ptr->c.s); mustdeleteimpu = 0; hascontacts = 1; } else { LM_WARN("Bogus state for contact [%.*s] - state: %d... ignoring", ptr->c.len, ptr->c.s, ptr->state); mustdeleteimpu = 0; hascontacts = 1; } } else { LM_DBG("\t\tContact #%i - %.*s, Ref [%d] (expires in %ld seconds) (State: %d)\n", k, ptr->c.len, ptr->c.s, ptr->ref_count, ptr->expires - act_time, ptr->state); mustdeleteimpu = 0; hascontacts = 1; } } else { LM_WARN("num_contacts and actual data not consistent... .aborting\n"); break; } } if (num_contacts_to_expire > 0) { LM_DBG("\tThere are %d contacts to expire/unlink\n", num_contacts_to_expire); for (n = 0; n < num_contacts_to_expire; n++) { ptr = contacts_to_expire[n]; LM_DBG("\t\texpiring contact %i: [%.*s] in slot [%d]\n", n, contacts_to_expire[n]->c.len, contacts_to_expire[n]->c.s, contacts_to_expire[n]->sl); sl = ptr->sl; lock_contact_slot_i(sl); unlink_contact_from_impu(_r, ptr, 1, 0 /*implicit dereg of contact from IMPU*/); unlock_contact_slot_i(sl); } } if (!flag) LM_DBG("no contacts\n"); if (mustdeleteimpu) { register_udomain("location", &_d); delete_impurecord(_d, &_r->public_identity, _r); } else { if (!hascontacts) { LM_DBG("This impu is not to be deleted but has no contacts - changing state to IMPU_UNREGISTERED\n"); _r->reg_state = IMPU_UNREGISTERED; } } }
/* * function that updates a subscription in hash table * sets reply_code and reply_str in case of error and * if different that server error * */ int update_rlsubs( subs_t* subs, unsigned int hash_code, int* reply_code, str* reply_str) { subs_t* s, *ps; /* search the record in hash table */ lock_get(&rls_table[hash_code].lock); s= pres_search_shtable(rls_table, subs->callid, subs->to_tag, subs->from_tag, hash_code); if(s== NULL) { LM_DBG("record not found in hash table\n"); lock_release(&rls_table[hash_code].lock); return -1; } s->expires= subs->expires+ (int)time(NULL); if(s->db_flag == NO_UPDATEDB_FLAG) s->db_flag= UPDATEDB_FLAG; if( s->remote_cseq>= subs->remote_cseq) { lock_release(&rls_table[hash_code].lock); LM_DBG("stale cseq stored cseq= %d - received cseq= %d\n", s->remote_cseq, subs->remote_cseq); *reply_code = Stale_cseq_code; *reply_str = stale_cseq_rpl; return -1; } s->remote_cseq= subs->remote_cseq; subs->pres_uri.s= (char*)pkg_malloc(s->pres_uri.len* sizeof(char)); if(subs->pres_uri.s== NULL) { ERR_MEM(PKG_MEM_STR); } memcpy(subs->pres_uri.s, s->pres_uri.s, s->pres_uri.len); subs->pres_uri.len= s->pres_uri.len; subs->local_cseq= s->local_cseq; subs->version= s->version; if(s->record_route.s && s->record_route.len) { subs->record_route.s= (char*)pkg_malloc(s->record_route.len); if(subs->record_route.s== NULL) { ERR_MEM(PKG_MEM_STR); } memcpy(subs->record_route.s, s->record_route.s, s->record_route.len); subs->record_route.len= s->record_route.len; } if(subs->expires== 0) { /* delete record from hash table */ ps= rls_table[hash_code].entries; int found= 0; while(ps->next) { if(ps->next== s) { found= 1; break; } ps= ps->next; } if(found== 0) { LM_ERR("record not found\n"); goto error; } ps->next= s->next; shm_free(s); /* delete from rls_presentity table also */ } lock_release(&rls_table[hash_code].lock); return 0; error: lock_release(&rls_table[hash_code].lock); return -1; }
int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2) { struct to_body *pto, *pfrom = NULL; subs_t subs; pres_ev_t* event= NULL; str* contact= NULL; xmlDocPtr doc= NULL; xmlNodePtr service_node= NULL; unsigned int hash_code= 0; event_t* parsed_event; param_t* ev_param= NULL; int init_req; int reply_code; str reply_str; /*** filter: 'For me or for presence server?' */ reply_code = 400; reply_str = pu_400_rpl; memset(&subs, 0, sizeof(subs_t)); if ( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("parsing headers\n"); goto error; } /* check for Support: eventlist header */ if(!msg->supported) { LM_DBG("no supported header found\n"); return to_presence_code; } if(parse_supported(msg) < 0) { LM_ERR("failed to parse supported headers\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if(!(get_supported(msg) & F_SUPPORTED_EVENTLIST)) { LM_DBG("No 'Support: eventlist' header found\n"); return to_presence_code; } /* inspecting the Event header field */ if(msg->event && msg->event->body.len > 0) { if (!msg->event->parsed && (parse_event(msg->event) < 0)) { LM_ERR("cannot parse Event header\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if(! ( ((event_t*)msg->event->parsed)->parsed & rls_events) ) { return to_presence_code; } } else { goto bad_event; } /* search event in the list */ parsed_event= (event_t*)msg->event->parsed; event= pres_search_event(parsed_event); if(event== NULL) { goto bad_event; } subs.event= event; /* extract the id if any*/ ev_param= parsed_event->params; while(ev_param) { if(ev_param->name.len== 2 && strncasecmp(ev_param->name.s, "id", 2)== 0) { subs.event_id= ev_param->body; break; } ev_param= ev_param->next; } pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("parsing 'To' header failed\n"); goto error; } if(parse_from_uri(msg)<0) { LM_ERR("failed to parse From header\n"); goto error; } pfrom = (struct to_body*)msg->from->parsed; if(pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); goto error; } /* verify if the presentity URI is a resource list */ if(pto->tag_value.s== NULL || pto->tag_value.len==0) /* if an initial Subscribe */ { struct sip_uri fu = ((struct to_body*)msg->from->parsed)->parsed_uri; if( parse_sip_msg_uri(msg)< 0) { LM_ERR("parsing Request URI failed\n"); goto error; } /*verify if Request URI represents a list by asking xcap server*/ if(uandd_to_uri(msg->parsed_uri.user, msg->parsed_uri.host, &subs.pres_uri)< 0) { LM_ERR("while constructing uri from user and domain\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if( get_resource_list(&subs.pres_uri, fu.user, fu.host, &service_node, &doc) < 0) { LM_ERR("failed to get resource list document\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if(doc== NULL|| service_node==NULL) { LM_DBG("list not found - search for uri = %.*s\n",subs.pres_uri.len, subs.pres_uri.s); pkg_free(subs.pres_uri.s); return to_presence_code; } } else /* if request inside a dialog */ { if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot parse callid header\n"); goto error; } /* search if a stored dialog */ hash_code= core_hash(&msg->callid->body, &pto->tag_value, hash_size); lock_get(&rls_table[hash_code].lock); if(pres_search_shtable(rls_table,msg->callid->body, pto->tag_value, pfrom->tag_value, hash_code)== NULL) { lock_release(&rls_table[hash_code].lock); /* reply with Call/Transaction Does Not Exist */ LM_DBG("No dialog match found\n"); return to_presence_code; } lock_release(&rls_table[hash_code].lock); } /* extract dialog information from message headers */ if(pres_extract_sdialog_info(&subs, msg, rls_max_expires, &init_req, server_address)< 0) { LM_ERR("bad Subscribe request\n"); goto error; } reply_code = 500; reply_str = pu_500_rpl; if(init_req) /* if an initial subscribe */ { /** reply with 200 OK*/ if(reply_200(msg, &subs.local_contact, subs.expires, &subs.to_tag)< 0) goto error_free; hash_code= core_hash(&subs.callid, &subs.to_tag, hash_size); subs.local_cseq= 0; if(subs.expires!= 0) { subs.version= 1; if(pres_insert_shtable(rls_table, hash_code, &subs)< 0) { LM_ERR("while adding new subscription\n"); goto error_free; } } } else { if(update_rlsubs(&subs, hash_code, &reply_code, &reply_str) < 0) { LM_ERR("while updating resource list subscription\n"); goto error; } if(get_resource_list(&subs.pres_uri, subs.from_user, subs.from_domain, &service_node, &doc)< 0) { LM_ERR("when getting resource list\n"); goto error; } if(doc== NULL || service_node== NULL) { LM_DBG("list not found( in-dialog request)- search for uri = %.*s\n", subs.pres_uri.len, subs.pres_uri.s); reply_code = 404; reply_str = pu_404_rpl; goto error; } /** reply with 200 OK*/ if(reply_200(msg, &subs.local_contact, subs.expires, 0)< 0) goto error_free; } /*** send Subscribe requests for all in the list */ /* call sending Notify with full state */ if(send_full_notify(&subs, service_node, subs.version, &subs.pres_uri,hash_code)< 0) { LM_ERR("while sending full state Notify\n"); goto error_free; } if(resource_subscriptions(&subs, service_node)< 0) { LM_ERR("while sending Subscribe requests to resources in a list\n"); goto error_free; } if(contact) { if(contact->s) pkg_free(contact->s); pkg_free(contact); } pkg_free(subs.pres_uri.s); if(subs.record_route.s) pkg_free(subs.record_route.s); xmlFreeDoc(doc); return 1; bad_event: if(reply_489(msg)< 0) LM_ERR("failed to send 489 reply\n"); goto error_free; error: if (rls_sigb.reply(msg, reply_code, &reply_str, 0) == -1) { LM_ERR("failed to send 400 reply\n"); return -1; } error_free: if(contact) { if(contact->s) pkg_free(contact->s); pkg_free(contact); } if(subs.pres_uri.s) pkg_free(subs.pres_uri.s); if(subs.record_route.s) pkg_free(subs.record_route.s); if(doc) xmlFreeDoc(doc); return -1; }
int update_rlsubs( subs_t* subs, unsigned int hash_code) { subs_t* s; if (dbmode == RLS_DB_ONLY) { LM_ERR( "update_rlsubs called in RLS_DB_ONLY mode\n" ); } /* search the record in hash table */ lock_get(&rls_table[hash_code].lock); s= pres_search_shtable(rls_table, subs->callid, subs->to_tag, subs->from_tag, hash_code); if(s== NULL) { LM_DBG("record not found in hash table\n"); lock_release(&rls_table[hash_code].lock); return -1; } s->expires= subs->expires+ (int)time(NULL); if(s->db_flag & NO_UPDATEDB_FLAG) s->db_flag= UPDATEDB_FLAG; if( s->remote_cseq>= subs->remote_cseq) { lock_release(&rls_table[hash_code].lock); LM_DBG("stored cseq= %d\n", s->remote_cseq); return Stale_cseq_code; } s->remote_cseq= subs->remote_cseq; subs->pres_uri.s= (char*)pkg_malloc(s->pres_uri.len* sizeof(char)); if(subs->pres_uri.s== NULL) { ERR_MEM(PKG_MEM_STR); } memcpy(subs->pres_uri.s, s->pres_uri.s, s->pres_uri.len); subs->pres_uri.len= s->pres_uri.len; if(s->record_route.s!=NULL && s->record_route.len>0) { subs->record_route.s = (char*)pkg_malloc(s->record_route.len* sizeof(char)); if(subs->record_route.s==NULL) { ERR_MEM(PKG_MEM_STR); } memcpy(subs->record_route.s, s->record_route.s, s->record_route.len); subs->record_route.len= s->record_route.len; } subs->local_cseq= s->local_cseq; subs->version= s->version; lock_release(&rls_table[hash_code].lock); return 0; error: lock_release(&rls_table[hash_code].lock); return -1; }
int rls_handle_subscribe(struct sip_msg* msg, str watcher_user, str watcher_domain) { subs_t subs; pres_ev_t* event = NULL; int err_ret = -1; int ret = to_presence_code; str* contact = NULL; xmlDocPtr doc = NULL; xmlNodePtr service_node = NULL; unsigned int hash_code=0; int to_tag_gen = 0; event_t* parsed_event; param_t* ev_param = NULL; str reason; int rt; str rlsubs_did = {0, 0}; memset(&subs, 0, sizeof(subs_t)); /** sanity checks - parse all headers */ if (parse_headers(msg, HDR_EOH_F, 0)<-1) { LM_ERR("failed parsing all headers\n"); if (slb.freply(msg, 400, &pu_400_rpl) < 0) { LM_ERR("while sending 400 reply\n"); return -1; } return 0; } /* check for To and From headesr */ if(parse_to_uri(msg)<0 || parse_from_uri(msg)<0) { LM_ERR("failed to find To or From headers\n"); if (slb.freply(msg, 400, &pu_400_rpl) < 0) { LM_ERR("while sending 400 reply\n"); return -1; } return 0; } if(get_from(msg)->tag_value.s ==NULL || get_from(msg)->tag_value.len==0) { LM_ERR("no from tag value present\n"); return -1; } if(msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot find callid header\n"); return -1; } if(parse_sip_msg_uri(msg)<0) { LM_ERR("failed parsing Request URI\n"); return -1; } /* check for header 'Support: eventlist' */ if(msg->supported==NULL) { LM_DBG("supported header not found - not for rls\n"); goto forpresence; } if(parse_supported(msg)<0) { LM_ERR("failed to parse supported headers\n"); return -1; } if(!(get_supported(msg) & F_SUPPORTED_EVENTLIST)) { LM_DBG("No support for 'eventlist' - not for rls\n"); goto forpresence; } /* inspecting the Event header field */ if(msg->event && msg->event->body.len > 0) { if (!msg->event->parsed && (parse_event(msg->event) < 0)) { LM_ERR("cannot parse Event header\n"); goto error; } if(! ( ((event_t*)msg->event->parsed)->type & rls_events) ) { goto forpresence; } } else { goto bad_event; } /* search event in the list */ parsed_event = (event_t*)msg->event->parsed; event = pres_search_event(parsed_event); if(event==NULL) { goto bad_event; } subs.event= event; /* extract the id if any*/ ev_param= parsed_event->params.list; while(ev_param) { if(ev_param->name.len==2 && strncmp(ev_param->name.s, "id", 2)==0) { subs.event_id = ev_param->body; break; } ev_param= ev_param->next; } /* extract dialog information from message headers */ if(pres_extract_sdialog_info(&subs, msg, rls_max_expires, &to_tag_gen, rls_server_address, watcher_user, watcher_domain)<0) { LM_ERR("bad subscribe request\n"); goto error; } hash_code = core_hash(&subs.callid, &subs.to_tag, hash_size); if (CONSTR_RLSUBS_DID(&subs, &rlsubs_did) < 0) { LM_ERR("cannot build rls subs did\n"); goto error; } subs.updated = core_hash(&rlsubs_did, NULL, 0) % (waitn_time * rls_notifier_poll_rate * rls_notifier_processes); if(get_to(msg)->tag_value.s==NULL || get_to(msg)->tag_value.len==0) { /* initial Subscribe */ /*verify if Request URI represents a list by asking xcap server*/ if(uandd_to_uri(msg->parsed_uri.user, msg->parsed_uri.host, &subs.pres_uri)<0) { LM_ERR("while constructing uri from user and domain\n"); goto error; } if(rls_get_service_list(&subs.pres_uri, &subs.watcher_user, &subs.watcher_domain, &service_node, &doc)<0) { LM_ERR("while attepmting to get a resource list\n"); goto error; } if(doc==NULL) { /* if not for RLS, pass it to presence serivce */ LM_DBG("list not found - searched for uri <%.*s>\n", subs.pres_uri.len, subs.pres_uri.s); goto forpresence; } /* if correct reply with 200 OK */ if(reply_200(msg, &subs.local_contact, subs.expires)<0) goto error; subs.local_cseq = 0; if(subs.expires != 0) { subs.version = 1; if (dbmode==RLS_DB_ONLY) { rt=insert_rlsdb( &subs ); } else { rt=pres_insert_shtable(rls_table, hash_code, &subs); } if (rt<0) { LM_ERR("while adding new subscription\n"); goto error; } } } else { /* search if a stored dialog */ if ( dbmode == RLS_DB_ONLY ) { if (rls_dbf.start_transaction) { if (rls_dbf.start_transaction(rls_db, DB_LOCKING_WRITE) < 0) { LM_ERR("in start_transaction\n"); goto error; } } rt = get_dialog_subscribe_rlsdb(&subs); if (rt <= 0) { LM_DBG("subscription dialog not found for <%.*s@%.*s>\n", subs.watcher_user.len, subs.watcher_user.s, subs.watcher_domain.len, subs.watcher_domain.s); if (rls_dbf.end_transaction) { if (rls_dbf.end_transaction(rls_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } goto forpresence; } else if(rt>=400) { reason = (rt==400)?pu_400_rpl:stale_cseq_rpl; if (slb.freply(msg, 400, &reason) < 0) { LM_ERR("while sending reply\n"); goto error; } if (rls_dbf.end_transaction) { if (rls_dbf.end_transaction(rls_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } ret = 0; goto stop; } /* if correct reply with 200 OK */ if(reply_200(msg, &subs.local_contact, subs.expires)<0) goto error; if (update_dialog_subscribe_rlsdb(&subs) < 0) { LM_ERR("while updating resource list subscription\n"); goto error; } if (rls_dbf.end_transaction) { if (rls_dbf.end_transaction(rls_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } } else { lock_get(&rls_table[hash_code].lock); if(pres_search_shtable(rls_table, subs.callid, subs.to_tag, subs.from_tag, hash_code)==NULL) { lock_release(&rls_table[hash_code].lock); LM_DBG("subscription dialog not found for <%.*s@%.*s>\n", subs.watcher_user.len, subs.watcher_user.s, subs.watcher_domain.len, subs.watcher_domain.s); goto forpresence; } lock_release(&rls_table[hash_code].lock); /* if correct reply with 200 OK */ if(reply_200(msg, &subs.local_contact, subs.expires)<0) goto error; rt = update_rlsubs(&subs, hash_code); if(rt<0) { LM_ERR("while updating resource list subscription\n"); goto error; } if(rt>=400) { reason = (rt==400)?pu_400_rpl:stale_cseq_rpl; if (slb.freply(msg, 400, &reason) < 0) { LM_ERR("while sending reply\n"); goto error; } ret = 0; goto stop; } } if(rls_get_service_list(&subs.pres_uri, &subs.watcher_user, &subs.watcher_domain, &service_node, &doc)<0) { LM_ERR("failed getting resource list\n"); goto error; } if(doc==NULL) { /* warning: no document returned?!?! */ LM_WARN("no document returned for uri <%.*s>\n", subs.pres_uri.len, subs.pres_uri.s); goto done; } } if (dbmode != RLS_DB_ONLY) { /* sending notify with full state */ if(send_full_notify(&subs, service_node, &subs.pres_uri, hash_code)<0) { LM_ERR("failed sending full state notify\n"); goto error; } } /* send subscribe requests for all in the list */ if(resource_subscriptions(&subs, service_node)< 0) { LM_ERR("failed sending subscribe requests to resources in list\n"); goto error; } if (dbmode !=RLS_DB_ONLY) remove_expired_rlsubs(&subs, hash_code); done: ret = 1; stop: forpresence: if(contact!=NULL) { if(contact->s!=NULL) pkg_free(contact->s); pkg_free(contact); } if(subs.pres_uri.s!=NULL) pkg_free(subs.pres_uri.s); if(subs.record_route.s!=NULL) pkg_free(subs.record_route.s); if(doc!=NULL) xmlFreeDoc(doc); if (rlsubs_did.s != NULL) pkg_free(rlsubs_did.s); return ret; bad_event: err_ret = 0; if(reply_489(msg)<0) { LM_ERR("failed sending 489 reply\n"); err_ret = -1; } error: LM_ERR("occured in rls_handle_subscribe\n"); if(contact!=NULL) { if(contact->s!=NULL) pkg_free(contact->s); pkg_free(contact); } if(subs.pres_uri.s!=NULL) pkg_free(subs.pres_uri.s); if(subs.record_route.s!=NULL) pkg_free(subs.record_route.s); if(doc!=NULL) xmlFreeDoc(doc); if (rlsubs_did.s != NULL) pkg_free(rlsubs_did.s); if (rls_dbf.abort_transaction) { if (rls_dbf.abort_transaction(rls_db) < 0) LM_ERR("in abort_transaction\n"); } return err_ret; }
void timer_send_notify(unsigned int ticks,void *param) { db_key_t query_cols[2], update_cols[1], result_cols[7]; db_val_t query_vals[2], update_vals[1]; int did_col, resource_uri_col, auth_state_col, reason_col, body_col, ctype_col; int n_result_cols= 0, i; db_res_t *result= NULL; char* prev_did= NULL, * curr_did= NULL; db_row_t *row; db_val_t *row_vals; char* resource_uri; str body; str callid, to_tag, from_tag; xmlDocPtr rlmi_doc= NULL; xmlNodePtr list_node= NULL, instance_node= NULL, resource_node; unsigned int hash_code= 0; int len; int size= BUF_REALLOC_SIZE, buf_len= 0; char* buf= NULL, *auth_state= NULL; int contor= 0, auth_state_flag; str bstr= {0, 0}; str rlmi_cont= {0, 0}, multi_cont; subs_t* s, *dialog= NULL; char* rl_uri= NULL; char* str_aux = NULL; str ctype, cid; int add_len; query_cols[0]= &str_updated_col; query_vals[0].type = DB_INT; query_vals[0].nul = 0; query_vals[0].val.int_val= UPDATED_TYPE; result_cols[did_col= n_result_cols++]= &str_rlsubs_did_col; result_cols[resource_uri_col= n_result_cols++]= &str_resource_uri_col; result_cols[auth_state_col= n_result_cols++]= &str_auth_state_col; result_cols[ctype_col= n_result_cols++]= &str_content_type_col; result_cols[reason_col= n_result_cols++]= &str_reason_col; result_cols[body_col= n_result_cols++]= &str_presence_state_col; /* query in alfabetical order after rlsusbs_did * (resource list Subscribe dialog indentifier)*/ if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) { LM_ERR("in use_table\n"); goto done; } if(rls_dbf.query(rls_db, query_cols, 0, query_vals, result_cols, 1, n_result_cols, &str_rlsubs_did_col, &result)< 0) { LM_ERR("in sql query\n"); goto done; } if(result== NULL || result->n<= 0) goto done; /* update the rlpres table */ update_cols[0]= &str_updated_col; update_vals[0].type = DB_INT; update_vals[0].nul = 0; update_vals[0].val.int_val= NO_UPDATE_TYPE; if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) { LM_ERR("in use_table\n"); goto error; } if(rls_dbf.update(rls_db, query_cols, 0, query_vals, update_cols, update_vals, 1, 1)< 0) { LM_ERR("in sql update\n"); goto error; } /* generate the boundary string */ bstr.s= generate_string((int)time(NULL), BOUNDARY_STRING_LEN); if(bstr.s == NULL) { LM_ERR("failed to generate random string\n"); goto error; } bstr.len= strlen(bstr.s); /* for the multipart body , use here also an initial allocated * and reallocated on need buffer */ buf= pkg_malloc(size); if(buf== NULL) { ERR_MEM(PKG_MEM_STR); } LM_DBG("found %d records with updated state\n", result->n); for(i= 0; i< result->n; i++) { row = &result->rows[i]; row_vals = ROW_VALUES(row); curr_did= (char*)row_vals[did_col].val.string_val; resource_uri= (char*)row_vals[resource_uri_col].val.string_val; auth_state_flag= row_vals[auth_state_col].val.int_val; body.s= (char*)row_vals[body_col].val.string_val; body.len= strlen(body.s); ctype.s = (char*)row_vals[ctype_col].val.string_val; ctype.len = strlen(ctype.s); /* if all the info for one dialog have been collected -> send notify */ /* the 'dialog' variable must be filled with the dialog info */ /* 'buf' must contain the body */ if(prev_did!= NULL && strcmp(prev_did, curr_did)) { xmlDocDumpMemory(rlmi_doc,(xmlChar**)(void*)&rlmi_cont.s, &rlmi_cont.len); multi_cont.s= buf; multi_cont.len= buf_len; if(agg_body_sendn_update(&dialog->pres_uri, bstr, &rlmi_cont, (buf_len==0)?NULL:&multi_cont, dialog, hash_code)<0) { LM_ERR("in function agg_body_sendn_update\n"); goto error; } xmlFree(rlmi_cont.s); xmlFreeDoc(rlmi_doc); rlmi_doc= NULL; pkg_free(rl_uri); rl_uri= NULL; pkg_free(dialog); dialog= NULL; } /* for the new dialog -> search the dialog info and * fill the dialog structure and start a new rlmi document */ if(prev_did== NULL || strcmp(prev_did, curr_did)) { /* search the subscription in rlsubs_table*/ if( parse_rlsubs_did(curr_did, &callid, &from_tag, &to_tag)< 0) { LM_ERR("bad format for " "resource list Subscribe dialog indentifier(rlsubs did)\n"); prev_did = NULL; continue; } hash_code= core_hash(&callid, &to_tag, hash_size); lock_get(&rls_table[hash_code].lock); s= pres_search_shtable(rls_table,callid,to_tag,from_tag,hash_code); if(s== NULL) { LM_DBG("record not found in hash_table [rlsubs_did]= %s\n", curr_did); LM_DBG("callid= %.*s\tfrom_tag= %.*s\tto_tag= %.*s\n", callid.len, callid.s,from_tag.len,from_tag.s, to_tag.len,to_tag.s); lock_release(&rls_table[hash_code].lock); prev_did = NULL; continue; } LM_DBG("Found rl-subs record in hash table\n"); /* save dialog info and rl_uri*/ dialog= pres_copy_subs(s, PKG_MEM_TYPE); if(dialog== NULL) { LM_ERR("while copying subs_t structure\n"); lock_release(&rls_table[hash_code].lock); goto done; } dialog->expires-= (int)time(NULL); lock_release(&rls_table[hash_code].lock); /* make new rlmi and multipart documents */ rlmi_doc= xmlNewDoc(BAD_CAST "1.0"); if(rlmi_doc== NULL) { LM_ERR("when creating new xml doc\n"); goto done; } list_node= xmlNewNode(NULL, BAD_CAST "list"); if(list_node== NULL) { LM_ERR("while creating new xml node\n"); goto done; } rl_uri= (char*)pkg_malloc((dialog->pres_uri.len+ 1)* sizeof(char)); if(rl_uri== NULL) { ERR_MEM(PKG_MEM_STR); } memcpy(rl_uri, dialog->pres_uri.s, dialog->pres_uri.len); rl_uri[dialog->pres_uri.len]= '\0'; xmlNewProp(list_node, BAD_CAST "uri", BAD_CAST rl_uri); xmlNewProp(list_node, BAD_CAST "xmlns", BAD_CAST "urn:ietf:params:xml:ns:rlmi"); xmlNewProp(list_node, BAD_CAST "version", BAD_CAST int2str(dialog->version, &len)); xmlNewProp(list_node, BAD_CAST "fullState", BAD_CAST "false"); xmlDocSetRootElement(rlmi_doc, list_node); buf_len= 0; /* !!!! for now I will include the auth state without checking if * it has changed - > in future chech if it works */ } /* add a node in rlmi_doc and if any presence state registered add * it in the buffer */ resource_node= xmlNewChild(list_node,NULL,BAD_CAST "resource", NULL); if(resource_node== NULL) { LM_ERR("when adding resource child\n"); goto done; } xmlNewProp(resource_node, BAD_CAST "uri", BAD_CAST resource_uri); /* there might be more records with the same uri- more instances- * search and add them all */ contor= 0; while(1) { contor++; cid.s= NULL; instance_node= xmlNewChild(resource_node, NULL, BAD_CAST "instance", NULL); if(instance_node== NULL) { LM_ERR("while adding instance child\n"); goto error; } str_aux = generate_string(contor, 8); if(str_aux == NULL) { LM_ERR("failed to create random string\n"); goto error; } xmlNewProp(instance_node, BAD_CAST "id", BAD_CAST str_aux); pkg_free(str_aux); auth_state= get_auth_string(auth_state_flag); if(auth_state== NULL) { LM_ERR("bad authorization status flag\n"); goto error; } xmlNewProp(instance_node, BAD_CAST "state", BAD_CAST auth_state); if(auth_state_flag & ACTIVE_STATE) { cid.s= generate_cid(resource_uri, strlen(resource_uri)); cid.len = strlen(cid.s); xmlNewProp(instance_node, BAD_CAST "cid", BAD_CAST cid.s); } else if(auth_state_flag & TERMINATED_STATE) { xmlNewProp(instance_node, BAD_CAST "reason", BAD_CAST row_vals[resource_uri_col].val.string_val); } /* add in the multipart buffer */ if(cid.s) { APPEND_MULTIPART_BODY(); pkg_free(cid.s); cid.s = NULL; } i++; if(i== result->n) { i--; break; } row = &result->rows[i]; row_vals = ROW_VALUES(row); if(strncmp(row_vals[resource_uri_col].val.string_val,resource_uri, strlen(resource_uri)) || strncmp(curr_did, row_vals[did_col].val.string_val, strlen(curr_did))) { i--; break; } resource_uri= (char*)row_vals[resource_uri_col].val.string_val; auth_state_flag= row_vals[auth_state_col].val.int_val; body.s= (char*)row_vals[body_col].val.string_val; body.len = strlen(body.s); } prev_did= curr_did; } if(rlmi_doc) { xmlDocDumpMemory( rlmi_doc,(xmlChar**)(void*)&rlmi_cont.s, &rlmi_cont.len); multi_cont.s= buf; multi_cont.len= buf_len; if(agg_body_sendn_update(&dialog->pres_uri, bstr, &rlmi_cont, (buf_len==0)?NULL:&multi_cont, dialog, hash_code)<0) { LM_ERR("in function agg_body_sendn_update\n"); goto error; } xmlFree(rlmi_cont.s); pkg_free(rl_uri); rl_uri= NULL; pkg_free(dialog); dialog= NULL; } error: done: if(result) rls_dbf.free_result(rls_db, result); if(rlmi_doc) xmlFreeDoc(rlmi_doc); if(rl_uri) pkg_free(rl_uri); if(bstr.s) pkg_free(bstr.s); if(buf) pkg_free(buf); if(dialog) pkg_free(dialog); return; }