Example #1
0
/**
 * \brief Send a SQL query to the server.
 *
 * Send a SQL query to the database server. This methods tries to reconnect
 * to the server if the connection is gone and the auto_reconnect parameter is
 * enabled. It also issues a mysql_ping before the query to connect again after
 * a long waiting period because for some older mysql versions the auto reconnect
 * don't work sufficient. If auto_reconnect is enabled and the server supports it,
 * then the mysql_ping is probably not necessary, but its safer to do it in this
 * cases too.
 *
 * \param _h handle for the db
 * \param _s executed query
 * \return zero on success, negative value on failure
 */
static int db_mysql_submit_query(const db1_con_t* _h, const str* _s)
{
	time_t t;
	int i, code;

	if (!_h || !_s || !_s->s) {
		LM_ERR("invalid parameter value\n");
		return -1;
	}

	if (my_ping_interval) {
		t = time(0);
		if ((t - CON_TIMESTAMP(_h)) > my_ping_interval) {
			for (i=0; i < (db_mysql_auto_reconnect ? 3 : 1); i++) {
				if (mysql_ping(CON_CONNECTION(_h))) {
					LM_INFO("driver error on ping: %s\n", mysql_error(CON_CONNECTION(_h)));
					counter_inc(mysql_cnts_h.driver_err);
				} else {
					break;
				}
			}
		}
		/*
		 * We're doing later a query anyway that will reset the timout of the server,
		 * so it makes sense to set the timestamp value to the actual time in order
		 * to prevent unnecessary pings.
		 */
		CON_TIMESTAMP(_h) = t;
	}

	/* When a server connection is lost and a query is attempted, most of
	 * the time the query will return a CR_SERVER_LOST, then at the second
	 * attempt to execute it, the mysql lib will reconnect and succeed.
	 * However is a few cases, the first attempt returns CR_SERVER_GONE_ERROR
	 * the second CR_SERVER_LOST and only the third succeeds.
	 * Thus the 3 in the loop count. Increasing the loop count over this
	 * value shouldn't be needed, but it doesn't hurt either, since the loop
	 * will most of the time stop at the second or sometimes at the third
	 * iteration. In the case of CR_SERVER_GONE_ERROR and CR_SERVER_LOST the
	 * driver error counter is increased
	 */
	for (i=0; i < (db_mysql_auto_reconnect ? 3 : 1); i++) {
		if (mysql_real_query(CON_CONNECTION(_h), _s->s, _s->len) == 0) {
			return 0;
		}
		code = mysql_errno(CON_CONNECTION(_h));
		if (code!=CR_SERVER_GONE_ERROR && code!=CR_SERVER_LOST
				&& code!=CR_SSL_CONNECTION_ERROR && code!=CR_CONNECTION_ERROR
				&& code!=CR_CONN_HOST_ERROR && code!=CR_SERVER_LOST_EXTENDED) {
			break;
		}
		counter_inc(mysql_cnts_h.driver_err);
	}
	LM_ERR("driver error on query: %s (%d)\n", mysql_error(CON_CONNECTION(_h)),
			mysql_errno(CON_CONNECTION(_h)));
	return -2;
}
Example #2
0
/**
 * Retrieve a result set
 * \param _h handle to the database
 * \param _r result set that should be retrieved
 * \return zero on success, negative value on failure
 */
static int db_mysql_store_result(const db1_con_t* _h, db1_res_t** _r)
{
	int code;
	if ((!_h) || (!_r)) {
		LM_ERR("invalid parameter value\n");
		return -1;
	}

	*_r = db_mysql_new_result();
	if (*_r == 0) {
		LM_ERR("no memory left\n");
		return -2;
	}

	RES_RESULT(*_r) = mysql_store_result(CON_CONNECTION(_h));
	if (!RES_RESULT(*_r)) {
		if (mysql_field_count(CON_CONNECTION(_h)) == 0) {
			(*_r)->col.n = 0;
			(*_r)->n = 0;
			goto done;
		} else {
			LM_ERR("driver error: %s\n", mysql_error(CON_CONNECTION(_h)));
			code = mysql_errno(CON_CONNECTION(_h));
			if (code == CR_SERVER_GONE_ERROR || code == CR_SERVER_LOST) {
				counter_inc(mysql_cnts_h.driver_err);
			}
			db_mysql_free_result(_h, *_r);
			*_r = 0;
			return -3;
		}
	}

	if (db_mysql_convert_result(_h, *_r) < 0) {
		LM_ERR("error while converting result\n");
		LM_DBG("freeing result set at %p\n", _r);
		/* all mem on Kamailio API side is already freed by
		 * db_mysql_convert_result in case of error, but we also need
		 * to free the mem from the mysql lib side, internal pkg for it
		 * and *_r */
		db_mysql_free_result(_h, *_r);
		*_r = 0;
#if (MYSQL_VERSION_ID >= 40100)
		while( mysql_more_results(CON_CONNECTION(_h)) && mysql_next_result(CON_CONNECTION(_h)) == 0 ) {
			MYSQL_RES *res = mysql_store_result( CON_CONNECTION(_h) );
			mysql_free_result(res);
		}
#endif
		return -4;
	}

done:
#if (MYSQL_VERSION_ID >= 40100)
	while( mysql_more_results(CON_CONNECTION(_h)) && mysql_next_result(CON_CONNECTION(_h)) == 0 ) {
		MYSQL_RES *res = mysql_store_result( CON_CONNECTION(_h) );
		mysql_free_result(res);
	}
#endif

	return 0;
}
Example #3
0
/**
 * Timer callback for checking the transaction status.
 * @param now - time of call
 * @param ptr - generic pointer, passed to the transactional callbacks
 */
int cdp_trans_timer(time_t now, void* ptr)
{
    cdp_trans_t *x,*n;
    lock_get(trans_list->lock);
    x = trans_list->head;
    while(x)
    {
        if (now>x->expires) {
            counter_inc(cdp_cnts_h.timeout);		//Transaction has timed out waiting for response

            x->ans = 0;
            if (x->cb) {
                (x->cb)(1,*(x->ptr),0, (now - x->expires));
            }
            n = x->next;

            if (x->prev) x->prev->next = x->next;
            else trans_list->head = x->next;
            if (x->next) x->next->prev = x->prev;
            else trans_list->tail = x->prev;
            if (x->auto_drop) cdp_free_trans(x);

            x = n;
        } else
            x = x->next;
    }
    lock_release(trans_list->lock);
    return 1;
}
Example #4
0
/*
 * Called upon receipt of an ASR. Terminates the user session and returns the ASA.
 * Terminates the corresponding dialog
 * @param request - the received request
 * @returns 0 always because ASA will be generated by the State Machine
 *
 */
AAAMessage* rx_process_asr(AAAMessage *request) {
    AAASession* session;
    unsigned int code = 0;

    rx_authsessiondata_t* p_session_data = 0;

    if (!request || !request->sessionId) return 0;

    counter_inc(ims_qos_cnts_h.asrs);
    
    session = cdpb.AAAGetAuthSession(request->sessionId->data);

    if (!session) {
        LM_DBG("received an ASR but the session is already deleted\n");
        return 0;
    }
    
    code = rx_get_abort_cause(request);
    LM_DBG("abort-cause code is %u\n", code);

    LM_DBG("PCRF requested an ASR");


    p_session_data = (rx_authsessiondata_t*) session->u.auth.generic_data;
    if (p_session_data->subscribed_to_signaling_path_status) {
        LM_DBG("This is a subscription to signalling status\n");
    } else {
        LM_DBG("This is a normal media bearer -  bearer is releaed by CDP callbacks\n");
    }
    cdpb.AAASessionsUnlock(session->hash);
    return 0;
}
Example #5
0
unsigned int cop421_execute(unsigned int cycles)
{
	unsigned int completed_cycles;
	
	for (completed_cycles = 0; completed_cycles < cycles; completed_cycles++)
	{
		
		// Store current instruction
		cur_inst = coprom[PC];
		inst_pc = PC;
		// Do preinstruction stuff
		preinst();
		pc_inc();		

		if (!g_skip)
		{
			if (cur_inst == 0x23 || cur_inst == 0x33 || (cur_inst >= 0x60 && cur_inst <= 0x63) || (cur_inst >= 0x68 && cur_inst <= 0x6b))
			{
				cur_operand = coprom[PC];
				pc_inc();
				execute_two_byte();
				
				// TODO: two byte instructions take two clocks?
				completed_cycles++; 
				counter_inc();
				counter_inc();
			}
	
			else // If its one byte
			{
				counter_inc();
				execute_one_byte();
			}
		}
		else
		{
			g_skip = 0;
			if (cur_inst == 0x23 || cur_inst == 0x33 || (cur_inst >= 0x60 && cur_inst <= 0x63) || (cur_inst >= 0x68 && cur_inst <= 0x6b))
			{
				pc_inc();
			}
			completed_cycles--; // TODO: a skipped instruction doesn't take a clock cycle?
		}
	}

	return completed_cycles;
}
Example #6
0
/*!
 * \brief Timer function that removes expired dialogs, run timeout route
 * \param tl dialog timer list
 */
