示例#1
0
/**
 * 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);
}
示例#2
0
/**
 * 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;
	}
}
示例#3
0
/**
 * 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;	
}
示例#8
0
/**
 * 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;	
}
示例#9
0
/**
 * 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;	
}