/** * Expires all the contacts for the given public id * @param public_id - public identity to expire contacts for */ void r_public_expire(str public_id) { int expire; r_public *r_pub; r_contact * r_cont ; r_act_time(); expire = time_now; r_pub = get_r_public(public_id); if (!r_pub){ LOG(L_ERR,"ERR:"M_NAME":set_expires: identity not found in registrar <%.*s>\n",public_id.len,public_id.s); return; } r_cont = r_pub->head; while(r_cont!=NULL){ r_cont->expires = expire; r_cont=r_cont->next; } r_unlock(r_pub->hash); print_r(L_ALERT); }
/** * Updates the r_public with the new reg_state and ims_subscription values. * If not found, it will be inserted. * \note Aquires the lock on the hash_slot on success, so release it when you are done. * @param aor - the address of record * @param reg_state - new registration state, NULL if no update necessary * @param s - the new subscription attached, NULL if no update necessary * @returns the update r_public or NULL on error */ r_public* update_r_public(str aor,enum Reg_States *reg_state,ims_subscription **s) { r_public *p; p = get_r_public(aor); if (!p){ if (reg_state && *reg_state && *reg_state!=NOT_REGISTERED && s) return add_r_public(aor,*reg_state,*s); else return 0; }else{ if (reg_state) p->reg_state = *reg_state; if (*s) { if (p->s){ lock_get(p->s->lock); if (p->s->ref_count==1){ free_user_data(p->s); }else{ p->s->ref_count--; lock_release(p->s->lock); } } p->s = *s; lock_get(p->s->lock); p->s->ref_count++; lock_release(p->s->lock); } return p; } }
/** * Searches for a r_public record and returns its expiration value. * @param aor - the address of record to look for * @returns - the expiration of the r_public if found or -999 if not found */ int get_r_public_expires(str aor) { int max_expires=-999; r_contact *c; r_public *p=get_r_public(aor); if (!p) return -999; r_act_time(); for(c=p->head;c;c=c->next) if (c->expires-time_now>max_expires){ max_expires = c->expires - time_now; } r_unlock(p->hash); return max_expires; }
/** * Updates the r_public with the new is_default. * If not found, it will be inserted * \note Must be called with a lock on the domain to avoid races * @param c - the r_contact to add to * @param pub_id - the public identity * @param is_default - if this is the default contact * @returns the newly added r_public, 0 on error */ r_public* update_r_public(r_contact *c,str pub_id,int *is_default) { r_public *p; if (!c) return 0; p = get_r_public(c,pub_id); if (!p){ if (is_default) return add_r_public(c,pub_id,*is_default); else return 0; }else{ if (is_default) p->is_default = *is_default; return p; } }
/** * Creates the full reginfo XML. * @param pv - the r_public to create for * @param event_type - event type * @param subsExpires - subscription expiration * @returns the str with the XML content */ str r_get_reginfo_full(void *pv,int event_type,long *subsExpires) { str x={0,0}; str buf,pad; char bufc[MAX_REGINFO_SIZE],padc[MAX_REGINFO_SIZE]; r_public *p=(r_public*)pv,*p2; r_contact *c; r_contact_param *cp; ims_public_identity *pi; int i,j; unsigned int hash; buf.s = bufc; buf.len=0; pad.s = padc; pad.len=0; *subsExpires = r_update_subscription_status(p); STR_APPEND(buf,xml_start); sprintf(pad.s,r_reginfo_s.s,"%d",r_full.len,r_full.s); pad.len = strlen(pad.s); STR_APPEND(buf,pad); if (p->s){ for(i=0;i<p->s->service_profiles_cnt;i++) for(j=0;j<p->s->service_profiles[i].public_identities_cnt;j++){ pi = &(p->s->service_profiles[i].public_identities[j]); if (!pi->barring){ hash = get_aor_hash(pi->public_identity,r_hash_size); if (hash == p->hash) /* because we already have the lock on p->hash */ p2 = get_r_public_nolock(pi->public_identity); else p2 = get_r_public(pi->public_identity); if (p2){ if (p2->reg_state==REGISTERED) sprintf(pad.s,registration_s.s,p2->aor.len,p2->aor.s,p2,r_active.len,r_active.s); else sprintf(pad.s,registration_s.s,p2->aor.len,p2->aor.s,p2,r_terminated.len,r_terminated.s); pad.len = strlen(pad.s); STR_APPEND(buf,pad); c = p2->head; while(c){ if(c->qvalue != -1) { float q = (float)c->qvalue/1000; sprintf(pad.s,contact_s_q.s,c,r_active.len,r_active.s,r_registered.len,r_registered.s,c->expires-time_now, q); } else sprintf(pad.s,contact_s.s,c,r_active.len,r_active.s,r_registered.len,r_registered.s,c->expires-time_now); pad.len = strlen(pad.s); STR_APPEND(buf,pad); STR_APPEND(buf,uri_s); STR_APPEND(buf,c->uri); STR_APPEND(buf,uri_e); for(cp=c->parameters;cp;cp=cp->next){ sprintf(pad.s,unknown_param_s.s,cp->name.len,cp->name.s); pad.len = strlen(pad.s); STR_APPEND(buf,pad); STR_APPEND(buf,cp->value); STR_APPEND(buf,unknown_param_e); } STR_APPEND(buf,contact_e); c = c->next; } STR_APPEND(buf,registration_e); if (p2->hash != p->hash) r_unlock(p2->hash); } } } } STR_APPEND(buf,r_reginfo_e); x.s = pkg_malloc(buf.len+1); if (x.s){ x.len = buf.len; memcpy(x.s,buf.s,buf.len); x.s[x.len]=0; } return x; }
/** * Save this subscription. * @param msg - the SIP SUBSCRIBE message * @param str1 - not used * @param str2 - not used * @returns #CSCF_RETURN_TRUE if allowed, #CSCF_RETURN_FALSE if not, #CSCF_RETURN_ERROR on error */ int S_subscribe(struct sip_msg *msg,char *str1,char *str2) { int ret=CSCF_RETURN_FALSE; struct sip_uri puri; str uri={0,0}; str event; int event_i=IMS_EVENT_NONE; int expires=0,expires_time=0; str subscriber; r_public *p=0; r_subscriber *s=0,*new_s=0; dlg_t *dialog=0; LOG(L_DBG,"DBG:"M_NAME":S_subscribe: Saving SUBSCRIBE\n"); /* First check the parameters */ if (msg->first_line.type!=SIP_REQUEST) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: This message is not a request\n"); goto error; } if (msg->first_line.u.request.method.len != 9 || memcmp(msg->first_line.u.request.method.s,"SUBSCRIBE",9)!=0) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: This message is not a SUBSCRIBE\n"); goto error; } /* 1. Get the event */ event = cscf_get_event(msg); if (event.len!=3||strncasecmp(event.s,"reg",3)!=0){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Accepting only <Event: reg>. Found: <%.*s>\n", event.len,event.s); ret = CSCF_RETURN_FALSE; goto done; } if (event.len==0 && strncasecmp(event.s,"reg",3)==0) event_i = IMS_EVENT_REG; /* 2. Get the target of the SUBSCRIBE from RequestURI */ if (msg->new_uri.s) uri = msg->new_uri; else uri = msg->first_line.u.request.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Error parsing uri <%.*s>\n", uri.len,uri.s); goto error; } uri.len = lookup_sip.len+puri.user.len+1+puri.host.len; uri.s = pkg_malloc(uri.len); if (!uri.s){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Error allocating %d bytes\n",uri.len); goto error; } uri.len=0; memcpy(uri.s,lookup_sip.s,lookup_sip.len); uri.len+=lookup_sip.len; memcpy(uri.s+uri.len,puri.user.s,puri.user.len); uri.len+=puri.user.len; uri.s[uri.len++]='@'; memcpy(uri.s+uri.len,puri.host.s,puri.host.len); uri.len+=puri.host.len; /* 3. Get the Subscriber's Identity */ subscriber = cscf_get_contact(msg); if (!subscriber.len){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Contact empty.\n"); ret = CSCF_RETURN_FALSE; goto done; } LOG(L_DBG,"DBG:"M_NAME":S_subscribe: Contact <%.*s>.\n", subscriber.len,subscriber.s); p = get_r_public(uri); /* Registration is possible even if the user is not registered... so just create one */ if (!p){ p = add_r_public(uri,0,0); } if (!p){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Identity not found and error on creation <%.*s>\n", uri.len,uri.s); ret = CSCF_RETURN_FALSE; goto done; } expires = cscf_get_expires_hdr(msg,0); if (expires == -1) expires = subscription_default_expires; if (expires > 0) { if (expires < subscription_min_expires) expires = subscription_min_expires; if (expires > subscription_max_expires) expires = subscription_max_expires; r_act_time(); expires_time = expires + time_now; /* get the old subscriber - if any */ s = get_r_subscriber(p,subscriber,event_i); if (!s){ /* create a new dialog */ if (tmb.new_dlg_uas(msg, 200, &dialog) < 0) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Error while creating dialog state\n"); ret = CSCF_RETURN_FALSE; goto error; } }else dialog = s->dialog; /* update the subscriber */ if ((new_s=update_r_subscriber(p,subscriber,event_i,&expires_time,dialog))!=0){ //if (!s) /* Only on first subscription, not on refreshes, send a notify */ S_event_reg(p,0,new_s,IMS_REGISTRAR_SUBSCRIBE,0); ret = CSCF_RETURN_TRUE; } else ret = CSCF_RETURN_FALSE; }else{ /* Unsubscribe */ /* get the old subscriber - if any */ r_act_time(); s = get_r_subscriber(p,subscriber,event_i); if (s) { s->expires = time_now; S_event_reg(p,0,s,IMS_REGISTRAR_UNSUBSCRIBE,1); del_r_subscriber(p,s); } ret = CSCF_RETURN_TRUE; } done: r_unlock(p->hash); if (expires ==0 )S_SUBSCRIBE_reply(msg,200,MSG_REG_UNSUBSCRIBE_OK,&expires,&uri); else S_SUBSCRIBE_reply(msg,200,MSG_REG_SUBSCRIBE_OK,&expires,&uri); if (uri.s) pkg_free(uri.s); return ret; error: if (p) r_unlock(p->hash); if (uri.s) pkg_free(uri.s); ret=CSCF_RETURN_FALSE; return ret; }
/** * Check if this message quallifies for a subscription. * Only 3 entities can subscribe: * - the user agent to its own state * - the P-CSCF specified in a Path header for that user * - AS (not implemented yet * \todo Allow also the AS listed in iFC and not belonging to a 3rd party * @param msg - the SIP SUBSCRIBE message * @param str1 - not used * @param str2 - not used * @returns #CSCF_RETURN_TRUE if allowed, #CSCF_RETURN_FALSE if not, #CSCF_RETURN_ERROR on error */ int S_can_subscribe(struct sip_msg *msg,char *str1,char *str2) { int ret=CSCF_RETURN_FALSE; struct sip_uri puri; str uri={0,0}; str event; str asserted_id; r_public *p=0; r_contact *c=0; ims_public_identity *pi=0; int i,j; LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Checking if allowed to SUBSCRIBE\n"); /* First check the parameters */ if (msg->first_line.type!=SIP_REQUEST) { LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: This message is not a request\n"); goto error; } if (msg->first_line.u.request.method.len != 9 || memcmp(msg->first_line.u.request.method.s,"SUBSCRIBE",9)!=0) { LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: This message is not a SUBSCRIBE\n"); goto error; } /* 1. Get the event */ event = cscf_get_event(msg); if (event.len!=3||strncasecmp(event.s,"reg",3)!=0){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Accepting only <Event: reg>. Found: <%.*s>\n", event.len,event.s); ret = CSCF_RETURN_FALSE; goto done; } /* 2. Get the target of the SUBSCRIBE from RequestURI */ if (msg->new_uri.s) uri = msg->new_uri; else uri = msg->first_line.u.request.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Error parsing uri <%.*s>\n", uri.len,uri.s); goto error; } uri.len = lookup_sip.len+puri.user.len+1+puri.host.len; uri.s = pkg_malloc(uri.len); if (!uri.s){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Error allocating %d bytes\n",uri.len); goto error; } uri.len=0; memcpy(uri.s,lookup_sip.s,lookup_sip.len); uri.len+=lookup_sip.len; memcpy(uri.s+uri.len,puri.user.s,puri.user.len); uri.len+=puri.user.len; uri.s[uri.len++]='@'; memcpy(uri.s+uri.len,puri.host.s,puri.host.len); uri.len+=puri.host.len; /* 3. Check if the asserted identity is in the same group with the ReqURI */ asserted_id = cscf_get_asserted_identity(msg); if (!asserted_id.len){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: P-Asserted-Identity empty.\n"); ret = CSCF_RETURN_FALSE; goto done; } LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: P-Asserted-Identity <%.*s>.\n", asserted_id.len,asserted_id.s); p = get_r_public(uri); if (!p){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Identity not found <%.*s>\n", uri.len,uri.s); ret = CSCF_RETURN_FALSE; goto done; } if (p->aor.len == asserted_id.len && strncasecmp(p->aor.s,asserted_id.s,asserted_id.len)==0) { LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found as AOR <%.*s>\n", uri.len,uri.s); ret = CSCF_RETURN_TRUE; goto done; } if (p->s){ for(i=0;i<p->s->service_profiles_cnt;i++) for(j=0;j<p->s->service_profiles[i].public_identities_cnt;j++) { pi = &(p->s->service_profiles[i].public_identities[j]); if (!pi->barring && pi->public_identity.len == asserted_id.len && strncasecmp(pi->public_identity.s,asserted_id.s,asserted_id.len)==0) { LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found in SP[%d][%d]\n", i,j); ret = CSCF_RETURN_TRUE; goto done; } } } /* 4. Check if it present in any of the Path headers */ c=p->head; while(c){ if (c->path.len){ for(i=0;i<c->path.len-asserted_id.len;i++) if (strncasecmp(c->path.s+i,asserted_id.s,asserted_id.len)==0){ LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found in Path <%.*s>\n", c->path.len,c->path.s); ret = CSCF_RETURN_TRUE; goto done; } } c = c->next; } done: if (p) r_unlock(p->hash); if (uri.s) pkg_free(uri.s); return ret; error: if (p) r_unlock(p->hash); if (uri.s) pkg_free(uri.s); ret=CSCF_RETURN_ERROR; return ret; }
/** * Updates the r_public with the new reg_state and ims_subscription values. * If not found, it will be inserted. * \note Aquires the lock on the hash_slot on success, so release it when you are done. * @param aor - the address of record * @param reg_state - new registration state, NULL if no update necessary * @param s - the new subscription attached, NULL if no update necessary * @returns the update r_public or NULL on error */ r_public* update_r_public(str aor,enum Reg_States *reg_state,ims_subscription **s, str *ccf1, str *ccf2, str *ecf1, str *ecf2) { r_public *p=0; //LOG(L_CRIT,"update_r_public():with aor %.*s\n",aor.len,aor.s); if ((*s)->wpsi) { p = get_r_public_wpsi(aor); } else { p = get_r_public(aor); } if (!p){ //LOG(L_DBG,"updating a new r_public profile\n"); if (reg_state && *reg_state && *reg_state!=NOT_REGISTERED && s){ p = add_r_public(aor,*reg_state,*s); if (!p) return p; if (ccf1) { if (p->ccf1.s) shm_free(p->ccf1.s); STR_SHM_DUP( &(p->ccf1), ccf1,"SHM CCF1"); } if (ccf2) { if (p->ccf2.s) shm_free(p->ccf2.s); STR_SHM_DUP( &(p->ccf2), ccf2,"SHM CCF2"); } if (ecf1) { if (p->ecf1.s) shm_free(p->ecf1.s); STR_SHM_DUP( &(p->ecf1), ecf1,"SHM ECF1"); } if (ecf2) { if (p->ecf2.s) shm_free(p->ecf2.s); STR_SHM_DUP( &(p->ecf2), ecf2,"SHM ECF2"); } //LOG(L_DBG,"update_r_public(): it was actually adding\n"); return p; } else return 0; }else{ //LOG(L_DBG,"updating a not so new r_public profile\n"); if (reg_state) p->reg_state = *reg_state; if (*s) { if (p->s){ lock_get(p->s->lock); if (p->s->ref_count==1){ free_user_data(p->s); }else{ p->s->ref_count--; lock_release(p->s->lock); } } p->s = *s; lock_get(p->s->lock); p->s->ref_count++; lock_release(p->s->lock); if ((*s)->wpsi) { p->s=NULL; if (p->prev) p->prev->next=p->next; else registrar[r_hash_size].head=p->next; if (p->next) p->next->prev=p->prev; else registrar[r_hash_size].tail=p->prev; free_r_public(p); r_unlock(r_hash_size); p=add_r_public(aor,0,*s); } } if (ccf1) { if (p->ccf1.s) shm_free(p->ccf1.s); STR_SHM_DUP( &(p->ccf1), ccf1,"SHM CCF1"); } if (ccf2) { if (p->ccf2.s) shm_free(p->ccf2.s); STR_SHM_DUP( &(p->ccf2), ccf2,"SHM CCF2"); } if (ecf1) { if (p->ecf1.s) shm_free(p->ecf1.s); STR_SHM_DUP( &(p->ecf1), ecf1,"SHM ECF1"); } if (ecf2) { if (p->ecf2.s) shm_free(p->ecf2.s); STR_SHM_DUP( &(p->ecf2), ecf2,"SHM ECF2"); } //LOG(L_DBG,"update_r_public(): return normaly\n"); return p; } out_of_memory: return p; }
/** * Updates the r_public with the new reg_state and ims_subscription values. * If not found, it will be inserted. * \note Aquires the lock on the hash_slot on success, so release it when you are done. * @param aor - the address of record * @param reg_state - new registration state, NULL if no update necessary * @param s - the new subscription attached, NULL if no update necessary * @returns the update r_public or NULL on error */ r_public* update_r_public(str aor,enum Reg_States *reg_state,ims_subscription **s, str *ccf1, str *ccf2, str *ecf1, str *ecf2) { r_public *p=0; p = get_r_public(aor); if (!p){ if (reg_state && *reg_state && *reg_state!=NOT_REGISTERED && s){ p = add_r_public(aor,*reg_state,*s); if (!p) return p; if (ccf1) { if (p->ccf1.s) shm_free(p->ccf1.s); STR_SHM_DUP(p->ccf1,*ccf1,"SHM CCF1"); } if (ccf2) { if (p->ccf2.s) shm_free(p->ccf2.s); STR_SHM_DUP(p->ccf2,*ccf2,"SHM CCF2"); } if (ecf1) { if (p->ecf1.s) shm_free(p->ecf1.s); STR_SHM_DUP(p->ecf1,*ecf1,"SHM ECF1"); } if (ecf2) { if (p->ecf2.s) shm_free(p->ecf2.s); STR_SHM_DUP(p->ecf2,*ecf2,"SHM ECF2"); } return p; } else return 0; }else{ if (reg_state) p->reg_state = *reg_state; if (*s) { if (p->s){ lock_get(p->s->lock); if (p->s->ref_count==1){ free_user_data(p->s); }else{ p->s->ref_count--; lock_release(p->s->lock); } } p->s = *s; lock_get(p->s->lock); p->s->ref_count++; lock_release(p->s->lock); } if (ccf1) { if (p->ccf1.s) shm_free(p->ccf1.s); STR_SHM_DUP(p->ccf1,*ccf1,"SHM CCF1"); } if (ccf2) { if (p->ccf2.s) shm_free(p->ccf2.s); STR_SHM_DUP(p->ccf2,*ccf2,"SHM CCF2"); } if (ecf1) { if (p->ecf1.s) shm_free(p->ecf1.s); STR_SHM_DUP(p->ecf1,*ecf1,"SHM ECF1"); } if (ecf2) { if (p->ecf2.s) shm_free(p->ecf2.s); STR_SHM_DUP(p->ecf2,*ecf2,"SHM ECF2"); } return p; } out_of_memory: return p; }