void dlg_ontimeout(struct dlg_tl *tl) {
    struct dlg_cell *dlg;
    int new_state, old_state, unref;
    struct sip_msg *fmsg;

    /* get the dialog tl payload */
    dlg = ((struct dlg_cell*) ((char *) (tl) -
            (unsigned long) (&((struct dlg_cell*) 0)->tl)));

    if (dlg->toroute > 0 && dlg->toroute < main_rt.entries
            && main_rt.rlist[dlg->toroute] != NULL) {
        fmsg = faked_msg_next();
        if (exec_pre_script_cb(fmsg, REQUEST_CB_TYPE) > 0) {
            dlg_set_ctx_dialog(dlg);
            LM_DBG("executing route %d on timeout\n", dlg->toroute);
            set_route_type(REQUEST_ROUTE);
            run_top_route(main_rt.rlist[dlg->toroute], fmsg, 0);
            dlg_set_ctx_dialog(0);
            exec_post_script_cb(fmsg, REQUEST_CB_TYPE);
        }
    }

    if (dlg->state == DLG_STATE_CONFIRMED) {
        dlg_bye_all(dlg, NULL);
        unref_dlg(dlg, 1);
        return;
    }

    next_state_dlg(dlg, DLG_EVENT_REQBYE, &old_state, &new_state, &unref, 0);

    if (new_state == DLG_STATE_DELETED && old_state != DLG_STATE_DELETED) {
        LM_WARN("timeout for dlg with CallID '%.*s' and tags '%.*s'\n",
                dlg->callid.len, dlg->callid.s,
                dlg->from_tag.len, dlg->from_tag.s);

		/* dialog timeout */
		run_dlg_callbacks(DLGCB_EXPIRED, dlg, NULL, NULL, DLG_DIR_NONE, 0);
		unref_dlg(dlg, unref + 1);
		counter_add(dialog_ng_cnts_h.active, -1);
		counter_inc(dialog_ng_cnts_h.expired);
		counter_inc(dialog_ng_cnts_h.processed);
    } else {
        unref_dlg(dlg, 1);
    }

    return;
}
Example #7
0
static int cnt_inc_f(struct sip_msg* msg, char* handle, char* bar)
{
	counter_handle_t h;
	
	h.id = (long)(void*)handle;
	counter_inc(h);
	return 1;
}
Example #8
0
int reg_ht_add(reg_uac_t *reg)
{
	int len;
	reg_uac_t *nr = NULL;
	char *p;

	if(reg==NULL || _reg_htable==NULL)
	{
		LM_ERR("bad parameters: %p/%p\n", reg, _reg_htable);
		return -1;
	}
	if(reg->auth_password.len>UAC_REG_MAX_PASSWD_SIZE)
	{
		LM_ERR("bad parameters: %p/%p -- password too long %d\n",
				reg, _reg_htable, reg->auth_password.len);
		return -1;
	}

	len = reg->l_uuid.len + 1
			+ reg->l_username.len + 1
			+ reg->l_domain.len + 1
			+ reg->r_username.len + 1
			+ reg->r_domain.len + 1
			+ reg->realm.len + 1
			+ reg->auth_proxy.len + 1
			+ reg->auth_username.len + 1
			+ UAC_REG_MAX_PASSWD_SIZE /*reg->auth_password.len*/ + 1;
	nr = (reg_uac_t*)shm_malloc(sizeof(reg_uac_t) + len);
	if(nr==NULL)
	{
		LM_ERR("no more shm\n");
		return -1;
	}
	memset(nr, 0, sizeof(reg_uac_t) + len);
	nr->expires = reg->expires;
	nr->h_uuid = reg_compute_hash(&reg->l_uuid);
	nr->h_user = reg_compute_hash(&reg->l_username);
	
	p = (char*)nr + sizeof(reg_uac_t);

	reg_copy_shm(&nr->l_uuid, &reg->l_uuid);
	reg_copy_shm(&nr->l_username, &reg->l_username);
	reg_copy_shm(&nr->l_domain, &reg->l_domain);
	reg_copy_shm(&nr->r_username, &reg->r_username);
	reg_copy_shm(&nr->r_domain, &reg->r_domain);
	reg_copy_shm(&nr->realm, &reg->realm);
	reg_copy_shm(&nr->auth_proxy, &reg->auth_proxy);
	reg_copy_shm(&nr->auth_username, &reg->auth_username);
	/* password at the end, to be able to update it easily */
	reg_copy_shm(&nr->auth_password, &reg->auth_password);

	reg_ht_add_byuser(nr);
	reg_ht_add_byuuid(nr);
	counter_inc(regtotal);

	return 0;
}
Example #9
0
static int ki_cnt_inc(sip_msg_t* msg, str *sname)
{
	char* name;
	char* grp;
	char* p;
	counter_handle_t h;

	cnt_op_handle_get();

	counter_inc(h);
	return 1;
}
Example #10
0
void sendtcpdata(struct tcb *ptcb, unsigned char *data, int len)
{
   printf("Sending tcp data\n");
   static int counter_id = -1;
   if(counter_id == -1) {
      counter_id = create_counter("tcp_sent");
   }
   counter_inc(counter_id, len);
   //uint8_t tcp_len = 0x50 + add_mss_option(mbuf, 1300);// + add_winscale_option(mbuf, 7);
   struct rte_mbuf *mbuf = get_mbuf(); // remove mbuf from parameters.
   uint8_t data_len = add_tcp_data(mbuf, data, len);
   uint8_t option_len = 0;//add_winscale_option(mbuf, 7) + add_mss_option(mbuf, 1300) + add_timestamp_option(mbuf, 203032, 0);
   uint8_t tcp_len = 20 + option_len;
   uint8_t pad = (tcp_len%4) ? 4 - (tcp_len % 4): 0;
   tcp_len += pad;
   logger(LOG_TCP, NORMAL, "padding option %d for tcb %u\n",  pad, ptcb->identifier); 
   char *nop = rte_pktmbuf_prepend (mbuf, pad); // always pad the option to make total size multiple of 4.
   memset(nop, 0, pad);
   tcp_len = (tcp_len + 3) / 4;  // len is in multiple of 4 bytes;  20  will be 5
   tcp_len = tcp_len << 4; // len has upper 4 bits position in tcp header.
   logger(LOG_TCP, NORMAL, "sending tcp data of len %d total %d for tcb %u\n", data_len, tcp_len, ptcb->identifier);
   struct tcp_hdr *ptcphdr = (struct tcp_hdr *)rte_pktmbuf_prepend (mbuf, sizeof(struct tcp_hdr));
  // printf("head room2 = %d\n", rte_pktmbuf_headroom(mbuf));
   if(ptcphdr == NULL) {
    //  printf("tcp header is null\n");
   }
   ptcphdr->src_port = htons(ptcb->dport);
   ptcphdr->dst_port = htons(ptcb->sport);
   ptcphdr->sent_seq = htonl(ptcb->next_seq);
   ptcb->next_seq += data_len;
   if(((ptcb->tcp_flags & TCP_FLAG_SYN) == TCP_FLAG_SYN) || ((ptcb->tcp_flags & TCP_FLAG_FIN) == TCP_FLAG_FIN)) {
      logger(LOG_TCP, NORMAL, "Increasing seq number by one for flag syn or fin for tcb %u\n", ptcb->identifier);
      ptcb->next_seq += 1;
   }
   logger(LOG_TCP, LOG_LEVEL_NORMAL, "Next seq number is %u flags %u for tcb %u\n", ptcb->next_seq, ptcb->tcp_flags, ptcb->identifier);
   ptcphdr->recv_ack = htonl(ptcb->ack);
   ptcphdr->data_off = tcp_len;
   ptcphdr->tcp_flags =  ptcb->tcp_flags;
   ptcphdr->rx_win = 12000;
   ptcphdr->cksum = 0x0000;
   ptcphdr->tcp_urp = 0; 

   ptcb->tcp_flags = 0; //reset the flags as we have sent them in packet now.
   //mbuf->ol_flags |=  PKT_TX_IP_CKSUM; // someday will calclate checkum here only.
   
 //  printf(" null\n");
  // fflush(stdout);
   logger(LOG_TCP, NORMAL, "[SENDING TCP PACKET] sending tcp packet seq %u ack %u and datalen %u for tcb %u\n", ntohl(ptcphdr->sent_seq), ntohl(ptcphdr->recv_ack), data_len, ptcb->identifier);
   // push the mbuf in send_window unacknowledged data and increase the refrence count of this segment also start the rto timer for this tcb.
   PushDataToSendWindow(ptcb, mbuf, ntohl(ptcphdr->sent_seq), ptcb->next_seq, data_len);  
   ip_out(ptcb, mbuf, ptcphdr, data_len); 
}
Example #11
0
//the "policy" here isn't strictly necessary (one can sleep when preemption is
//disabled), but _maybe_ this is what an API user might expect
void thread_wakeup_safe(Thread* thread, void* object)
{
    #ifdef COLLECT_HEAVY_THREAD_STATISTICS
    //we count at this point, because all other functions are too fuzzy
    //xxx only meaningful if not executed from an IRQ handler!
    counter_inc(&g_current_thread->wakeup_counter);
    #endif
    
    if (preemption_is_disabled())
        thread_wakeup_delayed(thread, object);
    else
        thread_wakeup_undelayed(thread, object);
}
Example #12
0
/*!
 * \brief Add an element to an slot's linked list
 * \param _s hash slot
 * \param _r added record
 */
