/** * \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; }
/** * 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; }
/** * 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; }
/* * 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; }
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; }
/*! * \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; }
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; }
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(®->l_uuid); nr->h_user = reg_compute_hash(®->l_username); p = (char*)nr + sizeof(reg_uac_t); reg_copy_shm(&nr->l_uuid, ®->l_uuid); reg_copy_shm(&nr->l_username, ®->l_username); reg_copy_shm(&nr->l_domain, ®->l_domain); reg_copy_shm(&nr->r_username, ®->r_username); reg_copy_shm(&nr->r_domain, ®->r_domain); reg_copy_shm(&nr->realm, ®->realm); reg_copy_shm(&nr->auth_proxy, ®->auth_proxy); reg_copy_shm(&nr->auth_username, ®->auth_username); /* password at the end, to be able to update it easily */ reg_copy_shm(&nr->auth_password, ®->auth_password); reg_ht_add_byuser(nr); reg_ht_add_byuuid(nr); counter_inc(regtotal); return 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; }
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); }
//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); }
/*! * \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; }
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); } }
//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(); }
/* 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; }
/*! * \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; }
/*! * \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; }
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(); }
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; }
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; }
/*! \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); }
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)?®->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; }
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); }
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); }
/* 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; }
/** * \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; }
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); }
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); }
/*! 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; }
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; }