/**
 * Send a AAAMessage asynchronously.
 * When the response is received, the callback_f(callback_param,...) is called.
 * @param message - the request to be sent
 * @param peer_id - FQDN of the peer to send
 * @param callback_f - callback to be called on transactional response or transaction timeout
 * @param callback_param - generic parameter to call the transactional callback function with
 * @returns 1 on success, 0 on failure 
 * \todo remove peer_id and add Realm routing
 */
AAAReturnCode AAASendMessageToPeer(	
		AAAMessage *message,
		str *peer_id, 
		AAATransactionCallback_f *callback_f,
		void *callback_param)
{
	peer *p;
	p = get_peer_by_fqdn(peer_id);
	if (!p) {
		LOG(L_ERR,"ERROR:AAASendMessageToPeer(): Peer unknown %.*s\n",peer_id->len,peer_id->s);
		goto error;
	}
	if (p->state!=I_Open && p->state!=R_Open){
		LOG(L_ERR,"ERROR:AAASendMessageToPeer(): Peer not connected to %.*s\n",peer_id->len,peer_id->s);
		goto error;
	}
	/* only add transaction following when required */
	if (callback_f){
		if (is_req(message))
			cdp_add_trans(message,callback_f,callback_param,config->transaction_timeout,1);
		else
			LOG(L_ERR,"ERROR:AAASendMessageToPeer(): can't add transaction callback for answer.\n");
	}
		
//	if (!peer_send_msg(p,message))
	if (!sm_process(p,Send_Message,message,0,0))	
		goto error;
		
	return 1;
error:	
	AAAFreeMessage(&message);
	return 0;
}
int check_peer(str * peer_fqdn) {
	peer * p;
	p = get_peer_by_fqdn(peer_fqdn);
	if (p && !p->disabled &&  (p->state == I_Open || p->state == R_Open)) {
		return 1;
	} else {
		return -1;
	}	
}
Beispiel #3
0
/**
 * Get the first peer that is connected from the list of routing entries.
 * @param r - the list of routing entries to look into
 * @returns - the peer or null if none connected
 */
peer* get_first_connected_route(routing_entry *r,int app_id,int vendor_id)
{
	peer *peers[LB_MAX_PEERS];
	int peer_count=0;
	int prev_metric=0;
	routing_entry *i;
	peer *p;
	int j;
	time_t least_recent_time;

	LM_DBG("get_first_connected_route in list %p for app_id %d and vendor_id %d\n",
		r,app_id,vendor_id);
	for(i=r;i;i=i->next){
		if (peer_count >= LB_MAX_PEERS)
			break;
		p = get_peer_by_fqdn(&(i->fqdn));
		if (!p)
			LM_DBG("The peer %.*s does not seem to be connected or configured\n",
				i->fqdn.len,i->fqdn.s);
		else
			LM_DBG("The peer %.*s state is %s\n",i->fqdn.len,i->fqdn.s,
				(p->state==I_Open||p->state==R_Open)?"opened":"closed");
		if (p && !p->disabled && (p->state==I_Open || p->state==R_Open) && peer_handles_application(p,app_id,vendor_id)) {
			LM_DBG("The peer %.*s matches - will forward there\n",i->fqdn.len,i->fqdn.s);
			if (peer_count!=0) {//check the metric
				if (i->metric != prev_metric)
					break;
				//metric must be the same
				peers[peer_count++] = p;
			} else {//we're first
				prev_metric = i->metric;
				peers[peer_count++] = p;
			}
		}
	}

	if (peer_count==0)
		return 0;

	least_recent_time = peers[0]->last_selected;
	p = peers[0];
	for (j=1; j<peer_count; j++) {
		if (peers[j]->last_selected < least_recent_time) {
			least_recent_time = peers[j]->last_selected;
			p = peers[j];
		}
	}

	p->last_selected = time(NULL);
	return p;
}
/**
 * Send a AAAMessage synchronously.
 * This blocks until a response is received or a transactional time-out happens. 
 * @param message - the request to be sent
 * @param peer_id - FQDN of the peer to send
 * @returns 1 on success, 0 on failure 
 * \todo remove peer_id and add Realm routing
 * \todo replace the busy-waiting lock in here with one that does not consume CPU
 */