void subs_slot_add(hslot_sp_t* _s, struct ims_subscription_s* _r)
{
	if (_s->n == 0) {
		_s->first = _s->last = _r;
	} else {
		_r->prev = _s->last;
		_s->last->next = _r;
		_s->last = _r;
	}
	_s->n++;
        counter_inc(ul_scscf_cnts_h.active_subscriptions);
	_r->slot = _s;
}
Example #13
0
static void resume_on_termination_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs) {
    Ro_CCA_t *ro_cca_data = NULL;

    if (is_timeout) {
	counter_inc(ims_charging_cnts_h.ccr_timeouts);
	LM_ERR("Transaction timeout - did not get CCA\n");
	goto error;
    }

    counter_inc(ims_charging_cnts_h.ccr_replies_received);
    counter_add(ims_charging_cnts_h.ccr_response_time, elapsed_msecs);

    if (!cca) {
	LM_ERR("Error in termination CCR.\n");
	return;
    }

    ro_cca_data = Ro_parse_CCA_avps(cca);

    if (ro_cca_data == NULL) {
	LM_DBG("Could not parse CCA message response.\n");
	return;
    }

    if (ro_cca_data->resultcode != 2001) {
	LM_ERR("Got bad CCA result code for STOP record - [%d]\n", ro_cca_data->resultcode);
	goto error;
    } else {
	LM_DBG("Valid CCA response for STOP record\n");
    }

    counter_inc(ims_charging_cnts_h.successful_final_ccrs);

error:
    Ro_free_CCA(ro_cca_data);
    if (!is_timeout && cca) {
	cdpb.AAAFreeMessage(&cca);
    }
}
Example #14
0
//set the current thread to sleep
//must respect the current preemption disable state (no windows!)
void thread_sleep(void* object)
{
    #ifdef COLLECT_HEAVY_THREAD_STATISTICS
    counter_inc(&g_current_thread->sleep_counter);
    #endif
    
    //preemption must be disabled
    //else there'll be a race condition in the _sleep/_wakeup mechanism
    assert(preemption_is_disabled());
    
    g_current_thread->state = THREAD_STATE_BLOCKED;
    g_current_thread->block_object = object;
    reschedule();
}
Example #15
0
/* resolves a host name trying:
 * - NAPTR lookup if enabled, the address is not an ip and *proto==0 and 
 *   *port==0. The result of the NAPTR query will be used for a SRV lookup
 * - SRV lookup if the address is not an ip *port==0. The result of the SRV
 *   query will be used for an A/AAAA lookup.
 *  - normal A/AAAA lookup (either fallback from the above or if *port!=0
 *   and *proto!=0 or port==0 && proto==0)
 * when performing SRV lookup (*port==0) it will use *proto to look for
 * tcp or udp hosts, otherwise proto is unused; if proto==0 => no SRV lookup
 *
 * returns: hostent struct & *port filled with the port from the SRV record;
 *  0 on error
 */
struct hostent* _sip_resolvehost(str* name, unsigned short* port, char* proto)
{
	struct hostent* res = NULL;
#ifdef USE_NAPTR
	if (cfg_get(core, core_cfg, dns_try_naptr))
		res = naptr_sip_resolvehost(name, port, proto);
	else
#endif
	res = srv_sip_resolvehost(name, 0, port, proto, 0, 0);
	if( unlikely(!res) ){
		/* failed DNS request */
		counter_inc(dns_cnts_h.failed_dns_req);
	}
	return res;
}
Example #16
0
/*!
 * \brief Insert a new record into domain in memory
 * \param _d domain the record belongs to
 * \param _aor address of record
 * \param _r new created record
 * \return 0 on success, -1 on failure
 */
int mem_insert_impurecord(struct udomain* _d, str* public_identity, str* private_identity, int reg_state, int barring,
        ims_subscription** s, str* ccf1, str* ccf2, str* ecf1, str* ecf2,
        struct impurecord** _r) {
    int sl;

    if (new_impurecord(_d->name, public_identity, private_identity, reg_state, barring, s, ccf1, ccf2, ecf1,
            ecf2, _r) < 0) {
        LM_ERR("creating impurecord failed\n");
        return -1;
    }

    sl = ((*_r)->aorhash) & (_d->size - 1);
    slot_add(&_d->table[sl], *_r);
    counter_inc(ul_scscf_cnts_h.active_impus);

    LM_DBG("inserted new impurecord into memory [%.*s]\n", (*_r)->public_identity.len, (*_r)->public_identity.s);
    return 0;
}
Example #17
0
/*!
 * \brief Add a new contact in memory
 *
 * Add a new contact in memory, contacts are ordered by:
 * 1) q value, 2) descending modification time
 * \param _r record this contact belongs to
 * \param _c contact
 * \param _ci contact information
 * \return pointer to new created contact on success, 0 on failure
 */
ucontact_t* mem_insert_scontact(impurecord_t* _r, str* _c, ucontact_info_t* _ci) {
    ucontact_t* c;
    int sl;

    if ((c = new_ucontact(_r->domain, &_r->public_identity, _c, _ci)) == 0) {
        LM_ERR("failed to create new contact\n");
        return 0;
    }
    counter_inc(ul_scscf_cnts_h.active_contacts);

    LM_DBG("Created new contact in memory with AOR: [%.*s] and hash [%d]\n", _c->len, _c->s, c->sl);

    sl = (c->sl);
    lock_contact_slot_i(sl);
    contact_slot_add(&contact_list->slot[sl], c);
    unlock_contact_slot_i(sl);

    return c;
}
Example #18
0
void LongProcessing(void)
{
  int i, j;

  counter_start(10000);

  for (i = 0; i < 10000; i++)
  {
    for (j = 0; j < 10000; j++)
    {
      double x = fabs(sin(j * 100.) + cos(j * 100.));
      x = sqrt(x * x);
    }

    if (!counter_inc())
      break;
  }

  counter_stop();
}
Example #19
0
int
ether_out(unsigned char *dst_mac, char *src_mac, uint16_t ether_type, struct rte_mbuf *mbuf)
{
   int i = 0;
   struct ether_hdr *eth;
   eth = (struct ether_hdr *)rte_pktmbuf_prepend (mbuf, sizeof(struct ether_hdr)); 
   eth->ether_type = htons(ether_type);
   for(i=0;i<6;i++) {
      eth->d_addr.addr_bytes[i] = dst_mac[i];
   }
//   for(i=0;i<6;i++) {
   eth->s_addr.addr_bytes[0] = 0x6a;
   eth->s_addr.addr_bytes[1] = 0x9c;
   eth->s_addr.addr_bytes[2] = 0xba;
   eth->s_addr.addr_bytes[3] = 0xa0;
   eth->s_addr.addr_bytes[4] = 0x96;
   eth->s_addr.addr_bytes[5] = 0x24;
//   }
// fix this this should be automatically detect the network interface id.
   send_packet_out(mbuf, 0);
   static int counter_id = -1;
   if(counter_id == -1) {
      counter_id = create_counter("sent_rate");
   }
   int data_len = rte_pktmbuf_data_len(mbuf);

   counter_abs(counter_id, data_len);
   {
      static int counter_id = -1;
      if(counter_id == -1) {
         counter_id = create_counter("wire_sent");
      }
      int data_len = rte_pktmbuf_data_len(mbuf);
 
      counter_inc(counter_id, data_len);
   }
   (void) src_mac; // jusat to avoid warning
   src_mac = NULL;
   return 0;
}
Example #20
0
static int send_msg(msg_data_t *msg, struct remote_ip_t * rip , int work_idx , int file_fd )
{
	int	ret;
	int	left_len = 0;

	left_len = sizeof(msg_data_t) + ntohl(msg->datalen);

retry_head:
	ret = write(rip->sockfd[work_idx], /*msg->data*/ (char*)msg, left_len);
	if(ret <= 0){
		perror("write fail\n");
		printf("fd %d\n" , rip->sockfd[work_idx]);
		return ret;
	}

	left_len -= ret;
	if(left_len > 0)
		goto retry_head;
	snd_msg_cnt++;
	counter_inc(&send_success_cnt);
	//printf("handler block id %d cnt %d\n" , ntohl(msg->blockid) , counter_read(&send_success_cnt));
	return 1;
}
Example #21
0
/*! \brief
 * Create a new connection structure,
 * open the MySQL connection and set reference count to 1
 */
struct my_con* db_mysql_new_connection(const struct db_id* id)
{
	struct my_con* ptr;
	char *host, *grp, *egrp;

	if (!id) {
		LM_ERR("invalid parameter value\n");
		return 0;
	}

	ptr = (struct my_con*)pkg_malloc(sizeof(struct my_con));
	if (!ptr) {
		LM_ERR("no private memory left\n");
		return 0;
	}

	egrp = 0;
	memset(ptr, 0, sizeof(struct my_con));
	ptr->ref = 1;
	
	ptr->con = (MYSQL*)pkg_malloc(sizeof(MYSQL));
	if (!ptr->con) {
		LM_ERR("no private memory left\n");
		goto err;
	}

	mysql_init(ptr->con);

	if (id->host[0] == '[' && (egrp = strchr(id->host, ']')) != NULL) {
		grp = id->host + 1;
		*egrp = '\0';
		host = egrp;
		if (host != id->host + strlen(id->host)-1) {
			host += 1; // host found after closing bracket
		}
		else {
			// let mysql read host info from my.cnf
			// (defaults to "localhost")
			host = NULL;
		}
		// read [client] and [<grp>] sections in the order
		// given in my.cnf
		mysql_options(ptr->con, MYSQL_READ_DEFAULT_GROUP, grp);
	}
	else {
		host = id->host;
	}

	if (id->port) {
		LM_DBG("opening connection: mysql://xxxx:xxxx@%s:%d/%s\n", ZSW(host),
			id->port, ZSW(id->database));
	} else {
		LM_DBG("opening connection: mysql://xxxx:xxxx@%s/%s\n", ZSW(host),
			ZSW(id->database));
	}

	// set connect, read and write timeout, the value counts three times
	mysql_options(ptr->con, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&db_mysql_timeout_interval);
	mysql_options(ptr->con, MYSQL_OPT_READ_TIMEOUT, (const char *)&db_mysql_timeout_interval);
	mysql_options(ptr->con, MYSQL_OPT_WRITE_TIMEOUT, (const char *)&db_mysql_timeout_interval);

#if (MYSQL_VERSION_ID >= 40100)
	if (!mysql_real_connect(ptr->con, host, id->username, id->password,
				id->database, id->port, 0, CLIENT_MULTI_STATEMENTS)) {
#else
	if (!mysql_real_connect(ptr->con, host, id->username, id->password,
				id->database, id->port, 0, 0)) {
#endif
		LM_ERR("driver error: %s\n", mysql_error(ptr->con));
		/* increase error counter */
		counter_inc(mysql_cnts_h.driver_err);
		mysql_close(ptr->con);
		goto err;
	}
	/* force reconnection if enabled */
	if (db_mysql_auto_reconnect)
		ptr->con->reconnect = 1;
	else 
		ptr->con->reconnect = 0;

	LM_DBG("connection type is %s\n", mysql_get_host_info(ptr->con));
	LM_DBG("protocol version is %d\n", mysql_get_proto_info(ptr->con));
	LM_DBG("server version is %s\n", mysql_get_server_info(ptr->con));

	ptr->timestamp = time(0);
	ptr->id = (struct db_id*)id;
	if(egrp) *egrp = ']';
	return ptr;

 err:
	if (ptr && ptr->con) pkg_free(ptr->con);
	if (ptr) pkg_free(ptr);
	if(egrp) *egrp = ']';
	return 0;
}


/*! \brief
 * Close the connection and release memory
 */
void db_mysql_free_connection(struct pool_con* con)
{
	struct my_con * _c;
	
	if (!con) return;

	_c = (struct my_con*) con;

	if (_c->id) free_db_id(_c->id);
	if (_c->con) {
		mysql_close(_c->con);
		pkg_free(_c->con);
	}
	pkg_free(_c);
}
Example #22
0
int uac_reg_update(reg_uac_t *reg, time_t tn)
{
	char *uuid;
	uac_req_t uac_r;
	str method = {"REGISTER", 8};
	int ret;
	char  b_ruri[MAX_URI_SIZE];
	str   s_ruri;
	char  b_turi[MAX_URI_SIZE];
	str   s_turi;
	char  b_hdrs[MAX_UACH_SIZE];
	str   s_hdrs;

	if(uac_tmb.t_request==NULL)
		return -1;
	if(reg->expires==0)
		return 1;
	if(reg->flags&UAC_REG_ONGOING)
		return 2;
	if(reg->flags&UAC_REG_DISABLED)
		return 4;
	if(reg->timer_expires > tn + reg_timer_interval + 3)
		return 3;
	reg->timer_expires = tn;
	reg->flags |= UAC_REG_ONGOING;
	reg->flags &= ~UAC_REG_ONLINE;
	counter_add(regactive, -1);		/* Take it out of the active pool while re-registering */
	uuid = (char*)shm_malloc(reg->l_uuid.len+1);
	if(uuid==NULL)
	{
		LM_ERR("no more shm\n");
		return -1;
	}
	memcpy(uuid, reg->l_uuid.s, reg->l_uuid.len);
	uuid[reg->l_uuid.len] = '\0';

	snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s",
			reg->r_domain.len, reg->r_domain.s);
	s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);

	snprintf(b_turi, MAX_URI_SIZE, "sip:%.*s@%.*s",
			reg->r_username.len, reg->r_username.s,
			reg->r_domain.len, reg->r_domain.s);
	s_turi.s = b_turi; s_turi.len = strlen(s_turi.s);

	snprintf(b_hdrs, MAX_UACH_SIZE,
			"Contact: <sip:%.*s@%.*s>\r\n"
			"Expires: %d\r\n",
			reg->l_uuid.len, reg->l_uuid.s,
			reg_contact_addr.len, reg_contact_addr.s,
			reg->expires);
	s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);

	memset(&uac_r, '\0', sizeof(uac_r));
	uac_r.method = &method;
	uac_r.headers = &s_hdrs;
	uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
	/* Callback function */
	uac_r.cb  = uac_reg_tm_callback;
	/* Callback parameter */
	uac_r.cbp = (void*)uuid;
	ret = uac_tmb.t_request(&uac_r,  /* UAC Req */
			&s_ruri, /* Request-URI */
			&s_turi, /* To */
			&s_turi, /* From */
			(reg->auth_proxy.len)?&reg->auth_proxy:NULL /* outbound uri */
		);

	if(ret<0)
	{
		LM_ERR("failed to send request for [%.*s]", reg->l_uuid.len, reg->l_uuid.s);
		shm_free(uuid);
		if (reg_retry_interval)
			reg->timer_expires = (tn ? tn : time(NULL)) + reg_retry_interval;
		else {
			reg->flags |= UAC_REG_DISABLED;
			counter_inc(regdisabled);
		}
		reg->flags &= ~UAC_REG_ONGOING;
		return -1;
	}
	return 0;
}
Example #23
0
void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
{
	char *uuid;
	str suuid;
	reg_uac_t *ri = NULL;
	contact_t* c;
	int expires;
	struct sip_uri puri;
	struct hdr_field *hdr;
	HASHHEX response;
	str *new_auth_hdr = NULL;
	static struct authenticate_body auth;
	struct uac_credential cred;
	char  b_ruri[MAX_URI_SIZE];
	str   s_ruri;
#ifdef UAC_OLD_AUTH
	char  b_turi[MAX_URI_SIZE];
	str   s_turi;
#endif
	char  b_hdrs[MAX_UACH_SIZE];
	str   s_hdrs;
	uac_req_t uac_r;
	str method = {"REGISTER", 8};
	int ret;
	dlg_t tmdlg;

	if(ps->param==NULL || *ps->param==0)
	{
		LM_DBG("uuid not received\n");
		return;
	}
	uuid = *((char**)ps->param);
	LM_DBG("completed with status %d [uuid: %s]\n",
		ps->code, uuid);
	suuid.s = uuid;
	suuid.len = strlen(suuid.s);
	ri = reg_ht_get_byuuid(&suuid);

	if(ri==NULL)
	{
		LM_DBG("no user with uuid %s\n", uuid);
		goto done;
	}

	if(ps->code == 200)
	{
		if (parse_headers(ps->rpl, HDR_EOH_F, 0) == -1)
		{
			LM_ERR("failed to parse headers\n");
			goto error;
		}
		if (ps->rpl->contact==NULL)
		{
			LM_ERR("no Contact found\n");
			goto error;
		}
		if (parse_contact(ps->rpl->contact) < 0)
		{
			LM_ERR("failed to parse Contact HF\n");
			goto error;
		}
		if (((contact_body_t*)ps->rpl->contact->parsed)->star)
		{
			LM_DBG("* Contact found\n");
			goto done;
		}

		if (contact_iterator(&c, ps->rpl, 0) < 0)
			goto done;
		while(c)
		{
			if(parse_uri(c->uri.s, c->uri.len, &puri)!=0)
			{
				LM_ERR("failed to parse c-uri\n");
				goto error;
			}
			if(suuid.len==puri.user.len
					&& (strncmp(puri.user.s, suuid.s, suuid.len)==0))
			{
				/* calculate expires */
				expires=0;
				if(c->expires==NULL || c->expires->body.len<=0)
				{
					if(ps->rpl->expires!=NULL && ps->rpl->expires->body.len>0)
						expires = atoi(ps->rpl->expires->body.s);
				} else {
					str2int(&c->expires->body, (unsigned int*)(&expires));
				}
				ri->timer_expires = ri->timer_expires + expires;
				ri->flags |= UAC_REG_ONLINE;
				goto done;
			}
			if (contact_iterator(&c, ps->rpl, c) < 0)
			{
				LM_DBG("local contact not found\n");
				goto done;
			}
		}
	}

	if(ps->code == 401 || ps->code == 407)
	{
		if(ri->flags & UAC_REG_AUTHSENT)
		{
			LM_ERR("authentication failed for <%.*s>\n",
					ri->l_uuid.len, ri->l_uuid.s);
			goto error;
		}
		hdr = get_autenticate_hdr(ps->rpl, ps->code);
		if (hdr==0)
		{
			LM_ERR("failed to extract authenticate hdr\n");
			goto error;
		}

		LM_DBG("auth header body [%.*s]\n",
			hdr->body.len, hdr->body.s);

		if (parse_authenticate_body(&hdr->body, &auth)<0)
		{
			LM_ERR("failed to parse auth hdr body\n");
			goto error;
		}
		if (ri->realm.len>0) {
			/* only check if realms match if it is non-empty */
			if(auth.realm.len!=ri->realm.len
					|| strncmp(auth.realm.s, ri->realm.s, ri->realm.len)!=0)
			{
				LM_ERR("realms do not match. requested realm: [%.*s]\n",
					auth.realm.len, auth.realm.s);
				goto error;
			}
		}
		cred.realm = auth.realm;
		cred.user = ri->auth_username; 
		cred.passwd = ri->auth_password;
 		cred.next = NULL;

		snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s",
				ri->r_domain.len, ri->r_domain.s);
		s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);

		do_uac_auth(&method, &s_ruri, &cred, &auth, response);
		new_auth_hdr=build_authorization_hdr(ps->code, &s_ruri, &cred,
						&auth, response);
		if (new_auth_hdr==0)
		{
			LM_ERR("failed to build authorization hdr\n");
			goto error;
		}
		
#ifdef UAC_OLD_AUTH
		snprintf(b_turi, MAX_URI_SIZE, "sip:%.*s@%.*s",
				ri->r_username.len, ri->r_username.s,
				ri->r_domain.len, ri->r_domain.s);
		s_turi.s = b_turi; s_turi.len = strlen(s_turi.s);