AAAMessage* AAASendRecvMessageToPeer(AAAMessage *message, str *peer_id)
{
	peer *p;
	gen_sem_t *sem;
	cdp_trans_t *t;
	AAAMessage *ans;
	
	p = get_peer_by_fqdn(peer_id);
	if (!p) {
		LOG(L_ERR,"ERROR:AAASendRecvMessageToPeer(): Peer unknown %.*s\n",peer_id->len,peer_id->s);
		goto error;
	}
	if (p->state!=I_Open && p->state!=R_Open){
		LOG(L_ERR,"ERROR:AAASendRecvMessageToPeer(): Peer not connected to %.*s\n",peer_id->len,peer_id->s);
		goto error;
	}
	
	
	if (is_req(message)){
		sem_new(sem,0);
		t = cdp_add_trans(message,sendrecv_cb,(void*)sem,config->transaction_timeout,0);

//		if (!peer_send_msg(p,message)) {
		if (!sm_process(p,Send_Message,message,0,0)){	
			sem_free(sem);				
			goto error;
		}

		/* block until callback is executed */
		while(sem_get(sem)<0){
			if (shutdownx&&(*shutdownx)) goto error;
			LOG(L_WARN,"WARN:AAASendRecvMessageToPeer(): interrupted by signal or something > %s\n",strerror(errno));
		}
		sem_free(sem);		
		ans = t->ans;
		cdp_free_trans(t);
		return ans;
	} else {
		LOG(L_ERR,"ERROR:AAASendRecvMessageToPeer(): can't add wait for answer to answer.\n");
		goto error;
	}

		
error:	
out_of_memory:
	AAAFreeMessage(&message);
	return 0;
}
Beispiel #5
0
static void cdp_rpc_enable_peer(rpc_t* rpc, void* ctx)
{
	peer *cdp_peer;
	str peer_fqdn;

	if (rpc->scan(ctx, "S", &peer_fqdn) < 1) {
		rpc->fault(ctx, 400, "required peer fqdn argument");
		return;
	}

	cdp_peer = get_peer_by_fqdn(&peer_fqdn);
	if (cdp_peer != NULL) {
		LM_DBG("Enabling CDP Peer: [%.*s]\n", peer_fqdn.len, peer_fqdn.s);
		cdp_peer->disabled = 0;
		return;
	}
	rpc->fault(ctx, 400, "peer not found");
	return;
}
void Send_ASA(cdp_session_t* s, AAAMessage* msg)
{
	AAAMessage *asa;
	char x[4];
	AAA_AVP *avp;	
	LOG(L_INFO,"Send_ASA():  sending ASA\n");
	if (!s) {
	//send an ASA for UNKNOWN_SESSION_ID - use AAASendMessage()
	// msg is the ASR received
		asa = AAANewMessage(IMS_ASA,0,0,msg);
		if (!asa) return;	
	
		set_4bytes(x,AAA_SUCCESS);
		AAACreateAndAddAVPToMessage(asa,AVP_Result_Code,AAA_AVP_FLAG_MANDATORY,0,x,4);
	
		AAASendMessage(asa,0,0);
	}else{
		// send... many cases... maybe not needed.
		// for now we do the same
		asa = AAANewMessage(IMS_ASA,0,0,msg);
		if (!asa) return;	
	
		set_4bytes(x,AAA_SUCCESS);
		AAACreateAndAddAVPToMessage(asa,AVP_Result_Code,AAA_AVP_FLAG_MANDATORY,0,x,4);
				
		avp = AAAFindMatchingAVP(msg,0,AVP_Origin_Host,0,0);	
		if (avp) {
				// This is because AAASendMessage is not going to find a route to the 
				// the PCRF because TS 29.214 says no Destination-Host and no Auth-Application-Id
				// in the ASA
			LOG(L_INFO,"sending ASA to peer %.*s\n",avp->data.len,avp->data.s); 
			peer *p;
			p = get_peer_by_fqdn(&avp->data);
			if (!peer_send_msg(p,asa)) {
				if (asa) AAAFreeMessage(&asa);	//needed in frequency
			} else  
				LOG(L_INFO,"success sending ASA\n");
		}else if (!AAASendMessage(asa,0,0)) {
			LOG(L_ERR,"Send_ASA() : error sending ASA\n");
		}	
	}	
}
Beispiel #7
0
/**
 * Get the first peer that is connected from the list of routing entries.
 * @param r - the list of routing entries to look into
 * @returns - the peer or null if none connected
 */