#endif
		snprintf(b_hdrs, MAX_UACH_SIZE,
				"Contact: <sip:%.*s@%.*s>\r\n"
				"Expires: %d\r\n"
				"%.*s",
				ri->l_uuid.len, ri->l_uuid.s,
				reg_contact_addr.len, reg_contact_addr.s,
				ri->expires,
				new_auth_hdr->len, new_auth_hdr->s);
		s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);
		pkg_free(new_auth_hdr->s);

		memset(&uac_r, 0, sizeof(uac_r));
		if(uac_reg_tmdlg(&tmdlg, ps->rpl)<0)
		{
			LM_ERR("failed to build tm dialog\n");
			goto error;
		}
		tmdlg.rem_target = s_ruri;
		if(ri->auth_proxy.len)
			tmdlg.dst_uri = ri->auth_proxy;
		uac_r.method = &method;
		uac_r.headers = &s_hdrs;
		uac_r.dialog = &tmdlg;
		uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
		/* Callback function */
		uac_r.cb  = uac_reg_tm_callback;
		/* Callback parameter */
		uac_r.cbp = (void*)uuid;
#ifdef UAC_OLD_AUTH
		ret = uac_tmb.t_request(&uac_r,  /* UAC Req */
				&s_ruri, /* Request-URI */
				&s_turi, /* To */
				&s_turi, /* From */
				(ri->auth_proxy.len)?&ri->auth_proxy:NULL /* outbound uri */
			);
#endif
		ret = uac_tmb.t_request_within(&uac_r);

		if(ret<0) {
			LM_ERR("failed to send request with authentication for [%.*s]",
			       ri->l_uuid.len, ri->l_uuid.s);
			goto error;
		}

		ri->flags |= UAC_REG_AUTHSENT;
		return;
	} else
	{
		LM_ERR("got sip response %d while registering [%.*s]\n",
		       ps->code, ri->l_uuid.len, ri->l_uuid.s);
		goto error;
	}

error:
	ri->flags &= ~(UAC_REG_ONGOING|UAC_REG_AUTHSENT);
	if(reg_retry_interval) {
		ri->timer_expires = time(NULL) + reg_retry_interval;
	} else {
		ri->flags |= UAC_REG_DISABLED;
		counter_inc(regdisabled);
	}
done:
	if(ri)
		ri->flags &= ~(UAC_REG_ONGOING|UAC_REG_AUTHSENT);
	shm_free(uuid);
	counter_inc(regactive);
}
Example #24
0
static void rpc_uac_reg_disable(rpc_t* rpc, void* ctx)
{
	rpc_uac_reg_update_flag(rpc, ctx, 1, UAC_REG_DISABLED);
	counter_inc(regdisabled);
}
Example #25
0
/* this is the function called when a we need to request more funds/credit. We need to try and reserve more credit.
 * If we cant we need to put a new timer to kill the call at the appropriate time
 */
void ro_session_ontimeout(struct ro_tl *tl) {
    time_t now, call_time;
    long used_secs;
    int adjustment;
    str default_out_of_credit_hdrs = {"Reason: outofcredit\r\n", 21};

    LM_DBG("We have a fired timer [p=%p] and tl=[%i].\n", tl, tl->timeout);

    /* find the session id for this timer*/
    struct ro_session* ro_session = ((struct ro_session*) ((char *) (tl) - (unsigned long) (&((struct ro_session*) 0)->ro_tl)));
    LM_DBG("offset for ro_tl is [%lu] and ro_session id is [%.*s]\n", (unsigned long) (&((struct ro_session*) 0)->ro_tl), ro_session->ro_session_id.len, ro_session->ro_session_id.s);

    if (!ro_session) {
        LM_ERR("Can't find a session. This is bad");
        return;
    }

    LM_DBG("event-type=%d", ro_session->event_type);

    //	if (!ro_session->active) {
    //		LM_ALERT("Looks like this session was terminated while requesting more units");
    //		goto exit;
    //		return;
    //	}


    if(ro_session->is_final_allocation) {
        now = get_current_time_micro();
        used_secs = now - ro_session->last_event_timestamp;
        if((ro_session->reserved_secs - used_secs) > 0) {
            update_ro_timer(&ro_session->ro_tl, (ro_session->reserved_secs - used_secs));
            return;
        }
        else {
            ro_session->event_type = no_more_credit;
        }
    }

    switch (ro_session->event_type) {
        case answered:
            now = get_current_time_micro();
            used_secs = rint((now - ro_session->last_event_timestamp) / (float) 1000000);
            call_time = rint((now - ro_session->start_time) / (float) 1000000);

			if ((used_secs + ro_session->billed) < (call_time)) {
				adjustment = call_time - (used_secs + ro_session->billed);
				LM_DBG("Making adjustment for Ro interim timer by adding %d seconds\n", adjustment);
				used_secs += adjustment;
			}
			
            counter_add(ims_charging_cnts_h.billed_secs, used_secs);

            if (ro_session->callid.s != NULL && ro_session->ro_session_id.s != NULL) {
                LM_DBG("Found a session to re-apply for timing [%.*s] and user is [%.*s]\n",
                        ro_session->ro_session_id.len,
                        ro_session->ro_session_id.s,
                        ro_session->asserted_identity.len,
                        ro_session->asserted_identity.s);

                LM_DBG("Call session has been active for %i seconds. The last reserved secs was [%i] and the last event was [%i seconds] ago",
                        (unsigned int) call_time,
                        (unsigned int) ro_session->reserved_secs,
                        (unsigned int) used_secs);

                LM_DBG("Call session [p=%p]: we will now make a request for another [%i] of credit with a usage of [%i] seconds from the last bundle.\n",
                        ro_session,
                        interim_request_credits/* new reservation request amount */,
                        (unsigned int) used_secs/* charged seconds from previous reservation */);

                // Apply for more credit.
                //
                // The function call will return immediately and we will receive the reply asynchronously via a callback
				ro_session->billed += used_secs;
                send_ccr_interim(ro_session, (unsigned int) used_secs, interim_request_credits);
                return;
            } else {
                LM_ERR("Hmmm, the session we have either doesn't have all the data or something else has gone wrong.\n");
                /* put the timer back so the call will be killed according to previous timeout. */
                ro_session->event_type = unknown_error;
                int ret = insert_ro_timer(&ro_session->ro_tl,
                        (ro_session->reserved_secs - used_secs) / 1000000);
                if (ret != 0) {
                    LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
                            ro_session->ro_session_id.len, ro_session->ro_session_id.s);
                } else {
                    ref_ro_session(ro_session, 1, 0);
                    return;
                }
                LM_ERR("Immediately killing call due to unknown error\n");
            }
            break;
        case delayed_delete:
            destroy_ro_session(ro_session);
            return;
        case pending:
            /* call is not answered yet. No point asking more credit. Just wait for dialog to progress somehow */
            return;
        default:
            LM_ERR("Diameter call session - event [%d]\n", ro_session->event_type);

            if (ro_session->event_type == no_more_credit)
                LM_INFO("Call/session must be ended - no more funds.\n");
            else if (ro_session->event_type == unknown_error)
                LM_ERR("last event caused an error. We will now tear down this session.\n");
    }

    counter_inc(ims_charging_cnts_h.killed_calls);

    dlgb.lookup_terminate_dlg(ro_session->dlg_h_entry, ro_session->dlg_h_id, &default_out_of_credit_hdrs);
    return;
}
Example #26
0
/**
 * \brief Gets a partial result set, fetch rows from a result
 *
 * Gets a partial result set, fetch a number of rows from a database result.
 * This function initialize the given result structure on the first run, and
 * fetches the nrows number of rows. On subsequenting runs, it uses the
 * existing result and fetches more rows, until it reaches the end of the
 * result set. Because of this the result needs to be null in the first
 * invocation of the function. If the number of wanted rows is zero, the
 * function returns anything with a result of zero.
 * \param _h structure representing the database connection
 * \param _r pointer to a structure representing the result
 * \param nrows number of fetched rows
 * \return zero on success, negative value on failure
 */
int db_mysql_fetch_result(const db1_con_t* _h, db1_res_t** _r, const int nrows)
{
	int rows, i, code;

	if (!_h || !_r || nrows < 0) {
		LM_ERR("Invalid parameter value\n");
		return -1;
	}

	/* exit if the fetch count is zero */
	if (nrows == 0) {
		db_free_result(*_r);
		*_r = 0;
		return 0;
	}

	if(*_r==0) {
		/* Allocate a new result structure */
		*_r = db_new_result();
		if (*_r == 0) {
			LM_ERR("no memory left\n");
			return -2;
		}

		CON_RESULT(_h) = mysql_store_result(CON_CONNECTION(_h));
		if (!CON_RESULT(_h)) {
			if (mysql_field_count(CON_CONNECTION(_h)) == 0) {
				(*_r)->col.n = 0;
				(*_r)->n = 0;
				return 0;
			} else {
				LM_ERR("driver error: %s\n", mysql_error(CON_CONNECTION(_h)));
				code = mysql_errno(CON_CONNECTION(_h));
				if (code == CR_SERVER_GONE_ERROR || code == CR_SERVER_LOST) {
					counter_inc(mysql_cnts_h.driver_err);
				}
				db_free_result(*_r);
				*_r = 0;
				return -3;
			}
		}
		if (db_mysql_get_columns(_h, *_r) < 0) {
			LM_ERR("error while getting column names\n");
			return -4;
		}

		RES_NUM_ROWS(*_r) = mysql_num_rows(CON_RESULT(_h));
		if (!RES_NUM_ROWS(*_r)) {
			LM_DBG("no rows returned from the query\n");
			RES_ROWS(*_r) = 0;
			return 0;
		}

	} else {
		/* free old rows */
		if(RES_ROWS(*_r)!=0)
			db_free_rows(*_r);
		RES_ROWS(*_r) = 0;
		RES_ROW_N(*_r) = 0;
	}

	/* determine the number of rows remaining to be processed */
	rows = RES_NUM_ROWS(*_r) - RES_LAST_ROW(*_r);

	/* If there aren't any more rows left to process, exit */
	if(rows<=0)
		return 0;

	/* if the fetch count is less than the remaining rows to process                 */
	/* set the number of rows to process (during this call) equal to the fetch count */
	if(nrows < rows)
		rows = nrows;

	RES_ROW_N(*_r) = rows;

	LM_DBG("converting row %d of %d count %d\n", RES_LAST_ROW(*_r),
			RES_NUM_ROWS(*_r), RES_ROW_N(*_r));

	RES_ROWS(*_r) = (struct db_row*)pkg_malloc(sizeof(db_row_t) * rows);
	if (!RES_ROWS(*_r)) {
		LM_ERR("no memory left\n");
		return -5;
	}

	for(i = 0; i < rows; i++) {
		CON_ROW(_h) = mysql_fetch_row(CON_RESULT(_h));
		if (!CON_ROW(_h)) {
			LM_ERR("driver error: %s\n", mysql_error(CON_CONNECTION(_h)));
			RES_ROW_N(*_r) = i;
			db_free_rows(*_r);
			return -6;
		}
		if (db_mysql_convert_row(_h, *_r, &(RES_ROWS(*_r)[i])) < 0) {
			LM_ERR("error while converting row #%d\n", i);
			RES_ROW_N(*_r) = i;
			db_free_rows(*_r);
			return -7;
		}
	}

	/* update the total number of rows processed */
	RES_LAST_ROW(*_r) += rows;
	return 0;
}
Example #27
0
void async_aar_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) {
    struct cell *t = 0;
    unsigned int cdp_result;
    int result = CSCF_RETURN_ERROR;
    
    LM_DBG("Received AAR callback\n");
    saved_transaction_t* data = (saved_transaction_t*) param;

    LM_DBG("received AAA answer");

    if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
        LM_ERR("t_continue: transaction not found\n");
        goto error;
    } else {
        LM_DBG("t_continue: transaction found\n");
    }
    //we have T, lets restore our state (esp. for AVPs)
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);

    if (is_timeout != 0) {
        LM_ERR("Error timeout when sending AAR message via CDP\n");
        counter_inc(ims_qos_cnts_h.media_aar_timeouts);
        goto error;
    }
    if (!aaa) {
        LM_ERR("Error sending message via CDP\n");
        goto error;
    }

    counter_inc(ims_qos_cnts_h.media_aars);
    counter_add(ims_qos_cnts_h.media_aar_response_time, elapsed_msecs);
    counter_inc(ims_qos_cnts_h.media_aar_replies_received);

    /* Process the response to AAR, retrieving result code and associated Rx session ID */
    if (rx_process_aaa(aaa, &cdp_result) < 0) {
        LM_ERR("Failed to process AAA from PCRF\n"); //puri.host.len, puri.host.s);
        goto error;
    }

    if (cdp_result >= 2000 && cdp_result < 3000) {
        LM_DBG("Success, received code: [%i] from PCRF for AAR request\n", cdp_result);
	counter_inc(ims_qos_cnts_h.successful_media_aars);
	
	LM_DBG("Auth session ID [%.*s]", aaa->sessionId->data.len, aaa->sessionId->data.s);

	if(!data->aar_update) {
	    LM_DBG("This is an AAA response to an initial AAR");
	    counter_inc(ims_qos_cnts_h.active_media_rx_sessions);
	    
	    str * passed_rx_session_id = shm_malloc(sizeof (struct _str));
	    passed_rx_session_id->s = 0;
	    passed_rx_session_id->len = 0;
	    STR_SHM_DUP(*passed_rx_session_id, aaa->sessionId->data, "cb_passed_rx_session_id");
	    LM_DBG("passed rx session id [%.*s]", passed_rx_session_id->len, passed_rx_session_id->s);

	    dlgb.register_dlgcb_nodlg(&data->callid, &data->ftag, &data->ttag, DLGCB_TERMINATED | DLGCB_DESTROY | DLGCB_EXPIRED | DLGCB_RESPONSE_WITHIN | DLGCB_CONFIRMED | DLGCB_FAILED, callback_dialog, (void*) (passed_rx_session_id), free_dialog_data);
	} 
        result = CSCF_RETURN_TRUE;
    } else {
        LM_DBG("Received negative reply from PCRF for AAR Request\n");
	counter_inc(ims_qos_cnts_h.failed_media_aars);
        //we don't free rx_authdata_p here - it is free-ed when the CDP session expires
        goto error; // if its not a success then that means i want to reject this call!
    }

    //set success response code AVP
    create_return_code(result);
    goto done;

out_of_memory:
    error :
            //set failure response code
            create_return_code(result);

done:
    if (t) tmb.unref_cell(t);
    //free memory
    if (aaa)
        cdpb.AAAFreeMessage(&aaa);

    tmb.t_continue(data->tindex, data->tlabel, data->act);
    free_saved_transaction_global_data(data);
}
Example #28
0
void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) {
    struct cell *t = 0;
    pcontact_t* pcontact;
    unsigned int cdp_result;
    struct pcontact_info ci;
    udomain_t* domain_t;
    int finalReply = 0;
    AAASession *auth = 0;
    rx_authsessiondata_t* p_session_data = 0;
    int result = CSCF_RETURN_ERROR;
    pcontact_info_t contact_info;

    LM_DBG("Received AAR callback\n");
    saved_transaction_local_t* local_data = (saved_transaction_local_t*) param;
    saved_transaction_t* data = local_data->global_data;
    domain_t = data->domain;

    int is_rereg = local_data->is_rereg;

    //before we do anything else, lets decrement the reference counter on replies
    lock_get(data->lock);
    data->answers_not_received--;
    if (data->answers_not_received <= 0) {
        finalReply = 1;
    }
    if (data->ignore_replies) { //there was obv. a subsequent error AFTER we had sent one/more AAR's - so we can ignore these replies and just free memory
        free_saved_transaction_data(local_data);
        if (finalReply) {
            free_saved_transaction_global_data(data);
        }
        return;
    }
    lock_release(data->lock);

    LM_DBG("received answer and we are waiting for [%d] answers so far failures flag is [%d]\n", data->answers_not_received, data->failed);

    if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
        LM_ERR("t_continue: transaction not found\n");
        goto error;
    }
    //we have T, lets restore our state (esp. for AVPs)
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);

    if (is_timeout != 0) {
        LM_ERR("Error timeout when sending AAR message via CDP\n");
        counter_inc(ims_qos_cnts_h.registration_aar_timeouts);
        goto error;
    }
    if (!aaa) {
        LM_ERR("Error sending message via CDP\n");
        goto error;
    }

    counter_inc(ims_qos_cnts_h.registration_aars);
    counter_add(ims_qos_cnts_h.registration_aar_response_time, elapsed_msecs);
    counter_inc(ims_qos_cnts_h.registration_aar_replies_received);

    /* Process the response to AAR, retrieving result code and associated Rx session ID */
    if (rx_process_aaa(aaa, &cdp_result) < 0) {
        LM_ERR("Failed to process AAA from PCRF\n"); //puri.host.len, puri.host.s);
        goto error;
    }

    if (cdp_result >= 2000 && cdp_result < 3000) {
        counter_inc(ims_qos_cnts_h.successful_registration_aars);
	if (is_rereg) {
            LM_DBG("this is a re-registration, therefore we don't need to do anything except know that the the subscription was successful\n");
            result = CSCF_RETURN_TRUE;
            create_return_code(result);
            goto done;
        }
	//need to set Rx auth data to say this session has been successfully opened
	//This is used elsewhere to prevent acting on termination events when the session has not been opened
	//getting auth session
	auth = cdpb.AAAGetAuthSession(aaa->sessionId->data);
	if (!auth) {
	    LM_DBG("Could not get Auth Session for session id: [%.*s]\n", aaa->sessionId->data.len, aaa->sessionId->data.s);
	    goto error;
	}
	//getting session data
	p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
	if (!p_session_data) {
	    LM_DBG("Could not get session data on Auth Session for session id: [%.*s]\n", aaa->sessionId->data.len, aaa->sessionId->data.s);
	    if (auth) cdpb.AAASessionsUnlock(auth->hash);
	    goto error;
	}
	p_session_data->session_has_been_opened = 1;
	counter_inc(ims_qos_cnts_h.active_registration_rx_sessions);
	
	if (auth) cdpb.AAASessionsUnlock(auth->hash);
	
	
        LM_DBG("Success, received code: [%i] from PCRF for AAR request (contact: [%.*s]), (auth session id: %.*s)\n",
                cdp_result, local_data->contact.len, local_data->contact.s,
                local_data->auth_session_id.len, local_data->auth_session_id.s);
        LM_DBG("Registering for Usrloc callbacks on DELETE\n");

        ul.lock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
        
        contact_info.received_host = local_data->recv_host;
        contact_info.received_port = local_data->recv_port;
        contact_info.received_proto = local_data->recv_proto;
        contact_info.searchflag = (1 << SEARCH_RECEIVED);
        
        
        contact_info.aor = local_data->contact;
        contact_info.via_host = local_data->via_host;
        contact_info.via_port = local_data->via_port;
        contact_info.via_prot = local_data->via_proto;
        
        if (ul.get_pcontact(domain_t, &contact_info, &pcontact) != 0) {
            LM_ERR("Shouldn't get here, can't find contact....\n");
            ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
            goto error;
        }

        //at this point we have the contact
        /*set the contact state to say we have succesfully done ARR for register and that we dont need to do it again
         * for the duration of the registration.
         * */
        if (ul.update_rx_regsession(domain_t, &local_data->auth_session_id, pcontact) != 0) {
            LM_ERR("unable to update pcontact......\n");
            ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
            goto error;
        }
        memset(&ci, 0, sizeof (struct pcontact_info));
        ci.reg_state = PCONTACT_REG_PENDING_AAR;
        ci.num_service_routes = 0;
        ci.num_public_ids = 0;
        LM_DBG("impu: [%.*s] updating status to PCONTACT_REG_PENDING\n", pcontact->aor.len, pcontact->aor.s);
        ul.update_pcontact(domain_t, &ci, pcontact);
        //register for callbacks on contact
        ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE,
                callback_pcscf_contact_cb, NULL);
        ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
        result = CSCF_RETURN_TRUE;
    } else {
        LM_DBG("Received negative reply from PCRF for AAR Request\n");
	counter_inc(ims_qos_cnts_h.failed_registration_aars);
        result = CSCF_RETURN_FALSE;
        goto error;
    }

    //set success response code AVP
    create_return_code(result);
    goto done;