peer* get_first_connected_route(routing_entry *r,int app_id,int vendor_id)
{
	routing_entry *i;
	peer *p;
	LOG(L_DBG,"get_first_connected_route in list %p for app_id %d and vendor_id %d\n",
		r,app_id,vendor_id);
	for(i=r;i;i=i->next){
		p = get_peer_by_fqdn(&(i->fqdn));
		if (!p)
			LOG(L_DBG,"The peer %.*s does not seem to be connected or configured\n",
				i->fqdn.len,i->fqdn.s);
		else
			LOG(L_DBG,"The peer %.*s state is %s\n",i->fqdn.len,i->fqdn.s,
				(p->state==I_Open||p->state==R_Open)?"opened":"closed");
		if (p && (p->state==I_Open || p->state==R_Open) && peer_handles_application(p,app_id,vendor_id)) {			
			LOG(L_DBG,"The peer %.*s matches - will forward there\n",i->fqdn.len,i->fqdn.s);
			return p;
		}
	}
	return 0;
}
Beispiel #8
0
/**
 * Get the first peer that is connected from the list of routing entries.
 * @param r - the list of routing entries to look into
 * @returns - the peer or null if none connected
 */
peer* get_first_connected_route(cdp_session_t* cdp_session, routing_entry *r, int app_id, int vendor_id) {
	peer * peers[LB_MAX_PEERS];
	int peer_count = 0;
	int prev_metric = 0;
	routing_entry *i;
	peer *p;
	int j;
	time_t least_recent_time;
	struct timespec time_spec;

	if (cdp_session) {
		/*try and find an already used peer for this session - sticky*/
		if ((cdp_session->sticky_peer_fqdn.len > 0) && cdp_session->sticky_peer_fqdn.s) {
			//we have an old sticky peer. let's make sure it's up and connected before we use it.
			AAASessionsUnlock(cdp_session->hash); /*V1.1 - Don't attempt to hold two locks at same time */
			p = get_peer_by_fqdn(&cdp_session->sticky_peer_fqdn);
			AAASessionsLock(cdp_session->hash); /*V1.1 - As we were...no call seems to pass cdp_session unlocked */
			if (p && !p->disabled && (p->state == I_Open || p->state == R_Open) && peer_handles_application(p, app_id, vendor_id)) {
				p->last_selected = time(NULL);
				LM_DBG("Found a sticky peer [%.*s] for this session - re-using\n", p->fqdn.len, p->fqdn.s);
				return p;
			}
		}
	}

	for (i = r; i; i = i->next) {
		if (peer_count >= LB_MAX_PEERS)
			break;
		p = get_peer_by_fqdn(&(i->fqdn));
		if (!p)
			LM_DBG("The peer %.*s does not seem to be connected or configured\n",
					i->fqdn.len, i->fqdn.s);
		else
			LM_DBG("The peer %.*s state is %s\n", i->fqdn.len, i->fqdn.s,
					(p->state == I_Open || p->state == R_Open) ? "opened" : "closed");
		if (p && !p->disabled && (p->state == I_Open || p->state == R_Open) && peer_handles_application(p, app_id, vendor_id)) {
			LM_DBG("The peer %.*s matches - will forward there\n", i->fqdn.len, i->fqdn.s);
			if (peer_count != 0) {//check the metric
				if (i->metric != prev_metric)
					break;
				//metric must be the same
				peers[peer_count++] = p;
			} else {//we're first
				prev_metric = i->metric;
				peers[peer_count++] = p;
			}
		}
	}

	if (peer_count == 0) {
		return 0;
	}

	least_recent_time = peers[0]->last_selected;
	LM_DBG("peer [%.*s] was last used @ %ld\n", peers[0]->fqdn.len, peers[0]->fqdn.s, peers[0]->last_selected);
	p = peers[0];
	for (j = 1; j < peer_count; j++) {
		LM_DBG("Peer [%.*s] was last used at [%ld]\n", peers[j]->fqdn.len, peers[j]->fqdn.s, peers[j]->last_selected);
		if (peers[j]->last_selected < least_recent_time) {
			least_recent_time = peers[j]->last_selected;
			p = peers[j];
		}
	}

	ser_clock_gettime(&time_spec);

	p->last_selected = (time_spec.tv_sec*1000000) + round(time_spec.tv_nsec / 1.0e3); // Convert nanoseconds to microseconds
	LM_DBG("chosen peer [%.*s]\n", p->fqdn.len, p->fqdn.s);

	if (cdp_session) {
		if (cdp_session->sticky_peer_fqdn_buflen <= p->fqdn.len) {
			LM_DBG("not enough storage for sticky peer - allocating more\n");
			if (cdp_session->sticky_peer_fqdn.s)
				shm_free(cdp_session->sticky_peer_fqdn.s);

			cdp_session->sticky_peer_fqdn.s = (char*) shm_malloc(p->fqdn.len + 1);
			if (!cdp_session->sticky_peer_fqdn.s) {
				LM_ERR("no more shm memory\n");
				return 0;
			}
			cdp_session->sticky_peer_fqdn_buflen = p->fqdn.len + 1;
			memset(cdp_session->sticky_peer_fqdn.s, 0, p->fqdn.len + 1);
		}
		cdp_session->sticky_peer_fqdn.len = p->fqdn.len;
		memcpy(cdp_session->sticky_peer_fqdn.s, p->fqdn.s, p->fqdn.len);
	}

	return p;
}
Beispiel #9
0
/**
 * Get the first connect peer that matches the routing mechanisms.
 * - First the Destination-Host AVP value is tried if connected (the peer does not have to
 * be in the routing table at all).
 * - Then we look for a connected peer in the specific realm for the Destination-Realm AVP
 * - Then we look for the first connected peer in the default routes
 * @param m - the Diameter message to find the destination peer for
 * @returns - the connected peer or null if none connected found
 */