error:
    //set failure response code
    create_return_code(result);

done:
    if (t) tmb.unref_cell(t);
    //free memory
    if (aaa)
        cdpb.AAAFreeMessage(&aaa);

    if (finalReply) {
        tmb.t_continue(data->tindex, data->tlabel, data->act);
        free_saved_transaction_global_data(data);
    }
    free_saved_transaction_data(local_data);
}
Example #29
0
/*! Send query to server, optionally post data.
 */
static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const curl_query_t * const params)
{
	CURL *curl = NULL;;
	CURLcode res;  
	char *at = NULL;
	curl_res_stream_t stream;
	long stat;
	str rval;
	double download_size;
	struct curl_slist *headerlist = NULL;

	memset(&stream, 0, sizeof(curl_res_stream_t));
	stream.max_size = (size_t) params->maxdatasize;

	if(params->pconn) {
		LM_DBG("****** ##### We have a pconn - keep_connections: %d!\n", params->keep_connections);
		params->pconn->result_content_type[0] = '\0';
		params->pconn->redirecturl[0] = '\0';
		if (params->pconn->curl != NULL) {
			LM_DBG("         ****** ##### Reusing existing connection if possible\n");
			curl = params->pconn->curl;	/* Reuse existing handle */
			curl_easy_reset(curl);		/* Reset handle */
		}
	}


	if (curl == NULL) {
		curl = curl_easy_init();
	}
	if (curl == NULL) {
		LM_ERR("Failed to initialize curl connection\n");
		return -1;
	}

	LM_DBG("****** ##### CURL URL [%s] \n", _url);
	res = curl_easy_setopt(curl, CURLOPT_URL, _url);

	/* Limit to HTTP and HTTPS protocols */
	res = curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
	res = curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);

	if (params->post) {
		char ctype[256];

		ctype[0] = '\0';
		snprintf(ctype, sizeof(ctype), "Content-Type: %s", params->contenttype);

	    	/* Now specify we want to POST data */ 
		res |= curl_easy_setopt(curl, CURLOPT_POST, 1L);
		/* Set the content-type of the DATA */
		headerlist = curl_slist_append(headerlist, ctype);
		res |= curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);

		/* Tell CURL we want to upload using POST */

		res |= curl_easy_setopt(curl, CURLOPT_POSTFIELDS, params->post);

	} else {
		/* Reset post option */
		res |= curl_easy_setopt(curl, CURLOPT_POST, 0L);
	}

	if (params->maxdatasize) {
		/* Maximum data size to download - we always download full response, but
	   	cut it off before moving to pvar */
		LM_DBG("****** ##### CURL Max datasize %u\n", params->maxdatasize);
	}

	if (params->username) {
		res |= curl_easy_setopt(curl, CURLOPT_USERNAME, params->username);
		res |= curl_easy_setopt(curl, CURLOPT_HTTPAUTH, params->authmethod);
	}
	if (params->secret) {
		res |= curl_easy_setopt(curl, CURLOPT_PASSWORD, params->secret);
	}

	/* Client certificate */
	if (params->clientcert != NULL && params->clientkey != NULL) {
	    	res |= curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
	    	res |= curl_easy_setopt(curl, CURLOPT_SSLCERT, params->clientcert);

	    	res |= curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
	    	res |= curl_easy_setopt(curl, CURLOPT_SSLKEY, params->clientkey);
	}

	if (params->cacert != NULL) {
	    	res |= curl_easy_setopt(curl, CURLOPT_CAINFO, params->cacert);
	}

	if (params->tlsversion != CURL_SSLVERSION_DEFAULT) {
	    	res |= curl_easy_setopt(curl, CURLOPT_SSLVERSION, (long) params->tlsversion);
	}

	if (params->ciphersuites != NULL) {
	    	res |= curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, params->ciphersuites);
	}

	if (params->http_proxy  != NULL) {
		LM_DBG("****** ##### CURL proxy [%s] \n", params->http_proxy);
		res |= curl_easy_setopt(curl, CURLOPT_PROXY, params->http_proxy);
	 } else {
		LM_DBG("****** ##### CURL proxy NOT SET \n");
	 }

	if (params->http_proxy_port > 0) {
		res |= curl_easy_setopt(curl, CURLOPT_PROXYPORT, params->http_proxy_port);
	}


	res |= curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long) params->verify_peer);
	res |= curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, (long) params->verify_host?2:0);

	res |= curl_easy_setopt(curl, CURLOPT_NOSIGNAL, (long) 1);
	res |= curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long) params->timeout);
	res |= curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, (long) params->http_follow_redirect);
	if (params->http_follow_redirect) {
		LM_DBG("****** ##### Following redirects for this request! \n");
	}


	res |= curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function);
	res |= curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream);


	if (res != CURLE_OK) {
		/* PANIC */
		LM_ERR("Could not set CURL options. Library error \n");
	} else {
		double totaltime, connecttime;

		res = curl_easy_perform(curl);

		curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &totaltime);
		curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &connecttime);
		LM_DBG("**** HTTP Call performed in %f s (connect time %f) \n", totaltime, connecttime);
		if (params->pconn) {
			params->pconn->querytime = totaltime;
			params->pconn->connecttime = connecttime;
		}

	}

	/* Cleanup */
	if (headerlist) {
		curl_slist_free_all(headerlist);
	}

	if (res != CURLE_OK) {
		/* http://curl.haxx.se/libcurl/c/libcurl-errors.html */
		if (res == CURLE_COULDNT_CONNECT) {
			LM_WARN("failed to connect() to host\n");
		} else if ( res == CURLE_COULDNT_RESOLVE_HOST ) {
			LM_WARN("Couldn't resolve host\n");
		} else if ( res == CURLE_COULDNT_RESOLVE_PROXY ) {
			LM_WARN("Couldn't resolve http_proxy host\n");
		} else if ( res == CURLE_UNSUPPORTED_PROTOCOL ) {
			LM_WARN("URL Schema not supported by curl\n");
		} else if ( res == CURLE_URL_MALFORMAT ) {
			LM_WARN("Malformed URL used in http_client\n");
		} else if ( res == CURLE_OUT_OF_MEMORY ) {
			LM_WARN("Curl library out of memory\n");
		} else if ( res == CURLE_OPERATION_TIMEDOUT ) {
			LM_WARN("Curl library timed out on request\n");
		} else if ( res == CURLE_SSL_CONNECT_ERROR ) {
			LM_WARN("TLS error in curl connection\n");
		} else if ( res == CURLE_SSL_CERTPROBLEM ) {
			LM_WARN("TLS local certificate error\n");
		} else if ( res == CURLE_SSL_CIPHER ) {
			LM_WARN("TLS cipher error\n");
		} else if ( res == CURLE_SSL_CACERT ) {
			LM_WARN("TLS server certificate validation error (No valid CA cert)\n");
		} else if ( res == CURLE_SSL_CACERT_BADFILE ) {
			LM_WARN("TLS CA certificate read error \n");
		} else if ( res == CURLE_SSL_ISSUER_ERROR ) {
			LM_WARN("TLS issuer certificate check error \n");
		} else if ( res == CURLE_PEER_FAILED_VERIFICATION ) {
			LM_WARN("TLS verification error\n");
		} else if ( res == CURLE_TOO_MANY_REDIRECTS ) {
			LM_WARN("Too many redirects\n");
		} else {
			LM_ERR("failed to perform curl (%d)\n", res);
		}

		if (params->pconn) {
			params->pconn->last_result = res;
		}
		if (params->pconn && params->keep_connections) {
			params->pconn->curl = curl;	/* Save connection, don't close */
		} else {
			/* Cleanup and close - bye bye and thank you for all the bytes */
			curl_easy_cleanup(curl);
		}
		if(stream.buf) {
			pkg_free(stream.buf);
		}
		counter_inc(connfail);
		if (params->failovercon != NULL) {
			LM_ERR("FATAL FAILURE: Trying failover to curl con (%s)\n", params->failovercon);
			return (1000 + res);
		}
		return res;
	}

	/* HTTP_CODE CHANGED TO CURLINFO_RESPONSE_CODE in curl > 7.10.7 */
	curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &stat);
	if(res == CURLE_OK) {
		char *ct;
		char *url;

		/* ask for the content-type of the response */
		res = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct);
		res |= curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);

		if(ct) {
	    		LM_DBG("We received Content-Type: %s\n", ct);
			if (params->pconn) {
				strncpy(params->pconn->result_content_type, ct, sizeof(params->pconn->result_content_type));
			}
	    	}
		if(url) {
	    		LM_DBG("We visited URL: %s\n", url);
			if (params->pconn) {
				strncpy(params->pconn->redirecturl, url , sizeof(params->pconn->redirecturl));
			}
	    	}
	}
	if (params->pconn) {
		params->pconn->last_result = stat;
	}

	if ((stat >= 200) && (stat < 500)) {
		double datasize = download_size;

		curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &download_size);
		LM_DBG("  -- curl download size: %u \n", (unsigned int)download_size);

		if (download_size > 0) {

			if (params->oneline) {
				/* search for line feed */
				at = memchr(stream.buf, (char)10, download_size);
				datasize = (double) (at - stream.buf);
				LM_DBG("  -- curl download size cut to first line: %d \n", (int) datasize);
			}
			if (at == NULL) {
				if (params->maxdatasize && ((unsigned int) download_size) > params->maxdatasize) {
					/* Limit at maximum data size */
					datasize = (double) params->maxdatasize;
					LM_DBG("  -- curl download size cut to maxdatasize : %d \n", (int) datasize);
				} else {
					/* Limit at actual downloaded data size */
					datasize = (double) download_size;
					LM_DBG("  -- curl download size cut to download_size : %d \n", (int) datasize);
	    				//at = stream.buf + (unsigned int) download_size;
				}
			}
			/* Create a STR object */
			rval.s = stream.buf;
			rval.len = datasize;
			/* Duplicate string to return */
			pkg_str_dup(_dst, &rval);
			LM_DBG("curl query result: Length %d %.*s \n", rval.len, rval.len, rval.s);
		} else {
			_dst->s = NULL;
			_dst->len = 0;
		}
	}
	if (stat == 200) {
		counter_inc(connok);
	} else {
		counter_inc(connfail);
		if (stat >= 500) {
			if (params->failovercon != NULL) {
				LM_ERR("FAILURE: Trying failover to curl con (%s)\n", params->failovercon);
				return (1000 + stat);
			}
		}
	}

	/* CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... ); */
	if (params->pconn && params->keep_connections) {
		params->pconn->curl = curl;	/* Save connection, don't close */
	} else {
		curl_easy_cleanup(curl);
	}
	if (stream.buf != NULL) {
		pkg_free(stream.buf);
	}
	return stat;
}
Example #30
0
void send_ccr_stop_with_param(struct ro_session *ro_session, unsigned int code, str* reason) {
    AAASession * auth = 0;
    Ro_CCR_t * ro_ccr_data = 0;
    AAAMessage * ccr = 0;
    ims_information_t *ims_info = 0;
    int32_t acc_record_type;
    subscription_id_t subscr;
    time_stamps_t *time_stamps;
    long used = 0;
    str user_name = {0, 0};
    int ret = 0;
    time_t stop_time;
    time_t actual_time_micros;
    int actual_time_seconds;

    stop_time = get_current_time_micro();

    if (ro_session->start_time == 0)
        actual_time_micros = 0;
    else
        actual_time_micros = stop_time - ro_session->start_time;

    actual_time_seconds = (actual_time_micros + (1000000 - 1)) / (float) 1000000;

    if (ro_session->event_type != pending) {
        used = rint((stop_time - ro_session->last_event_timestamp) / (float) 1000000);
        LM_DBG("Final used number of seconds for session is %ld\n", used);
    }

    LM_DBG("Call started at %ld and ended at %ld and lasted %d seconds and so far we have billed for %ld seconds\n", ro_session->start_time, stop_time,
            actual_time_seconds, ro_session->billed + used);
    if (ro_session->billed + used < actual_time_seconds) {
        LM_DBG("Making adjustment by adding %ld seconds\n", actual_time_seconds - (ro_session->billed + used));
        used += actual_time_seconds - (ro_session->billed + used);
    }

    counter_add(ims_charging_cnts_h.billed_secs, (int)used);

    event_type_t *event_type;

    str sip_method = str_init("dummy");
    str sip_event = str_init("dummy");

    time_t req_timestamp;

    event_type = new_event_type(&sip_method, &sip_event, 0);

    LM_DBG("Sending stop CCR request for (usage) [%i] seconds for user [%.*s] using session id [%.*s] active rating group [%d] active service identifier [%d] incoming_trunk_id [%.*s] outgoing_trunk_id [%.*s] pani [%.*s]\n",
            (int)used,
            ro_session->asserted_identity.len, ro_session->asserted_identity.s,
            ro_session->ro_session_id.len, ro_session->ro_session_id.s,
            ro_session->rating_group, ro_session->service_identifier,
            ro_session->incoming_trunk_id.len, ro_session->incoming_trunk_id.s,
            ro_session->outgoing_trunk_id.len, ro_session->outgoing_trunk_id.s,
            ro_session->pani.len, ro_session->pani.s);

    req_timestamp = get_current_time_micro();

    if (!(time_stamps = new_time_stamps(&req_timestamp, NULL, NULL, NULL)))
        goto error0;

    if (!(ims_info = new_ims_information(event_type, time_stamps, &ro_session->callid, &ro_session->callid, &ro_session->asserted_identity,
            &ro_session->called_asserted_identity, 0, 0, 0, ro_session->direction, &ro_session->incoming_trunk_id, &ro_session->outgoing_trunk_id, &ro_session->pani)))
        goto error0;

    event_type = 0;

    if (ro_session->direction == RO_ORIG_DIRECTION) {
        subscr.id = ro_session->asserted_identity;


    } else if (ro_session->direction == RO_TERM_DIRECTION) {
        subscr.id = ro_session->called_asserted_identity;
    } else {
        LM_CRIT("don't know what to do in unknown mode - should we even get here\n");
        goto error0;
    }

    //getting subscription id type
    if (strncasecmp(subscr.id.s, "tel:", 4) == 0) {
        subscr.type = Subscription_Type_MSISDN;
    } else {
        subscr.type = Subscription_Type_IMPU; //default is END_USER_SIP_URI
    }

    user_name.s = subscr.id.s;
    user_name.len = subscr.id.len;


    acc_record_type = AAA_ACCT_STOP;

    ro_ccr_data = new_Ro_CCR(acc_record_type, &user_name, ims_info, &subscr);
    if (!ro_ccr_data) {
        LM_ERR("send_ccr_stop: no memory left for generic\n");
        goto error0;
    }
    ims_info = 0;

    LM_DBG("Created Ro data\n");

    auth = cdpb.AAAGetCCAccSession(ro_session->ro_session_id);

    if (!auth) {
        LM_DBG("Diameter Auth Session has timed out.... creating a new one.\n");
        /* lets try and recreate this session */
        auth = cdpb.AAAMakeSession(ro_session->auth_appid, ro_session->auth_session_type, ro_session->ro_session_id); //TODO: would like this session to last longer (see session timeout in cdp
        if (!auth)
            goto error1;
    }


    if (!(ccr = Ro_new_ccr(auth, ro_ccr_data)))
        goto error1;

    LM_DBG("Created new CCR\n");

    if (!Ro_add_vendor_specific_appid(ccr, IMS_vendor_id_3GPP, IMS_Ro, 0)) {
        LM_ERR("Problem adding Vendor specific ID\n");
    }

    ro_session->hop_by_hop += 1;
    if (!Ro_add_cc_request(ccr, RO_CC_STOP, ro_session->hop_by_hop)) {
        LM_ERR("Problem adding CC-Request data\n");
    }

    if (!Ro_add_event_timestamp(ccr, time(NULL))) {
        LM_ERR("Problem adding Event-Timestamp data\n");
    }

    if (!Ro_add_user_equipment_info(ccr, AVP_EPC_User_Equipment_Info_Type_MAC, ro_session->mac)) {
        LM_ERR("Problem adding User-Equipment data\n");
    }

    if (!Ro_add_subscription_id(ccr, subscr.type, &subscr.id)) {
        LM_ERR("Problem adding Subscription ID data\n");
    }

    if (!Ro_add_multiple_service_credit_Control_stop(ccr, used, ro_session->rating_group, ro_session->service_identifier)) {
        LM_ERR("Problem adding Multiple Service Credit Control data\n");
    }

    if (!Ro_add_termination_cause(ccr, TERM_CAUSE_LOGOUT)) {
        LM_ERR("problem add Termination cause AVP to STOP record.\n");
    }

    if (vendor_specific_chargeinfo) {
        if (!Ro_add_vendor_specific_termination_cause(ccr, code)) {
            LM_ERR("problem add Termination cause AVP to STOP record.\n");
        }

        if (!Ro_add_vendor_specific_termination_reason(ccr, reason)) {
            LM_ERR("problem add Termination cause AVP to STOP record.\n");
        }
    }

    cdpb.AAASessionsUnlock(auth->hash);

    if (ro_forced_peer.len > 0) {
        ret = cdpb.AAASendMessageToPeer(ccr, &ro_forced_peer, resume_on_termination_ccr, NULL);
    } else {
        ret = cdpb.AAASendMessage(ccr, resume_on_termination_ccr, NULL);
    }

    if (ret != 1) {
        goto error1;
    }

    Ro_free_CCR(ro_ccr_data);

    counter_inc(ims_charging_cnts_h.final_ccrs);
//    counter_add(ims_charging_cnts_h.active_ro_sessions, -1);
    return;

error1:
    LM_ERR("error on Ro STOP record\n");
    Ro_free_CCR(ro_ccr_data);

    if (auth) {
        cdpb.AAASessionsUnlock(auth->hash);
        cdpb.AAADropCCAccSession(auth);
    }

error0:
    return;

}