peer* get_routing_peer(cdp_session_t* cdp_session, AAAMessage *m) {
	str destination_realm = {0, 0}, destination_host = {0, 0};
	AAA_AVP *avp, *avp_vendor, *avp2;
	AAA_AVP_LIST group;
	peer *p;
	routing_realm *rr;
	int app_id = 0, vendor_id = 0;

	LM_DBG("getting diameter routing peer for realm: [%.*s]\n", m->dest_realm->data.len, m->dest_realm->data.s);

	app_id = m->applicationId;
	avp = AAAFindMatchingAVP(m, 0, AVP_Vendor_Specific_Application_Id, 0, AAA_FORWARD_SEARCH);
	if (avp) {
		group = AAAUngroupAVPS(avp->data);
		avp_vendor = AAAFindMatchingAVPList(group, group.head, AVP_Vendor_Id, 0, 0);
		avp2 = AAAFindMatchingAVPList(group, group.head, AVP_Auth_Application_Id, 0, 0);
		if (avp_vendor && avp2) {
			vendor_id = get_4bytes(avp_vendor->data.s);
			app_id = get_4bytes(avp2->data.s);
		}
		avp2 = AAAFindMatchingAVPList(group, group.head, AVP_Acct_Application_Id, 0, 0);
		if (avp_vendor && avp2) {
			vendor_id = get_4bytes(avp_vendor->data.s);
			app_id = get_4bytes(avp2->data.s);
		}
		AAAFreeAVPList(&group);
	}

	avp_vendor = AAAFindMatchingAVP(m, 0, AVP_Vendor_Id, 0, AAA_FORWARD_SEARCH);
	avp = AAAFindMatchingAVP(m, 0, AVP_Auth_Application_Id, 0, AAA_FORWARD_SEARCH);
	if (avp && avp_vendor) {
		vendor_id = get_4bytes(avp_vendor->data.s);
		app_id = get_4bytes(avp->data.s);
	}

	avp = AAAFindMatchingAVP(m, 0, AVP_Acct_Application_Id, 0, AAA_FORWARD_SEARCH);
	if (avp && avp_vendor) {
		vendor_id = get_4bytes(avp_vendor->data.s);
		app_id = get_4bytes(avp->data.s);
	}

	avp = AAAFindMatchingAVP(m, 0, AVP_Destination_Host, 0, AAA_FORWARD_SEARCH);
	if (avp) destination_host = avp->data;

	if (destination_host.len) {
		/* There is a destination host present in the message try and route directly there */
		p = get_peer_by_fqdn(&destination_host);
		if (p && (p->state == I_Open || p->state == R_Open) && peer_handles_application(p, app_id, vendor_id)) {
			p->last_selected = time(NULL);
			return p;
		}
		/* the destination host peer is not connected at the moment, try a normal route then */
	}

	avp = AAAFindMatchingAVP(m, 0, AVP_Destination_Realm, 0, AAA_FORWARD_SEARCH);
	if (avp) destination_realm = avp->data;

	if (!config->r_table) {
		LM_ERR("get_routing_peer(): Empty routing table.\n");
		return 0;
	}

	if (destination_realm.len) {
		/* first search for the destination realm */
		for (rr = config->r_table->realms; rr; rr = rr->next)
			if (rr->realm.len == destination_realm.len &&
					strncasecmp(rr->realm.s, destination_realm.s, destination_realm.len) == 0)
				break;
		if (rr) {
			p = get_first_connected_route(cdp_session, rr->routes, app_id, vendor_id);
			if (p) return p;
			else LM_ERR("get_routing_peer(): No connected Route peer found for Realm <%.*s>. Trying DefaultRoutes next...\n",
					destination_realm.len, destination_realm.s);
		}
	}
	/* if not found in the realms or no destination_realm,
	 * get the first connected host in default routes */
	LM_DBG("no routing peer found, trying default route\n");
	p = get_first_connected_route(cdp_session, config->r_table->routes, app_id, vendor_id);
	if (!p) {
		LM_ERR("get_routing_peer(): No connected DefaultRoute peer found for app_id %d and vendor id %d.\n",
				app_id, vendor_id);
	}
	return p;
}
Beispiel #10
0
/**
 * Get the first peer that is connected from the list of routing entries.
 * @param r - the list of routing entries to look into
 * @returns - the peer or null if none connected
 */
peer* get_first_connected_route(cdp_session_t* cdp_session, routing_entry *r, int app_id, int vendor_id) {
    peer * peers[LB_MAX_PEERS];
    int peer_count = 0;
    int prev_metric = 0;
    routing_entry *i;
    peer *p;
    int j;
    time_t least_recent_time;

    if (cdp_session) {
        /*try and find an already used peer for this session - sticky*/
        if ((cdp_session->sticky_peer_fqdn.len > 0) && cdp_session->sticky_peer_fqdn.s) {
            //we have an old sticky peer. let's make sure it's up and connected before we use it.
            p = get_peer_by_fqdn(&cdp_session->sticky_peer_fqdn);
            if (p && !p->disabled && (p->state == I_Open || p->state == R_Open) && peer_handles_application(p, app_id, vendor_id)) {
                p->last_selected = time(NULL);
                LM_DBG("Found a sticky peer [%.*s] for this session - re-using\n", p->fqdn.len, p->fqdn.s);
                return p;
            }
        }
    }

    for (i = r; i; i = i->next) {
        if (peer_count >= LB_MAX_PEERS)
            break;
        p = get_peer_by_fqdn(&(i->fqdn));
        if (!p)
            LM_DBG("The peer %.*s does not seem to be connected or configured\n",
                i->fqdn.len, i->fqdn.s);
        else
            LM_DBG("The peer %.*s state is %s\n", i->fqdn.len, i->fqdn.s,
                (p->state == I_Open || p->state == R_Open) ? "opened" : "closed");
        if (p && !p->disabled && (p->state == I_Open || p->state == R_Open) && peer_handles_application(p, app_id, vendor_id)) {
            LM_DBG("The peer %.*s matches - will forward there\n", i->fqdn.len, i->fqdn.s);
            if (peer_count != 0) {//check the metric
                if (i->metric != prev_metric)
                    break;
                //metric must be the same
                peers[peer_count++] = p;
            } else {//we're first
                prev_metric = i->metric;
                peers[peer_count++] = p;
            }
        }
    }

    if (peer_count == 0) {
        return 0;
    }

    least_recent_time = peers[0]->last_selected;
    p = peers[0];
    for (j = 1; j < peer_count; j++) {
        if (peers[j]->last_selected < least_recent_time) {
            least_recent_time = peers[j]->last_selected;
            p = peers[j];
        }
    }

    if (cdp_session) {
        if (cdp_session->sticky_peer_fqdn_buflen <= p->fqdn.len) {
            LM_DBG("not enough storage for sticky peer - allocating more\n");
            if (cdp_session->sticky_peer_fqdn.s)
                shm_free(cdp_session->sticky_peer_fqdn.s);

            cdp_session->sticky_peer_fqdn.s = (char*) shm_malloc(p->fqdn.len + 1);
            if (!cdp_session->sticky_peer_fqdn.s) {
                LM_ERR("no more shm memory\n");
                return 0;
            }
            cdp_session->sticky_peer_fqdn_buflen = p->fqdn.len + 1;
            memset(cdp_session->sticky_peer_fqdn.s, 0, p->fqdn.len + 1);
        }
        cdp_session->sticky_peer_fqdn.len = p->fqdn.len;
        memcpy(cdp_session->sticky_peer_fqdn.s, p->fqdn.s, p->fqdn.len);
    }
    p->last_selected = time(NULL);
    return p;
}